core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-30 Thread Miklos Vajna (via logerrit)
 sw/qa/filter/ww8/ww8.cxx |   30 +++
 sw/source/filter/ww8/docxattributeoutput.cxx |   13 +++
 sw/source/filter/ww8/docxattributeoutput.hxx |2 -
 sw/source/filter/ww8/docxexport.cxx  |4 +--
 4 files changed, 46 insertions(+), 3 deletions(-)

New commits:
commit d0ee0c93d6145542d82ba62887f4e5a3691333fe
Author: Miklos Vajna 
AuthorDate: Wed May 29 13:34:25 2024 +0200
Commit: Caolán McNamara 
CommitDate: Thu May 30 14:08:24 2024 +0200

tdf#160984 sw continuous endnotes: DOCX: export of  pos == 
sectEnd

In case a DOCX file is re-exported to Word and it collected endnotes at
section end, this setting was lost on save.

The relevant markup seems to be  -> , though that's a per-section setting in Writer, and is
a per-doc setting in Word.

Fix the problem by doing it similar to
DocxExport::WriteDocumentBackgroundFill(), which takes the first page
style in a similar case; here we take the first section format.

This is meant to be good enough for the DOCX editing case, where we know
all sections have the same endnote position properties anyway.

(cherry picked from commit 566c7017a84e3d573de85a6d986b81d3f59de0fa)

Change-Id: I95508296e31c9be34196bdc0da2177101647abf9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168241
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/filter/ww8/ww8.cxx b/sw/qa/filter/ww8/ww8.cxx
index 4cbbfe5fbf31..070565345a2d 100644
--- a/sw/qa/filter/ww8/ww8.cxx
+++ b/sw/qa/filter/ww8/ww8.cxx
@@ -32,6 +32,7 @@
 #include 
 #include 
 #include 
+#include 
 
 namespace
 {
@@ -564,6 +565,35 @@ CPPUNIT_TEST_FIXTURE(Test, testNullPointerDereference)
 createSwDoc("null-pointer-dereference.doc");
 CPPUNIT_ASSERT_EQUAL(6, getPages());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testEndnotesAtSectEnd)
+{
+// Given a document, endnotes at collected at section end:
+createSwDoc();
+SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+pWrtShell->SplitNode();
+pWrtShell->Up(/*bSelect=*/false);
+pWrtShell->Insert("x");
+pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, 
/*bBasicCall=*/false);
+SwSectionData aSection(SectionType::Content, 
pWrtShell->GetUniqueSectionName());
+pWrtShell->StartAction();
+SfxItemSetFixed 
aSet(pWrtShell->GetAttrPool());
+aSet.Put(SwFormatEndAtTextEnd(FTNEND_ATTXTEND));
+pWrtShell->InsertSection(aSection, );
+pWrtShell->EndAction();
+pWrtShell->InsertFootnote(OUString(), /*bEndNote=*/true);
+
+// When saving to DOCX:
+save("Office Open XML Text");
+
+// Then make sure the endnote position is section end:
+xmlDocUniquePtr pXmlDoc = parseExport("word/settings.xml");
+OUString aPos = getXPath(pXmlDoc, "/w:settings/w:endnotePr/w:pos"_ostr, 
"val"_ostr);
+// Without the accompanying fix in place, this test would have failed with:
+// - XPath '/w:settings/w:endnotePr/w:pos' number of nodes is incorrect
+// i.e. the default position was used: document end.
+CPPUNIT_ASSERT_EQUAL(OUString("sectEnd"), aPos);
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 3201321a6328..2f77cf07b06a 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -127,6 +127,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -8786,6 +8787,18 @@ void DocxAttributeOutput::WriteFootnoteEndnotePr( 
::sax_fastparser::FSHelperPtr
 const SwEndNoteInfo& info, int listtag )
 {
 fs->startElementNS(XML_w, tag);
+
+SwSectionFormats& rSections = m_rExport.m_rDoc.GetSections();
+if (!rSections.empty())
+{
+SwSectionFormat* pFormat = rSections[0];
+bool bEndnAtEnd = pFormat->GetEndAtTextEnd().IsAtEnd();
+if (bEndnAtEnd)
+{
+fs->singleElementNS(XML_w, XML_pos, FSNS(XML_w, XML_val), 
"sectEnd");
+}
+}
+
 OString aCustomFormat;
 OString fmt = lcl_ConvertNumberingType(info.m_aFormat.GetNumberingType(), 
nullptr, aCustomFormat);
 if (!fmt.isEmpty() && aCustomFormat.isEmpty())
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx 
b/sw/source/filter/ww8/docxattributeoutput.hxx
index 10f39debc2a0..b23f5b98ee7e 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -1109,7 +1109,7 @@ public:
 void FootnotesEndnotes( bool bFootnotes );
 
 /// writes the footnotePr/endnotePr (depending on tag) section
-static void WriteFootnoteEndnotePr( ::sax_fastparser::FSHelperPtr const & 
fs, int tag, const SwEndNoteInfo& info, int listtag );
+void WriteFootnoteEndnotePr( ::sax_fastparser::FSHelperPtr const & fs, int 
tag, const SwEndNoteInfo& info, int listtag );
 
 bool HasPostitFields() const;
  

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-27 Thread Miklos Vajna (via logerrit)
 sw/qa/core/layout/data/inline-endnote-section-delete.docx |binary
 sw/qa/core/layout/ftnfrm.cxx  |   31 ++
 sw/source/core/layout/ftnfrm.cxx  |4 +
 3 files changed, 34 insertions(+), 1 deletion(-)

New commits:
commit ba0f1432e2162d32103e20d2030cf79b3dd4e2f7
Author: Miklos Vajna 
AuthorDate: Mon May 27 09:41:18 2024 +0200
Commit: Caolán McNamara 
CommitDate: Mon May 27 14:31:05 2024 +0200

tdf#160984 sw continuous endnotes: fix crash on loading 
forum-mso-en-7731.docx

Regression from commit 1ae5ea3f78cca11ba18f2dd1a06f875263336a3b
(tdf#160984 sw continuous endnotes: enable DOCX import, 2024-05-21), the
bugdoc crashed in SwSectionFrame::GetEndSectFormat_().

What seems to happen is that the first endnote is added to page 1, then
more content is inserted, so the endnote is moved to page 2, which
leaves an empty endnote section on page 1, which is marked for deletion
in SwSectionFrame::MakeAll(), and will be deleted in
SwRootFrame::DeleteEmptySct_(). At some point (after marking for
deletion, before deletion) SwFootnoteBossFrame::AppendFootnote() tries
to find the first endnote section in the layout, and finds this section,
but it crashes because there is no SwSection attached to it, as marking
for deletion in SwSectionFrame::DelEmpty() clears that.

Fix the problem by ignoring to-be-deleted sections in
SwFootnoteBossFrame::AppendFootnote(): this way a new, usable section
will be created and the to-be-deleted section go away as the layout
finishes.

An alternative would be to check for SwSectionFrame::GetSection()
earlier, as we iterate on pages (hoping that this way we find a later
page that has a not-dead endnote section), but that leads to 6 pages
instead of 4 pages for the bugdoc, so don't go that way.

(cherry picked from commit 3f2d0414686a8f9a042413c47c4c8ffa5d61f436)

Change-Id: I9a21cbccb5a088314520c7ade55dbdf9966d1265
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168099
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/core/layout/data/inline-endnote-section-delete.docx 
b/sw/qa/core/layout/data/inline-endnote-section-delete.docx
new file mode 100644
index ..bf3d3e60d890
Binary files /dev/null and 
b/sw/qa/core/layout/data/inline-endnote-section-delete.docx differ
diff --git a/sw/qa/core/layout/ftnfrm.cxx b/sw/qa/core/layout/ftnfrm.cxx
index a7640e26ca9a..98387be6a983 100644
--- a/sw/qa/core/layout/ftnfrm.cxx
+++ b/sw/qa/core/layout/ftnfrm.cxx
@@ -17,6 +17,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 /// Covers sw/source/core/layout/ftnfrm.cxx fixes.
 class Test : public SwModelTestBase
@@ -122,4 +124,33 @@ CPPUNIT_TEST_FIXTURE(Test, testInlineEndnotePosition)
 CPPUNIT_ASSERT_EQUAL(static_cast(269), nEndnoteContTopMargin);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testInlineEndnoteSectionDelete)
+{
+// Given a document, ContinuousEndnotes is true, 3 pages, endnodes start 
on page 2:
+// When laying out that document:
+createSwDoc("inline-endnote-section-delete.docx");
+
+// First page: just body text:
+SwDoc* pDoc = getSwDoc();
+SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+auto pPage = pLayout->Lower()->DynCastPageFrame();
+CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
+auto pBodyFrame = static_cast(pPage->GetLower());
+CPPUNIT_ASSERT(!pBodyFrame->GetLastLower()->IsSctFrame());
+// Second page: ends with endnotes:
+pPage = pPage->GetNext()->DynCastPageFrame();
+CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
+pBodyFrame = static_cast(pPage->GetLower());
+CPPUNIT_ASSERT(pBodyFrame->GetLastLower()->IsSctFrame());
+auto pSection = static_cast(pBodyFrame->GetLastLower());
+CPPUNIT_ASSERT(pSection->IsEndNoteSection());
+// Third page: just endnotes:
+pPage = pPage->GetNext()->DynCastPageFrame();
+CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
+pBodyFrame = static_cast(pPage->GetLower());
+CPPUNIT_ASSERT(pBodyFrame->GetLower()->IsSctFrame());
+pSection = static_cast(pBodyFrame->GetLower());
+CPPUNIT_ASSERT(pSection->IsEndNoteSection());
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx
index 46312f9f4e89..1c6b221cf511 100644
--- a/sw/source/core/layout/ftnfrm.cxx
+++ b/sw/source/core/layout/ftnfrm.cxx
@@ -1601,7 +1601,9 @@ void SwFootnoteBossFrame::AppendFootnote( SwContentFrame 
*pRef, SwTextFootnote *
 pEndnoteSection = pPage->GetEndNoteSection();
 }
 // If there are no endnotes sections yet, create one at the end of 
the document.
-if (!pEndnoteSection)
+// Ignore sections which are already marked for deletion, they 
don't have an SwSection
+   

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-27 Thread Miklos Vajna (via logerrit)
 sw/qa/core/layout/paintfrm.cxx |   10 ++
 sw/source/core/layout/paintfrm.cxx |9 -
 2 files changed, 18 insertions(+), 1 deletion(-)

New commits:
commit 69bbd6378ed7a7b7765948d5ec08673866947d5d
Author: Miklos Vajna 
AuthorDate: Fri May 24 10:51:31 2024 +0200
Commit: Caolán McNamara 
CommitDate: Mon May 27 14:30:44 2024 +0200

tdf#160984 sw continuous endnotes: fix the endnote separator length

See
,
Word has a longer separator line for the foot/endnote than Writer for
this bugdoc.

Writer defaults to 25% of the body frame width in the SwPageFootnoteInfo
ctor, and we don't seem to change that in the DOCX import. Word has a
static 2 inches setting, which is only reduced if it would go outside
the body frame.

Fix the problem by extending SwFootnoteContFrame::PaintLine() in the
DocumentSettingId::CONTINUOUS_ENDNOTES case to do the same.

I searched the OOXML spec and the MS implementer notes, they don't
specify this 2 inches length, but it seems static: the value doesn't
change with the page size. With this, the single-section bugdoc is now
rendered fine.

(cherry picked from commit 755f3bebd96ec7ae43b1dcf247f907b9c15c1995)

Change-Id: I3bb23680937580179b8d37c940ea14e0f80fc7f4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168088
Reviewed-by: Caolán McNamara 
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/core/layout/paintfrm.cxx b/sw/qa/core/layout/paintfrm.cxx
index 8e7154db2501..a5213c57d639 100644
--- a/sw/qa/core/layout/paintfrm.cxx
+++ b/sw/qa/core/layout/paintfrm.cxx
@@ -177,6 +177,16 @@ CPPUNIT_TEST_FIXTURE(Test, 
testInlineEndnoteSeparatorPosition)
 // - Actual  : 2060
 // i.e. the upper spacing was too low.
 CPPUNIT_ASSERT_EQUAL(static_cast(2164), nEndnoteSeparatorY);
+
+// Also make sure the separator length is correct:
+auto nEndnoteSeparatorStart = getXPath(pXmlDoc, "//polygon/point[1]"_ostr, 
"x"_ostr).toInt32();
+auto nEndnoteSeparatorEnd = getXPath(pXmlDoc, "//polygon/point[2]"_ostr, 
"x"_ostr).toInt32();
+sal_Int32 nEndnoteSeparatorLength = nEndnoteSeparatorEnd - 
nEndnoteSeparatorStart;
+// Without the accompanying fix in place, this test would have failed with:
+// - Expected: 2880
+// - Actual  : 2340
+// i.e. the separator wasn't 2 inches long, but was shorter vs Word.
+CPPUNIT_ASSERT_EQUAL(static_cast(2880), 
nEndnoteSeparatorLength);
 }
 }
 
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index b45226bbbcb6..89ea71f9acb7 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -5777,7 +5777,7 @@ void SwFootnoteContFrame::PaintLine( const SwRect& rRect,
 SwTwips nPrtWidth = aRectFnSet.GetWidth(getFramePrintArea());
 Fraction aFract( nPrtWidth, 1 );
 aFract *= rInf.GetWidth();
-const SwTwips nWidth = static_cast(aFract);
+SwTwips nWidth = static_cast(aFract);
 
 SwTwips nX = aRectFnSet.GetPrtLeft(*this);
 switch ( rInf.GetAdj() )
@@ -5808,6 +5808,13 @@ void SwFootnoteContFrame::PaintLine( const SwRect& rRect,
 // Word style: instead of fixed value, upper spacing is 60% of all 
space.
 auto nPrintAreaTop = 
static_cast(getFramePrintArea().Top());
 aPoint.setY(getFrameArea().Pos().Y() + nPrintAreaTop * 0.6);
+
+// Length is 2 inches, but don't paint outside the container frame.
+nWidth = o3tl::convert(2, o3tl::Length::in, o3tl::Length::twip);
+if (nWidth > nPrtWidth)
+{
+nWidth = nPrtWidth;
+}
 }
 oLineRect.emplace(aPoint, Size(nWidth, rInf.GetLineWidth()));
 }


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-27 Thread Miklos Vajna (via logerrit)
 sw/qa/core/layout/paintfrm.cxx |   20 
 sw/source/core/layout/paintfrm.cxx |   27 ---
 2 files changed, 40 insertions(+), 7 deletions(-)

New commits:
commit 461447cfdca85298435b0e029b1c1418789618ad
Author: Miklos Vajna 
AuthorDate: Thu May 23 15:31:05 2024 +0200
Commit: Caolán McNamara 
CommitDate: Mon May 27 14:30:26 2024 +0200

tdf#160984 sw continuous endnotes: fix the endnote separator position

See , the
total height of the endnote separator is now correct, but the
distribution of upper space, line width, lower space is still bad, when
compared to Word.

Our model is 2 spacings and a line width, while Word seems to simply
split the amount of available space: 60% goes above the separator and
the rest goes below.

Fix the problem by breaking up the monster expression for the separator
rectangle in SwFootnoteContFrame::PaintLine(), and then the compat +
horizontal case can do the 60% spacing in the Word compat mode.

The width of the separator is still not correct.

(cherry picked from commit f1d0b4e34a1f467e9f54baa7ac31ca28fdae3efb)

Change-Id: Ic065c138041892225b3c1b7d4bd64d4f1c625611
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168007
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/core/layout/paintfrm.cxx b/sw/qa/core/layout/paintfrm.cxx
index b5990648b20f..8e7154db2501 100644
--- a/sw/qa/core/layout/paintfrm.cxx
+++ b/sw/qa/core/layout/paintfrm.cxx
@@ -158,6 +158,26 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitTableMergedBorder)
 // bottom border.
 CPPUNIT_ASSERT_EQUAL(static_cast(2), aHorizontalBorderEnds.size());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testInlineEndnoteSeparatorPosition)
+{
+// Given a document with a Word-style endnote separator:
+createSwDoc("inline-endnote-position.docx");
+SwDocShell* pDocShell = getSwDocShell();
+
+// When rendering that document:
+std::shared_ptr xMetaFile = pDocShell->GetPreviewMetaFile();
+
+// Then make sure the separator upper spacing is 60% of all space, 
matching Word:
+MetafileXmlDump aDumper;
+xmlDocUniquePtr pXmlDoc = dumpAndParse(aDumper, *xMetaFile);
+auto nEndnoteSeparatorY = getXPath(pXmlDoc, "//polygon/point[1]"_ostr, 
"y"_ostr).toInt32();
+// Without the accompanying fix in place, this test would have failed with:
+// - Expected: 2164
+// - Actual  : 2060
+// i.e. the upper spacing was too low.
+CPPUNIT_ASSERT_EQUAL(static_cast(2164), nEndnoteSeparatorY);
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index ff5abcfcf898..b45226bbbcb6 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -5793,13 +5793,26 @@ void SwFootnoteContFrame::PaintLine( const SwRect& 
rRect,
 assert(false);
 }
 SwTwips nLineWidth = rInf.GetLineWidth();
-const SwRect aLineRect = aRectFnSet.IsVert() ?
-SwRect( 
Point(getFrameArea().Left()+getFrameArea().Width()-rInf.GetTopDist()-nLineWidth,
-  nX), Size( nLineWidth, nWidth ) )
-: SwRect( Point( nX, getFrameArea().Pos().Y() + rInf.GetTopDist() 
),
-Size( nWidth, rInf.GetLineWidth()));
-if ( aLineRect.HasArea() && rInf.GetLineStyle() != 
SvxBorderLineStyle::NONE)
-PaintBorderLine( rRect, aLineRect , pPage, (),
+std::optional oLineRect;
+if (aRectFnSet.IsVert())
+{
+
oLineRect.emplace(Point(getFrameArea().Left()+getFrameArea().Width()-rInf.GetTopDist()-nLineWidth,
+  nX), Size( nLineWidth, nWidth ) );
+}
+else
+{
+Point aPoint(nX, getFrameArea().Pos().Y() + rInf.GetTopDist());
+const IDocumentSettingAccess& rIDSA = 
GetFormat()->getIDocumentSettingAccess();
+if (rIDSA.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
+{
+// Word style: instead of fixed value, upper spacing is 60% of all 
space.
+auto nPrintAreaTop = 
static_cast(getFramePrintArea().Top());
+aPoint.setY(getFrameArea().Pos().Y() + nPrintAreaTop * 0.6);
+}
+oLineRect.emplace(aPoint, Size(nWidth, rInf.GetLineWidth()));
+}
+if ( oLineRect->HasArea() && rInf.GetLineStyle() != 
SvxBorderLineStyle::NONE)
+PaintBorderLine( rRect, *oLineRect , pPage, (),
 rInf.GetLineStyle() );
 }
 


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source xmloff/qa

2024-05-23 Thread Miklos Vajna (via logerrit)
 sw/qa/core/layout/data/fly-rel-width-rounding.odt |binary
 sw/qa/core/layout/fly.cxx |   25 ++
 sw/source/core/layout/fly.cxx |5 ++--
 xmloff/qa/unit/text.cxx   |4 +--
 4 files changed, 30 insertions(+), 4 deletions(-)

New commits:
commit 991341f9f69fded9c9573d91b2d65fc6a37b3132
Author: Miklos Vajna 
AuthorDate: Wed May 22 08:47:32 2024 +0200
Commit: Miklos Vajna 
CommitDate: Thu May 23 09:20:46 2024 +0200

Related: tdf#145972 sw images: fix rounding error in relative size 
calculation

Open the bugdoc, see that the image is roughly half of the page width,
right click, properties, UI shows that the width of the image is 5% of
the width of the entire page. This only happens if tools -> options ->
writer -> general sets the UI units to points, the default cm case is
fine.

This went wrong with commit 9e8712ed6f9fb5dbd971e352a5709bd45fadc74f (sw
image dialog: fix fallback width/height for images with relative sizes,
2022-03-17), because the layout size started to matter more after that
commit. This lead to the nWidth !=
m_xWidthED->get_value(FieldUnit::TWIP) check in SwFramePage::Init() to
be true, because 11906 * 0.48 is 5714.88, so you got 5714 in the layout,
but got 5715 with rounding in SwFramePage::Reset() (which tries to calc
the page width based on the 48% and the fly width). And once we had that
mismatch, we went down the wrong path.

Fix the problem by using rtl::math::round() in SwFlyFrame::CalcRel(), so
the relative width twips value is 5715 everywhere: once we have
consisteny, the UI value is correct, too.

Note that the original bugdoc needs more fixing, this just fixes the
bugdoc where KeepRatio is false.

Change-Id: I1e8782c95a0cf9d97375c36d41134735c01f3e46
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167916
Tested-by: Jenkins
Reviewed-by: Miklos Vajna 
Signed-off-by: Xisco Fauli 
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167926
(cherry picked from commit 3046bd0e30406d37813ce3eaa65f71f5ed10ab13)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167980
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/core/layout/data/fly-rel-width-rounding.odt 
b/sw/qa/core/layout/data/fly-rel-width-rounding.odt
new file mode 100644
index ..b70b9e51a917
Binary files /dev/null and b/sw/qa/core/layout/data/fly-rel-width-rounding.odt 
differ
diff --git a/sw/qa/core/layout/fly.cxx b/sw/qa/core/layout/fly.cxx
index 47cfb40fa6e7..81df20af3b35 100644
--- a/sw/qa/core/layout/fly.cxx
+++ b/sw/qa/core/layout/fly.cxx
@@ -86,6 +86,31 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyNegativeHeight)
 }
 }
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testFlyRelWithRounding)
+{
+// Given a document where page width is 21.001cm (11906 twips), and the 
image width is 48% of
+// the page width:
+createSwDoc("fly-rel-width-rounding.odt");
+
+// When laying out that document:
+SwDoc* pDoc = getSwDoc();
+SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+
+// Then make sure that we calculate the width of the fly correctly:
+auto pPage = pLayout->GetLower()->DynCastPageFrame();
+CPPUNIT_ASSERT(pPage->GetSortedObjs());
+SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
+CPPUNIT_ASSERT_EQUAL(static_cast(1), rPageObjs.size());
+auto pFly = rPageObjs[0]->DynCastFlyFrame()->DynCastFlyAtContentFrame();
+CPPUNIT_ASSERT(pFly);
+tools::Long nFlyWidth = pFly->getFrameArea().Width();
+// Without the accompanying fix in place, this test would have failed with:
+// - Expected: 5715
+// - Actual  : 5714
+// i.e. 5714.88 was truncated, not rounded.
+CPPUNIT_ASSERT_EQUAL(static_cast(5715), nFlyWidth);
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index b454bd95917f..fd95ce192cf7 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -70,6 +70,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -2845,9 +2846,9 @@ Size SwFlyFrame::CalcRel( const SwFormatFrameSize  ) 
const
 }
 
 if ( rSz.GetWidthPercent() && rSz.GetWidthPercent() != 
SwFormatFrameSize::SYNCED )
-aRet.setWidth( nRelWidth * rSz.GetWidthPercent() / 100 );
+aRet.setWidth(rtl::math::round(double(nRelWidth) * 
rSz.GetWidthPercent() / 100));
 if ( rSz.GetHeightPercent() && rSz.GetHeightPercent() != 
SwFormatFrameSize::SYNCED )
-aRet.setHeight( nRelHeight * rSz.GetHeightPercent() / 100 );
+aRet.setHeight(rtl::math::round(double(nRelHeight) * 
rSz.GetHeightPercent() / 100));
 
 if ( rSz.GetHeight() && rSz.GetWidthPercent() == 
SwFormatFrameSize::SYNCED )
 {
diff --git a/xmloff/qa/unit/text.cxx 

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-21 Thread Mike Kaganski (via logerrit)
 sw/qa/extras/uiwriter/data/tdf161172.fodt |   35 +
 sw/qa/extras/uiwriter/uiwriter9.cxx   |   41 ++
 sw/source/core/doc/docfmt.cxx |   10 ++-
 3 files changed, 80 insertions(+), 6 deletions(-)

New commits:
commit af38e96cad0949291a289443363218f93ba59ecd
Author: Mike Kaganski 
AuthorDate: Sun May 19 13:40:49 2024 +0500
Commit: Miklos Vajna 
CommitDate: Tue May 21 14:01:59 2024 +0200

tdf#161172: Also record history for !bChangeOfListStyleAtParagraph

Change-Id: I6443d7ef76a27ac3ab75f88edd271a8b36e06c14
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167839
Reviewed-by: Mike Kaganski 
Tested-by: Jenkins
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167841
Reviewed-by: Miklos Vajna 
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/extras/uiwriter/data/tdf161172.fodt 
b/sw/qa/extras/uiwriter/data/tdf161172.fodt
new file mode 100644
index ..08cea575cc60
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf161172.fodt
@@ -0,0 +1,35 @@
+
+
+
+ 
+  
+  
+  
+   
+
+ 
+
+   
+   
+
+ 
+
+   
+  
+ 
+ 
+  
+ 
+ 
+  
+ 
+ 
+  
+   
+
+ foo
+
+   
+  
+ 
+
\ No newline at end of file
diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx 
b/sw/qa/extras/uiwriter/uiwriter9.cxx
index ecf35075623e..335b004fa6f8 100644
--- a/sw/qa/extras/uiwriter/uiwriter9.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter9.cxx
@@ -19,6 +19,7 @@
 #include 
 
 #include 
+#include 
 #include 
 #include 
 
@@ -256,6 +257,46 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, 
testTdf159054_disableOutlineNumbering)
 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty(xPara2, 
"ListLabelString"));
 CPPUNIT_ASSERT_EQUAL(OUString("A."), getProperty(xPara3, 
"ListLabelString"));
 }
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf161172)
+{
+// Given a paragraph manually made a member of a list:
+createSwDoc("tdf161172.fodt");
+auto para = getParagraph(1);
+
+// Check initial state: the first paragraph has "No_list" para style, 
"Num_1" numbering style,
+// numbering level 0, and "Num1_lvl1_1" numbering label.
+CPPUNIT_ASSERT_EQUAL(u"No_list"_ustr, getProperty(para, 
u"ParaStyleName"_ustr));
+CPPUNIT_ASSERT_EQUAL(u"Num_1"_ustr, getProperty(para, 
u"NumberingStyleName"_ustr));
+CPPUNIT_ASSERT_EQUAL(u"Num1_lvl1_1"_ustr, getProperty(para, 
u"ListLabelString"_ustr));
+CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty(para, 
u"NumberingLevel"_ustr));
+
+// Assign "Num_1_lvl2" paragraph style to the first paragraph. The style 
is associated with
+// "Num_1" numbering style, level 1.
+dispatchCommand(mxComponent, u".uno:StyleApply"_ustr,
+{ comphelper::makePropertyValue(u"FamilyName"_ustr, 
u"ParagraphStyles"_ustr),
+  comphelper::makePropertyValue(u"Style"_ustr, 
u"Num_1_lvl2"_ustr) });
+
+// Check that the respective properties got correctly applied
+CPPUNIT_ASSERT_EQUAL(u"Num_1_lvl2"_ustr, getProperty(para, 
u"ParaStyleName"_ustr));
+CPPUNIT_ASSERT_EQUAL(u"Num_1"_ustr, getProperty(para, 
u"NumberingStyleName"_ustr));
+CPPUNIT_ASSERT_EQUAL(u"Num1_lvl2_1"_ustr, getProperty(para, 
u"ListLabelString"_ustr));
+CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty(para, 
u"NumberingLevel"_ustr));
+
+// Undo
+dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
+
+// Check that the numbering properties got correctly restored
+CPPUNIT_ASSERT_EQUAL(u"No_list"_ustr, getProperty(para, 
u"ParaStyleName"_ustr));
+CPPUNIT_ASSERT_EQUAL(u"Num_1"_ustr, getProperty(para, 
u"NumberingStyleName"_ustr));
+// Without the fix, this would fail with
+// - Expected: Num1_lvl1_1
+// - Actual  : Num1_lvl2_1
+CPPUNIT_ASSERT_EQUAL(u"Num1_lvl1_1"_ustr, getProperty(para, 
u"ListLabelString"_ustr));
+// Without the fix, this would fail with
+// - Expected: 0
+// - Actual  : 1
+CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty(para, 
u"NumberingLevel"_ustr));
+}
 
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 1c696bebb6a0..3390a506052c 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -1040,14 +1040,12 @@ static bool lcl_SetTextFormatColl( SwNode* pNode, void* 
pArgs )
 }
 }
 
+std::optional oRegH;
+if (pPara->pHistory)
+oRegH.emplace(, rTNd, pPara->pHistory);
+
 if ( bChangeOfListStyleAtParagraph )
 {
-std::unique_ptr< SwRegHistory > pRegH;
-if ( pPara->pHistory )
-{
-pRegH.reset(new SwRegHistory(, rTNd, 
pPara->pHistory));
-}
-
 pCNd->ResetAttr( RES_PARATR_NUMRULE );
 
 // reset all list attributes


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-17 Thread Miklos Vajna (via logerrit)
 sw/qa/filter/ww8/ww8.cxx  |7 ++-
 sw/source/core/inc/frame.hxx  |3 +++
 sw/source/core/layout/findfrm.cxx |   11 +++
 sw/source/filter/ww8/ww8par.cxx   |7 ---
 4 files changed, 20 insertions(+), 8 deletions(-)

New commits:
commit 135e86e7e3bafdb0ab39a372a989854eefefe30c
Author: Miklos Vajna 
AuthorDate: Thu May 16 08:46:36 2024 +0200
Commit: Caolán McNamara 
CommitDate: Fri May 17 12:03:49 2024 +0200

tdf#160984 sw continuous endnotes, DOC import: enable this unconditionally

DOC files with <= 2 endnotes were imported fine, but not if they had
more endnotes.

This was added in commit dc11f5b151e1a2ea2623fc8cf806a400763955d9
(tdf#143445 DOC import: limit the usage of the CONTINUOUS_ENDNOTES
compat flag, 2023-05-23), because mapping endnotes to footnotes was a
dead-end.

The limitation can be dropped: I checked that the tdf#143445 bugdoc with
all its 72 endnotes is laid out reasonably.

Also add a new SwFrame::DynCastColumnFrame() to easily get a column
frame from a frame using our own RTTI, if we have it anyway.

(cherry picked from commit d74fb6b571304b41c13b7a6dcdd2b853bfca7210)

Change-Id: If7fd856f5dc5f1feb1366fca69a2ad6b3602044d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167763
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/filter/ww8/ww8.cxx b/sw/qa/filter/ww8/ww8.cxx
index af19051a03e5..4cbbfe5fbf31 100644
--- a/sw/qa/filter/ww8/ww8.cxx
+++ b/sw/qa/filter/ww8/ww8.cxx
@@ -30,6 +30,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 namespace
 {
@@ -298,7 +300,10 @@ CPPUNIT_TEST_FIXTURE(Test, test3Endnotes)
 SwDoc* pDoc = getSwDoc();
 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
 SwPageFrame* pPage = pLayout->GetLastPage();
-SwFootnoteContFrame* pFootnoteCont = pPage->FindFootnoteCont();
+SwContentFrame* pLastContent = pPage->FindLastBodyContent();
+SwFrame* pSectionFrame = pLastContent->GetNext();
+auto pColumnFrame = pSectionFrame->GetLower()->DynCastColumnFrame();
+SwFootnoteContFrame* pFootnoteCont = pColumnFrame->FindFootnoteCont();
 int nEndnotes = 0;
 for (SwFrame* pLower = pFootnoteCont->GetLower(); pLower; pLower = 
pLower->GetNext())
 {
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index a86358508182..b662adc89086 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -40,6 +40,7 @@ namespace drawinglayer::processor2d { class BaseProcessor2D; }
 class SwLayoutFrame;
 class SwRootFrame;
 class SwPageFrame;
+class SwColumnFrame;
 class SwBodyFrame;
 class SwFlyFrame;
 class SwSectionFrame;
@@ -876,6 +877,8 @@ public:
 const SwTextFrame* DynCastTextFrame() const;
 SwPageFrame* DynCastPageFrame();
 const SwPageFrame* DynCastPageFrame() const;
+SwColumnFrame* DynCastColumnFrame();
+const SwColumnFrame* DynCastColumnFrame() const;
 inline bool IsNoTextFrame() const;
 // Frames where its PrtArea depends on their neighbors and that are
 // positioned in the content flow
diff --git a/sw/source/core/layout/findfrm.cxx 
b/sw/source/core/layout/findfrm.cxx
index 378e451b9f89..4efa25e553e6 100644
--- a/sw/source/core/layout/findfrm.cxx
+++ b/sw/source/core/layout/findfrm.cxx
@@ -18,6 +18,7 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -1973,4 +1974,14 @@ const SwPageFrame* SwFrame::DynCastPageFrame() const
 return IsPageFrame() ? static_cast(this) : nullptr;
 }
 
+SwColumnFrame* SwFrame::DynCastColumnFrame()
+{
+return IsColumnFrame() ? static_cast(this) : nullptr;
+}
+
+const SwColumnFrame* SwFrame::DynCastColumnFrame() const
+{
+return IsColumnFrame() ? static_cast(this) : nullptr;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/ww8par.cxx b/sw/source/filter/ww8/ww8par.cxx
index c88990a5f663..3f18c2058122 100644
--- a/sw/source/filter/ww8/ww8par.cxx
+++ b/sw/source/filter/ww8/ww8par.cxx
@@ -5195,13 +5195,6 @@ ErrCode SwWW8ImplReader::CoreLoad(WW8Glossary const 
*pGloss)
 if( m_xWDop->nEdn )
 aInfo.m_nFootnoteOffset = m_xWDop->nEdn - 1;
 m_rDoc.SetEndNoteInfo( aInfo );
-
-if (m_xSBase->GetEndnoteCount() > 2)
-{
-// This compatibility flag only works in easy cases, disable it 
for anything non-trivial
-// for now.
-
m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, 
false);
-}
 }
 
 if (m_xWwFib->m_lcbPlcfhdd)


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-16 Thread Miklos Vajna (via logerrit)
 sw/qa/core/layout/data/inline-endnote-and-section.odt |binary
 sw/qa/core/layout/ftnfrm.cxx  |   18 ++
 sw/source/core/layout/ftnfrm.cxx  |   16 +++-
 3 files changed, 33 insertions(+), 1 deletion(-)

New commits:
commit a8216967ebe242c379b7df1267836c4ec5a566a4
Author: Miklos Vajna 
AuthorDate: Wed May 15 13:25:13 2024 +0200
Commit: Caolán McNamara 
CommitDate: Thu May 16 16:02:17 2024 +0200

tdf#161083 sw continuous endnotes: fix layout with a section at doc end

Open the bugdoc, notice warnings like:

warn:legacy.osl:15059:15059:sw/source/core/layout/wsfrm.cxx:910: Frame tree 
is inconsistent.

Which means we try to insert the new section frame under body frame, but
the insert point is behind a frame which is not a direct child of the
body frame.

This went wrong in commit 6885dcd7ec7b82a946d8344bfc27a3e88eecc44a
(tdf#160984 sw continuous endnotes: switch to a section-based layout,
2024-05-14), where I didn't consider the case of having a continuous
section break at the Word doc end, which maps to a section frame before
the section frame of the endnotes in Writer.

Fix the problem by walking up the parent chain till we find the last
direct child of the body frame, which is typically not required, except
when having one or more (nested) section frames at the end of the
document.

Interestingly tdf#143456 had the same problem, which was the bugdoc to
trigger the revert of the old continuous endnotes code for DOCX in
eeda1b35a6e87d5349545464da33d997c52f15e3 (Revert "tdf#58521 DOCX import:
enable ContinuousEndnotes compat flag", 2021-08-10).

(cherry picked from commit 82dd81a9d2049ac95535880fc67c1867f90e1427)

Change-Id: I664672b91087217008a42120e8201c39e2a0a423
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167728
Reviewed-by: Caolán McNamara 
Tested-by: Caolán McNamara 
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/core/layout/data/inline-endnote-and-section.odt 
b/sw/qa/core/layout/data/inline-endnote-and-section.odt
new file mode 100644
index ..4518904f6009
Binary files /dev/null and 
b/sw/qa/core/layout/data/inline-endnote-and-section.odt differ
diff --git a/sw/qa/core/layout/ftnfrm.cxx b/sw/qa/core/layout/ftnfrm.cxx
index 71fd3fd67150..1cf31809e5a7 100644
--- a/sw/qa/core/layout/ftnfrm.cxx
+++ b/sw/qa/core/layout/ftnfrm.cxx
@@ -84,4 +84,22 @@ CPPUNIT_TEST_FIXTURE(Test, testInlineEndnoteAndFootnote)
 CPPUNIT_ASSERT_LESS(nFootnoteTop, nEndnoteTop);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testInlineEndnoteAndSection)
+{
+// Given a document ending with a section, ContinuousEndnotes is true:
+createSwDoc("inline-endnote-and-section.odt");
+
+// When laying out that document:
+xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+// Then make sure the endnote section is after the section at the end of 
the document, not
+// inside it:
+int nToplevelSections = countXPathNodes(pXmlDoc, 
"/root/page/body/section"_ostr);
+// Without the accompanying fix in place, this test would have failed with:
+// - Expected: 2
+// - Actual  : 1
+// and we even crashed on shutdown.
+CPPUNIT_ASSERT_EQUAL(2, nToplevelSections);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx
index 4be87ee57ccd..61a8385d51fc 100644
--- a/sw/source/core/layout/ftnfrm.cxx
+++ b/sw/source/core/layout/ftnfrm.cxx
@@ -1560,7 +1560,21 @@ void SwFootnoteBossFrame::AppendFootnote( SwContentFrame 
*pRef, SwTextFootnote *
 {
 SwSection* pSwSection = 
pDoc->GetEndNoteInfo().GetSwSection(*pDoc);
 pEndnoteSection = new SwSectionFrame(*pSwSection, pPage);
-pEndnoteSection->InsertBehind(pPage->FindBodyCont(), 
pPage->FindLastBodyContent());
+SwLayoutFrame* pParent = pPage->FindBodyCont();
+SwFrame* pBefore = pPage->FindLastBodyContent();
+while (pBefore)
+{
+// Check if the last content frame is directly under the 
body frame or there is
+// something in-between, e.g. a section frame.
+if (pBefore->GetUpper() == pParent)
+{
+break;
+}
+
+// If so, insert behind the parent of the content frame, 
not inside the parent.
+pBefore = pBefore->GetUpper();
+}
+pEndnoteSection->InsertBehind(pParent, pBefore);
 pEndnoteSection->Init();
 pEndnoteSection->SetEndNoteSection(true);
 }


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-16 Thread Miklos Vajna (via logerrit)
 sw/qa/core/layout/data/inline-endnote-and-footnote.doc |binary
 sw/qa/core/layout/ftnfrm.cxx   |   21 +++
 sw/source/core/layout/flowfrm.cxx  |   37 -
 sw/source/core/layout/ftnfrm.cxx   |   45 ++---
 sw/source/core/text/txtftn.cxx |   10 ---
 5 files changed, 83 insertions(+), 30 deletions(-)

New commits:
commit ad3586d6c6b03d588a45610e1f091f83b16b83a2
Author: Miklos Vajna 
AuthorDate: Tue May 14 08:28:33 2024 +0200
Commit: Caolán McNamara 
CommitDate: Thu May 16 15:57:41 2024 +0200

tdf#160984 sw continuous endnotes: switch to a section-based layout

The original layout added in commit
4814e8caa5f06c4fe438dfd7d7315e4a2410ea18 (tdf#124601 sw: add
ContinuousEndnotes layout compat option, 2019-09-30) puts endnotes to
the footnote container on the last page, which fixes the page count but
the endnote position is wrong: should be after the body text, not at the
bottom of the page.

Now that we can have an endnote section (with one or more section frames
at a layout level), we have a container that can span over multiple
pages, is at the end of the document and is inline.

Fix the bad position by:

1) Reverting the layout changes from the old approach, which gives us a
   bad position for the endnote.

2) Creating an endnote section frame on demand in
   SwFootnoteBossFrame::AppendFootnote().

3) Moving part of the endnote to a next page works out of the box, but
   moving part of the endnote to a previous page needs explicit handling
   in SwFlowFrame::MoveBwd(), similar to how SwFrame::GetPrevSctLeaf()
   does this in the simple section case. This needs explicit handling,
   because the body frame of the endnote section is empty, all content goes
   to its endnote container.

Note that this just reimplements the compat flag, but its enablement
(only for DOC import, only for <= 2 endnotes) stays unchanged for now.

(cherry picked from commit 6885dcd7ec7b82a946d8344bfc27a3e88eecc44a)

Change-Id: I8b271895aeff378418aed8705fe6b99a69232bd2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167727
Tested-by: Jenkins CollaboraOffice 
Tested-by: Caolán McNamara 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/core/layout/data/inline-endnote-and-footnote.doc 
b/sw/qa/core/layout/data/inline-endnote-and-footnote.doc
new file mode 100644
index ..39c5636e1e12
Binary files /dev/null and 
b/sw/qa/core/layout/data/inline-endnote-and-footnote.doc differ
diff --git a/sw/qa/core/layout/ftnfrm.cxx b/sw/qa/core/layout/ftnfrm.cxx
index 4c874202da3f..71fd3fd67150 100644
--- a/sw/qa/core/layout/ftnfrm.cxx
+++ b/sw/qa/core/layout/ftnfrm.cxx
@@ -63,4 +63,25 @@ CPPUNIT_TEST_FIXTURE(Test, testFlySplitFootnoteLayout)
 CPPUNIT_ASSERT(pPage->FindFootnoteCont());
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testInlineEndnoteAndFootnote)
+{
+// Given a DOC file with an endnote and then a footnote:
+createSwDoc("inline-endnote-and-footnote.doc");
+
+// When laying out that document:
+xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+// Then make sure the footnote is below the endnote:
+// Without the accompanying fix in place, this test would have failed with:
+// - xpath should match exactly 1 node
+// i.e. the endnote was also in the footnote container, not at the end of 
the body text.
+sal_Int32 nEndnoteTop
+= 
parseDump("/root/page/body/section/column/ftncont/ftn/infos/bounds"_ostr, 
"top"_ostr)
+  .toInt32();
+sal_Int32 nFootnoteTop
+= parseDump("/root/page/ftncont/ftn/infos/bounds"_ostr, 
"top"_ostr).toInt32();
+// Endnote at the end of body text, footnote at page bottom.
+CPPUNIT_ASSERT_LESS(nFootnoteTop, nEndnoteTop);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/flowfrm.cxx 
b/sw/source/core/layout/flowfrm.cxx
index 37fd20b323d7..1cb5cf7bf47a 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -2257,18 +2257,47 @@ bool SwFlowFrame::MoveBwd( bool  )
 const bool bEndnote = pFootnote->GetAttr()->GetFootnote().IsEndNote();
 const IDocumentSettingAccess& rSettings
 = pFootnote->GetAttrSet()->GetDoc()->getIDocumentSettingAccess();
-if( bEndnote && pFootnote->IsInSct() )
+bool bContEndnotes = 
rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES);
+if( bEndnote && pFootnote->IsInSct() && !bContEndnotes)
 {
 SwSectionFrame* pSect = pFootnote->FindSctFrame();
 if( pSect->IsEndnAtEnd() )
 // Endnotes at the end of the section.
 pRef = pSect->FindLastContent( SwFindMode::LastCnt );
 }
-else if (bEndnote && 
rSettings.get(DocumentSettingId::CONTINUOUS_ENDNOTES))
+else 

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-15 Thread Miklos Vajna (via logerrit)
 sw/qa/core/layout/calcmove.cxx  |   19 +++
 sw/qa/core/layout/data/ignore-top-margin-table.docx |binary
 sw/source/core/layout/calcmove.cxx  |6 +++---
 3 files changed, 22 insertions(+), 3 deletions(-)

New commits:
commit 07c93a65d2c8579adb100b7ae0c312e1872a1f37
Author: Miklos Vajna 
AuthorDate: Tue May 14 13:49:51 2024 +0200
Commit: Caolán McNamara 
CommitDate: Wed May 15 13:45:49 2024 +0200

tdf#160952 sw: ignore top margin only at page top, not e.g. table top

The bugdoc has a table at the top of the 2nd page and we ignored the top
margin inside the table cell (for the first paragraph), while this
doesn't happen in Word.

As mentioned at

,
the old code assumed "top of the page" for all frames not having a
previous frame, while that code was only tested with text frames
directly in the body frame of a page frame.

Fix the problem by limiting this "collapse upper spacing" behavior to
frames directly in body frames. This keeps the old bugdoc working, but
is meant to restore the old, wanted behavior in other cases like e.g. in
table cells.

If later it's discovered that upper spacing collapsing is wanted in
other contexts, those are best added on a case by case basis.

(cherry picked from commit 6025ac371bd5cd07c0af550d78db323ad394173b)

Change-Id: Ieb93facd8b2e7f6412fd20873c10ce6c8b775619
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167690
Tested-by: Jenkins CollaboraOffice 
Tested-by: Caolán McNamara 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/core/layout/calcmove.cxx b/sw/qa/core/layout/calcmove.cxx
index 3e4deec52ae8..a44dc1256b83 100644
--- a/sw/qa/core/layout/calcmove.cxx
+++ b/sw/qa/core/layout/calcmove.cxx
@@ -39,6 +39,25 @@ CPPUNIT_TEST_FIXTURE(Test, testIgnoreTopMargin)
 // i.e. the top margin in the first para of a non-first page wasn't 
ignored, like in Word.
 CPPUNIT_ASSERT_EQUAL(static_cast(0), nParaTopMargin);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testIgnoreTopMarginTable)
+{
+// Given a DOCX (>= Word 2013) file, with 2 pages:
+// When loading that document:
+createSwDoc("ignore-top-margin-table.docx");
+
+// Then make sure that the paragraph on the 2nd page in B1 has a top 
margin:
+xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+sal_Int32 nParaTopMargin
+= getXPath(pXmlDoc, 
"/root/page[2]/body/tab/row/cell[2]/txt/infos/prtBounds"_ostr,
+   "top"_ostr)
+  .toInt32();
+// Without the accompanying fix in place, this test would have failed with:
+// - Expected: 2000
+// - Actual  : 0
+// i.e. the top margin in B1's first paragraph was ignored, but not in 
Word.
+CPPUNIT_ASSERT_EQUAL(static_cast(2000), nParaTopMargin);
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/layout/data/ignore-top-margin-table.docx 
b/sw/qa/core/layout/data/ignore-top-margin-table.docx
new file mode 100644
index ..c82f6d63c13f
Binary files /dev/null and 
b/sw/qa/core/layout/data/ignore-top-margin-table.docx differ
diff --git a/sw/source/core/layout/calcmove.cxx 
b/sw/source/core/layout/calcmove.cxx
index 081472b98ee3..63c774c25cd6 100644
--- a/sw/source/core/layout/calcmove.cxx
+++ b/sw/source/core/layout/calcmove.cxx
@@ -1092,9 +1092,9 @@ bool SwFrame::IsCollapseUpper() const
 return false;
 }
 
-// Word >= 2013 style: when we're at the top of the page, but not on the 
first page, then ignore
-// the upper margin for paragraphs.
-if (GetPrev())
+// Word >= 2013 style: when we're at the top of the page's body, but not 
on the first page, then
+// ignore the upper margin for paragraphs.
+if (GetPrev() || !GetUpper() || !GetUpper()->IsBodyFrame())
 {
 return false;
 }


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source writerfilter/source

2024-05-13 Thread Michael Stahl (via logerrit)
 sw/qa/extras/ooxmlexport/ooxmlexport17.cxx  |4 -
 sw/source/core/fields/reffld.cxx|   66 +++-
 writerfilter/source/dmapper/StyleSheetTable.cxx |   14 +
 3 files changed, 58 insertions(+), 26 deletions(-)

New commits:
commit ec1c8270dd25fee7035e3fec5d22d220c12c7071
Author: Michael Stahl 
AuthorDate: Fri May 3 19:31:20 2024 +0200
Commit: Miklos Vajna 
CommitDate: Mon May 13 11:38:09 2024 +0200

tdf#160402 writerfilter,sw: STYLEREF field can refer to character style

Adapt SwGetRefFieldType::FindAnchor() to search for SwTextCharFormat,
and ApplyClonedTOCStylesToXText() to replace "CharStyleName".

Works for the "Intensive Hervorhebung" field in bugdoc.

(cherry picked from commit 74f859b5525da0760a70ab660bd912dabfd608ca)

Change-Id: Iee126eeb4cc2ff1c570941e3beefd93527c56fee
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167564
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Miklos Vajna 

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
index f0d5004f73b5..dee26b595c08 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
@@ -746,9 +746,9 @@ DECLARE_OOXMLEXPORT_TEST(testTdf160402, "StyleRef-DE.docx")
 xmlDocUniquePtr pLayout = parseLayoutDump();
 assertXPath(pLayout, 
"/root/page[1]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion"_ostr, 
"expand"_ostr, "Heading 1");
 assertXPath(pLayout, 
"/root/page[2]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion"_ostr, 
"expand"_ostr, "Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.");
-assertXPath(pLayout, 
"/root/page[3]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion"_ostr, 
"expand"_ostr, "Error: Reference source not found"); // TODO
+assertXPath(pLayout, 
"/root/page[3]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion"_ostr, 
"expand"_ostr, "Cras faucibus condimentum odio. Sed ac ligula. Aliquam at 
eros.");
 assertXPath(pLayout, 
"/root/page[4]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion"_ostr, 
"expand"_ostr, "Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.");
-assertXPath(pLayout, 
"/root/page[5]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion"_ostr, 
"expand"_ostr, "Error: Reference source not found"); // TODO
+assertXPath(pLayout, 
"/root/page[5]/header/txt[1]/SwParaPortion/SwLineLayout/SwFieldPortion"_ostr, 
"expand"_ostr, "Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.");
 }
 
 DECLARE_OOXMLEXPORT_TEST(testTdf142407, "tdf142407.docx")
diff --git a/sw/source/core/fields/reffld.cxx b/sw/source/core/fields/reffld.cxx
index 0ee26771bb2c..85a18c78927f 100644
--- a/sw/source/core/fields/reffld.cxx
+++ b/sw/source/core/fields/reffld.cxx
@@ -1220,7 +1220,9 @@ namespace
 /// Picks the first text node with a matching style from a double ended 
queue, starting at the front
 /// This allows us to use the deque either as a stack or as a queue 
depending on whether we want to search up or down
 SwTextNode* SearchForStyleAnchor(SwTextNode* pSelf, const 
std::deque& pToSearch,
-std::u16string_view rStyleName, bool 
bCaseSensitive = true)
+std::u16string_view rStyleName,
+sal_Int32 *const pStart, sal_Int32 *const 
pEnd,
+bool bCaseSensitive = true)
 {
 std::deque pSearching(pToSearch);
 while (!pSearching.empty())
@@ -1235,15 +1237,38 @@ namespace
 if (!pTextNode)
 continue;
 
-if (bCaseSensitive)
+if (bCaseSensitive
+? pTextNode->GetFormatColl()->GetName() == rStyleName
+: 
pTextNode->GetFormatColl()->GetName().equalsIgnoreAsciiCase(rStyleName))
 {
-if (pTextNode->GetFormatColl()->GetName() == rStyleName)
-return pTextNode;
+*pStart = 0;
+if (pEnd)
+{
+*pEnd = pTextNode->GetText().getLength();
+}
+return pTextNode;
 }
-else
+
+if (auto const pHints = pTextNode->GetpSwpHints())
 {
-if 
(pTextNode->GetFormatColl()->GetName().equalsIgnoreAsciiCase(rStyleName))
-return pTextNode;
+for (size_t i = 0; i < pHints->Count(); ++i)
+{
+auto const*const pHint(pHints->Get(i));
+if (pHint->Which() == RES_TXTATR_CHARFMT)
+{
+if (bCaseSensitive
+? 
pHint->GetCharFormat().GetCharFormat()->HasName(rStyleName)
+: 
pHint->GetCharFormat().GetCharFormat()->GetName().equalsIgnoreAsciiCase(rStyleName))
+

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-09 Thread Miklos Vajna (via logerrit)
 sw/qa/core/txtnode/data/plain-content-control-copy.docx |binary
 sw/qa/core/txtnode/txtnode.cxx  |   23 
 sw/source/core/txtnode/thints.cxx   |4 ++
 3 files changed, 26 insertions(+), 1 deletion(-)

New commits:
commit 47c917bcdbffd6423f50a3d970ed45ce06b9061e
Author: Miklos Vajna 
AuthorDate: Tue Apr 30 08:44:59 2024 +0200
Commit: Miklos Vajna 
CommitDate: Thu May 9 09:33:22 2024 +0200

tdf#159683 sw content controls, plain text: fix crash with the clipboard doc

Regression from commit c804c5354855188b5a37219cfe11dc079dc235f4 (sw
content control: fix lost properties on copy, 2023-03-10), select
a plain text content control, copy it to the clipboard, quit: assertion
fails during shutdown because the doc's "placeholder text" char style is
still referenced by a client.

What happens here is that the SwContentControl copy ctor copies the
plain text flag, and that flag is only read in SwTextNode::InsertHint(),
so that causes the problem. Note how that code is inconsistent: we avoid
the creation of dummy characters in the copy case, but we still try to
adjust the start/end of the content control attribute in the copy case,
which makes not much sense.

Fix the problem by not adjusting the content control attribute
boundaries in the copy case, since the original intention was to do
thees corrections only at a UI level, during interactive edit.

It's not clear why this inconsistency had an influence on the clients of
the char style, though.

Change-Id: I86b0516464f24fc453dcd97588dafb8afd010a9e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166882
Reviewed-by: Miklos Vajna 
Tested-by: Jenkins
(cherry picked from commit 06aeb9c61d50bba7edafe17f9d3513af26b0782f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167311
Reviewed-by: Xisco Fauli 
(cherry picked from commit 32616609c788aa1cf0837af0f387390a23de1766)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167375
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/core/txtnode/data/plain-content-control-copy.docx 
b/sw/qa/core/txtnode/data/plain-content-control-copy.docx
new file mode 100644
index ..80fecae26d5b
Binary files /dev/null and 
b/sw/qa/core/txtnode/data/plain-content-control-copy.docx differ
diff --git a/sw/qa/core/txtnode/txtnode.cxx b/sw/qa/core/txtnode/txtnode.cxx
index c2df8a407e69..be4d97190251 100644
--- a/sw/qa/core/txtnode/txtnode.cxx
+++ b/sw/qa/core/txtnode/txtnode.cxx
@@ -539,6 +539,29 @@ CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, 
testSplitFlyAnchorSplit)
 CPPUNIT_ASSERT_EQUAL(OUString("PortionType::Fly"), aPortionType);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testPlainContentControlCopy)
+{
+// Given a document with a plain text content control, all text selected 
and copied to the
+// clipboard:
+createSwDoc("plain-content-control-copy.docx");
+SwDocShell* pDocShell = getSwDocShell();
+SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+pWrtShell->SelAll();
+{
+rtl::Reference xTransfer = new 
SwTransferable(*pWrtShell);
+xTransfer->Copy();
+}
+
+// When closing that document, then make sure we don't crash on shutdown:
+uno::Reference xModel(mxComponent, uno::UNO_QUERY);
+uno::Reference 
xFrame(xModel->getCurrentController()->getFrame(),
+uno::UNO_QUERY);
+// Without the accompanying fix in place, this resulted in an assertion 
failure, a char style
+// still had clients by the time it was deleted.
+xFrame->close(false);
+mxComponent.clear();
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/thints.cxx 
b/sw/source/core/txtnode/thints.cxx
index cf5e1ff1cccf..c499294f4f26 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -1700,7 +1700,9 @@ bool SwTextNode::InsertHint( SwTextAttr * const pAttr, 
const SetAttrMode nMode )
 // for all of its content.
 auto* pTextContentControl = static_txtattr_cast(
 GetTextAttrAt(pAttr->GetStart(), RES_TXTATR_CONTENTCONTROL, 
::sw::GetTextAttrMode::Parent));
-if (pTextContentControl)
+// If the caller is SwTextNode::CopyText, we just copy an existing 
attribute, no need to
+// correct it.
+if (pTextContentControl && !(nMode & SetAttrMode::NOTXTATRCHR))
 {
 auto& rFormatContentControl
 = 
static_cast(pTextContentControl->GetAttr());


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-03 Thread Miklos Vajna (via logerrit)
 sw/qa/extras/ww8export/data/draw-obj-rtl-no-mirror-vml.docx |binary
 sw/qa/extras/ww8export/ww8export4.cxx   |   24 
 sw/source/filter/ww8/wrtw8esh.cxx   |6 +++
 3 files changed, 30 insertions(+)

New commits:
commit 3e9ff13bb78c56b5ddc6316b0b73c8a21ea7c0b0
Author: Miklos Vajna 
AuthorDate: Fri May 3 12:00:59 2024 +0200
Commit: Caolán McNamara 
CommitDate: Fri May 3 15:16:56 2024 +0200

Related: tdf#160833 teach DOC export about DoNotMirrorRtlDrawObjs

See

,
no need to undo the import-time mapping in case we know that the
mirroring is avoided at a layout level.

Change-Id: Idbdc10ad327540dc5045e9b19dd42160b5139470
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167048
Tested-by: Jenkins CollaboraOffice 
Tested-by: Caolán McNamara 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/extras/ww8export/data/draw-obj-rtl-no-mirror-vml.docx 
b/sw/qa/extras/ww8export/data/draw-obj-rtl-no-mirror-vml.docx
new file mode 100644
index ..3b291901f72d
Binary files /dev/null and 
b/sw/qa/extras/ww8export/data/draw-obj-rtl-no-mirror-vml.docx differ
diff --git a/sw/qa/extras/ww8export/ww8export4.cxx 
b/sw/qa/extras/ww8export/ww8export4.cxx
index e297ac949afe..b25d3b4a7701 100644
--- a/sw/qa/extras/ww8export/ww8export4.cxx
+++ b/sw/qa/extras/ww8export/ww8export4.cxx
@@ -262,6 +262,30 @@ CPPUNIT_TEST_FIXTURE(Test, testLegalNumbering)
 verify();
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testDOCExportDoNotMirrorRtlDrawObjs)
+{
+// Given a document with a shape, anchored in an RTL paragraph, loaded 
from DOCX:
+createSwDoc("draw-obj-rtl-no-mirror-vml.docx");
+
+// When saving that to DOC:
+saveAndReload(mpFilter);
+
+// Then make sure the shape is on the right margin:
+xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+sal_Int32 nPageRight = getXPath(pXmlDoc, "//page/infos/bounds"_ostr, 
"right"_ostr).toInt32();
+sal_Int32 nBodyRight = getXPath(pXmlDoc, "//body/infos/bounds"_ostr, 
"right"_ostr).toInt32();
+sal_Int32 nShapeLeft
+= getXPath(pXmlDoc, "//SwAnchoredDrawObject/bounds"_ostr, 
"left"_ostr).toInt32();
+CPPUNIT_ASSERT_GREATER(nBodyRight, nShapeLeft);
+sal_Int32 nShapeRight
+= getXPath(pXmlDoc, "//SwAnchoredDrawObject/bounds"_ostr, 
"right"_ostr).toInt32();
+// Without the accompanying fix in place, this test would have failed with:
+// - Expected less than: 12523
+// - Actual  : 12536
+// i.e. the shape was outside of the page right margin area, due to an 
unwanted mapping.
+CPPUNIT_ASSERT_LESS(nPageRight, nShapeRight);
+}
+
 DECLARE_WW8EXPORT_TEST(testNonInlinePageBreakFirstLine, 
"nonInlinePageBreakFirstLine.doc")
 {
 SwDoc* pDoc = getSwDoc();
diff --git a/sw/source/filter/ww8/wrtw8esh.cxx 
b/sw/source/filter/ww8/wrtw8esh.cxx
index f9e1082f9276..3e7087221db0 100644
--- a/sw/source/filter/ww8/wrtw8esh.cxx
+++ b/sw/source/filter/ww8/wrtw8esh.cxx
@@ -577,6 +577,12 @@ void WW8Export::MiserableRTLFrameFormatHack(SwTwips 
, SwTwips ,
 if (SvxFrameDirection::Horizontal_RL_TB != 
m_rDoc.GetTextDirection(rFrameFormat.GetPosition()))
 return;
 
+if 
(m_rDoc.getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_MIRROR_RTL_DRAW_OBJS))
+{
+// Swap is handled at a layout-level, no need to compensate for it at 
export time.
+return;
+}
+
 SwTwips nWidth = rRight - rLeft;
 SwTwips nPageLeft, nPageRight;
 SwTwips nPageSize = CurrentPageWidth(nPageLeft, nPageRight);


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-05-02 Thread Miklos Vajna (via logerrit)
 sw/qa/core/objectpositioning/objectpositioning.cxx  |   48 
 sw/source/core/objectpositioning/anchoredobjectposition.cxx |5 +
 2 files changed, 52 insertions(+), 1 deletion(-)

New commits:
commit 7f790600a530f7ca7c1e7de0abc0a5bf2f6b3023
Author: Miklos Vajna 
AuthorDate: Tue Apr 30 08:22:03 2024 +0200
Commit: Caolán McNamara 
CommitDate: Thu May 2 14:26:20 2024 +0200

tdf#160833 sw DoNotMirrorRtlDrawObjs: add layout

In case this flag is active (intended for DOCX files), then don't
automatically mirror the position of drawing objects, just because they
are anchored in an RTL text node.

(cherry picked from commit 016b2f2f9194a4a1997d0e7bb51bbd1b10bc27ec)

Change-Id: Ie743d94ecb511d7de89e8e1e8303896370ce58c8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167013
Tested-by: Jenkins CollaboraOffice 
Tested-by: Caolán McNamara 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/core/objectpositioning/objectpositioning.cxx 
b/sw/qa/core/objectpositioning/objectpositioning.cxx
index bf560cbdaf90..a1805bf4508e 100644
--- a/sw/qa/core/objectpositioning/objectpositioning.cxx
+++ b/sw/qa/core/objectpositioning/objectpositioning.cxx
@@ -24,6 +24,10 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
 namespace
 {
@@ -404,6 +408,50 @@ CPPUNIT_TEST_FIXTURE(Test, testFloatingTableOverlapCell)
 CPPUNIT_ASSERT(pPage1);
 CPPUNIT_ASSERT(!pPage1->GetNext());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testDoNotMirrorRtlDrawObjsLayout)
+{
+// Given a document with an RTL paragraph, Word-style compat flag is 
enabled:
+createSwDoc();
+SwDoc* pDoc = getSwDoc();
+auto& rIDSA = pDoc->getIDocumentSettingAccess();
+rIDSA.set(DocumentSettingId::DO_NOT_MIRROR_RTL_DRAW_OBJS, true);
+SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+SwView& rView = pWrtShell->GetView();
+SfxItemSetFixed aSet(rView.GetPool());
+SvxFrameDirectionItem aDirection(SvxFrameDirection::Horizontal_RL_TB, 
RES_FRAMEDIR);
+aSet.Put(aDirection);
+pWrtShell->SetAttrSet(aSet, SetAttrMode::DEFAULT, nullptr, 
/*bParagraphSetting=*/true);
+SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+auto pPageFrame = pLayout->Lower()->DynCastPageFrame();
+SwFrame* pBodyFrame = pPageFrame->GetLower();
+
+// When inserting a graphic on the middle of the right margin:
+SfxItemSet aFrameSet(pDoc->GetAttrPool(), svl::Items);
+SwFormatAnchor aAnchor(RndStdIds::FLY_AT_CHAR);
+aFrameSet.Put(aAnchor);
+// Default margin is 1440, this is 1440/2.
+SwFormatFrameSize aSize(SwFrameSize::Fixed, 720, 720);
+aFrameSet.Put(aSize);
+// This is 1440/4.
+SwFormatHoriOrient aOrient(pBodyFrame->getFrameArea().Right() + 360);
+aFrameSet.Put(aOrient);
+Graphic aGrf;
+pWrtShell->SwFEShell::Insert(OUString(), OUString(), , );
+
+// Then make sure that the image is on the right margin:
+SwTwips nBodyRight = pBodyFrame->getFrameArea().Right();
+CPPUNIT_ASSERT(pPageFrame->GetSortedObjs());
+const SwSortedObjs& rPageObjs = *pPageFrame->GetSortedObjs();
+CPPUNIT_ASSERT_EQUAL(static_cast(1), rPageObjs.size());
+const SwAnchoredObject* pAnchored = rPageObjs[0];
+Point aAnchoredCenter = 
pAnchored->GetDrawObj()->GetLastBoundRect().Center();
+// Without the accompanying fix in place, this test would have failed with:
+// - Expected greater than: 11389
+// - Actual  : 643
+// i.e. the graphic was on the left margin, not on the right margin.
+CPPUNIT_ASSERT_GREATER(nBodyRight, aAnchoredCenter.getX());
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/objectpositioning/anchoredobjectposition.cxx 
b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
index ab35ae7af738..4af3af542b27 100644
--- a/sw/source/core/objectpositioning/anchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
@@ -852,7 +852,10 @@ SwTwips SwAnchoredObjectPosition::CalcRelPosX(
 if ( _rHoriOrient.GetHoriOrient() == text::HoriOrientation::NONE )
 {
 // 'manual' horizontal position
-const bool bR2L = rAnchorFrame.IsRightToLeft();
+const IDocumentSettingAccess& rIDSA = 
mpFrameFormat->getIDocumentSettingAccess();
+// If compat flag is active, then disable automatic mirroring for RTL.
+bool bMirrorRtlDrawObjs = 
!rIDSA.get(DocumentSettingId::DO_NOT_MIRROR_RTL_DRAW_OBJS);
+const bool bR2L = rAnchorFrame.IsRightToLeft() && bMirrorRtlDrawObjs;
 if( IsAnchoredToChar() && text::RelOrientation::CHAR == eRelOrient )
 {
 if( bR2L )


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-04-30 Thread Miklos Vajna (via logerrit)
 sw/qa/core/frmedt/frmedt.cxx |   35 +
 sw/source/core/frmedt/fefly1.cxx |   47 ++-
 2 files changed, 81 insertions(+), 1 deletion(-)

New commits:
commit d7f6f7bd0dd5428bd1fd483dd13102174a19cd8e
Author: Miklos Vajna 
AuthorDate: Tue Apr 23 08:29:07 2024 +0200
Commit: Miklos Vajna 
CommitDate: Tue Apr 30 09:17:24 2024 +0200

tdf#159379 sw: fix crash on dropping multiple as-char images

Have an empty Writer document, set preferences so images created via
drag are anchored as-char, drop 2 images from a file manager,
crash.

The root of the problem is that the first image gets dropped fine, but
the second one would be anchored to the currently selected graphic node,
since commit 651527b4efe9700c8c8dff58ce5aa86ad5681f16 (sw: fix
double-click opening frame dialog, not graphic dialog on images,
2022-04-26).

The new SwTextCursor::GetModelPositionForViewPoint() returning a graphic
node for a point inside the image looks correct, so fix the problem by
extending SwFEShell::Insert() to take the anchor position as the anchor
for the new image, in case a graphic node is selected.

The original use-case would use SwEditWin::ExecuteDrop(), but keep the
test simple and invoke the underlying SwFEShell::Insert() instead, that
also triggers the problem.

Change-Id: Ibba57aa28d0616ded16b4abb314f04974f1b8f9a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166499
Tested-by: Jenkins
Reviewed-by: Miklos Vajna 
(cherry picked from commit f9f2b7590bb7b3334d499b6884cc7f3e80843b8c)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166511
Reviewed-by: Xisco Fauli 
(cherry picked from commit 008b1c3a8652b33b9b42ca0794a21ce9754e96f2)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166884
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/core/frmedt/frmedt.cxx b/sw/qa/core/frmedt/frmedt.cxx
index b2a53e60db27..37425c13060e 100644
--- a/sw/qa/core/frmedt/frmedt.cxx
+++ b/sw/qa/core/frmedt/frmedt.cxx
@@ -250,6 +250,41 @@ CPPUNIT_TEST_FIXTURE(SwCoreFrmedtTest, testSplitFlyUnfloat)
 CPPUNIT_ASSERT_EQUAL(static_cast(1), 
pDoc->GetTableFrameFormatCount(/*bUsed=*/true));
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreFrmedtTest, testInsertOnGrfNodeAsChar)
+{
+// Given a selected as-char image:
+createSwDoc();
+SwDoc* pDoc = getSwDocShell()->GetDoc();
+SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+{
+SfxItemSet aFrameSet(pDoc->GetAttrPool(), svl::Items);
+SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
+aFrameSet.Put(aAnchor);
+Graphic aGrf;
+pWrtShell->SwFEShell::Insert(OUString(), OUString(), , 
);
+}
+
+// When inserting another as-char image:
+SfxItemSet aFrameSet(pDoc->GetAttrPool(), svl::Items);
+SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
+aFrameSet.Put(aAnchor);
+Graphic aGrf;
+// Without the accompanying fix in place, this call crashed, we try to set 
a graphic node as an
+// anchor of an as-char image (which should be a text node).
+pWrtShell->SwFEShell::Insert(OUString(), OUString(), , );
+
+// Then make sure that the anchor of the second image is next to the first 
anchor:
+CPPUNIT_ASSERT(pDoc->GetSpzFrameFormats());
+sw::FrameFormats& rFormats = 
*pDoc->GetSpzFrameFormats();
+CPPUNIT_ASSERT_EQUAL(static_cast(2), rFormats.size());
+const sw::SpzFrameFormat& rFormat1 = *rFormats[0];
+const SwPosition* pAnchor1 = rFormat1.GetAnchor().GetContentAnchor();
+const sw::SpzFrameFormat& rFormat2 = *rFormats[1];
+const SwPosition* pAnchor2 = rFormat2.GetAnchor().GetContentAnchor();
+CPPUNIT_ASSERT_EQUAL(pAnchor1->nNode, pAnchor2->nNode);
+CPPUNIT_ASSERT_EQUAL(pAnchor1->GetContentIndex() + 1, 
pAnchor2->GetContentIndex());
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/frmedt/fefly1.cxx b/sw/source/core/frmedt/fefly1.cxx
index 93ad4212cf65..2e5b8bf53d15 100644
--- a/sw/source/core/frmedt/fefly1.cxx
+++ b/sw/source/core/frmedt/fefly1.cxx
@@ -890,6 +890,43 @@ const SwFrameFormat *SwFEShell::NewFlyFrame( const 
SfxItemSet& rSet, bool bAnchV
 return pRet;
 }
 
+namespace
+{
+/// If pCursor points to an as-char anchored graphic node, then set the node's 
anchor position on
+/// pAnchor and rPam.
+bool SetAnchorOnGrfNodeForAsChar(SwShellCursor *pCursor, SwFormatAnchor* 
pAnchor, std::optional& rPam)
+{
+const SwPosition* pPoint = pCursor->GetPoint();
+if (pAnchor->GetAnchorId() != RndStdIds::FLY_AS_CHAR)
+{
+return false;
+}
+
+if (!pPoint->GetNode().IsGrfNode())
+{
+return false;
+}
+
+SwFrameFormat* pFrameFormat = pPoint->GetNode().GetFlyFormat();
+if (!pFrameFormat)
+{
+return false;
+}
+
+const SwPosition* pContentAnchor = 

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-03-21 Thread Justin Luth (via logerrit)
 sw/qa/extras/uiwriter/data/tdf159054_disableOutlineNumbering.docx |binary
 sw/qa/extras/uiwriter/uiwriter9.cxx   |   43 
++
 sw/source/core/doc/docnum.cxx |   11 +-
 sw/source/uibase/shells/txtnum.cxx|1 
 sw/source/uibase/wrtsh/wrtsh1.cxx |   31 
---
 5 files changed, 52 insertions(+), 34 deletions(-)

New commits:
commit 5956bb9937164a815bccadd4801dee63c28367f5
Author: Justin Luth 
AuthorDate: Mon Mar 18 16:56:55 2024 -0400
Commit: Miklos Vajna 
CommitDate: Thu Mar 21 10:54:23 2024 +0100

tdf#159054 sw: fix .uno:DefaultNumber toggle on Heading numbering

This fixes a 7.2 regression from
commit c456f839a597f537f1c59becd7d0bb6c86248ef8
Author: Anshu on Wed Jan 6 15:04:16 2021 +0530
tdf#115965 tdf#92622 NoList default in menu,tool,sidebar

The current implementation would set the number format
to SVX_NUM_NUMBER_NONE, but it still looks like a number to the toolbar,
so toggling didn't work since 7.4's bcede3c0ed94d4
It also never cleared out the prefix/suffix when toggled off,
and it affected ALL paragraphs using that outline numbering style.

Remove numbering was doing the same kind of thing.

I think the toggle was trying to follow the drop-down behaviour
of modifying the outline numbering style itself.
While I think the drop-down handling could be considered appropriate,
using the toggle to pseudo-disable the entire style just seems wrong.

This patch kills that, and in addition
automatically gains all the nice undo/redo functionality.

This is one tiny step in making outline numbering go away.

make CppunitTest_sw_uiwriter9 \
CPPUNIT_TEST_NAME=testTdf159054_disableOutlineNumbering

Change-Id: Id6a24ac25479cb8f35bf1c2c58344390ed7512fe
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164985
Reviewed-by: Justin Luth 
Tested-by: Justin Luth 
Reviewed-by: Miklos Vajna 
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165076
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/extras/uiwriter/data/tdf159054_disableOutlineNumbering.docx 
b/sw/qa/extras/uiwriter/data/tdf159054_disableOutlineNumbering.docx
new file mode 100644
index ..091a3830e75b
Binary files /dev/null and 
b/sw/qa/extras/uiwriter/data/tdf159054_disableOutlineNumbering.docx differ
diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx 
b/sw/qa/extras/uiwriter/uiwriter9.cxx
index 3772955dd9c1..96ea65e988d9 100644
--- a/sw/qa/extras/uiwriter/uiwriter9.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter9.cxx
@@ -200,6 +200,49 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159816)
 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, 
/*bXSelection=*/true);
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159054_disableOutlineNumbering)
+{
+createSwDoc("tdf159054_disableOutlineNumbering.docx");
+SwDoc* pDoc = getSwDoc();
+SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+const uno::Reference xPara1 = getParagraph(1, "Heading 
A");
+const uno::Reference xPara2 = getParagraph(2, "Heading 
B");
+const uno::Reference xPara3 = getParagraph(3, "Heading 
C");
+
+CPPUNIT_ASSERT_EQUAL(OUString("A."), getProperty(xPara1, 
"ListLabelString"));
+CPPUNIT_ASSERT_EQUAL(OUString("B."), getProperty(xPara2, 
"ListLabelString"));
+CPPUNIT_ASSERT_EQUAL(OUString("C."), getProperty(xPara3, 
"ListLabelString"));
+
+// select (at least parts) of the first two paragraphs
+pWrtShell->Down(/*bSelect=*/true, /*nCount=*/1, /*bBasicCall=*/true);
+
+// on the selection, simulate pressing the toolbar button to toggle OFF 
numbering
+dispatchCommand(mxComponent, ".uno:DefaultNumbering", {});
+
+// the selected paragraphs should definitely have the list label removed
+CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty(xPara1, 
"ListLabelString"));
+CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty(xPara2, 
"ListLabelString"));
+// the third paragraph must retain the existing numbering format
+CPPUNIT_ASSERT_EQUAL(OUString("A."), getProperty(xPara3, 
"ListLabelString"));
+
+// on the selection, simulate pressing the toolbar button to toggle ON 
numbering again
+dispatchCommand(mxComponent, ".uno:DefaultNumbering", {});
+
+// the outline numbering format must be re-applied to the first two 
paragraphs
+CPPUNIT_ASSERT_EQUAL(OUString("A."), getProperty(xPara1, 
"ListLabelString"));
+CPPUNIT_ASSERT_EQUAL(OUString("B."), getProperty(xPara2, 
"ListLabelString"));
+CPPUNIT_ASSERT_EQUAL(OUString("C."), getProperty(xPara3, 
"ListLabelString"));
+
+// on the selection, simulate a right click - list - No list
+dispatchCommand(mxComponent, ".uno:RemoveBullets", {});
+
+// the selected paragraphs should definitely have the list label removed
+

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-03-19 Thread Justin Luth (via logerrit)
 sw/qa/extras/uiwriter/data/tdf147583_backwardSearch.odt |binary
 sw/qa/extras/uiwriter/uiwriter7.cxx |   31 +++
 sw/source/core/crsr/findtxt.cxx |   67 
 3 files changed, 66 insertions(+), 32 deletions(-)

New commits:
commit 2f5b9916baaf0017ece84bf867a9e9acfe86d61a
Author: Justin Luth 
AuthorDate: Fri Mar 15 20:01:39 2024 -0400
Commit: Miklos Vajna 
CommitDate: Tue Mar 19 08:57:27 2024 +0100

tdf#147583 sw find: fix backwards search for emptyPara/endOfPara

A comment added 10 years ago thought that it had never worked.

The very last paragraph end cannot be selected manually,
and so of course it can't work in find either.
It didn't work earlier either.

Everything goes ballistic if searching inside comments,
but that would be handled elsewhere anyway I guess.
It didn't work earlier either.

Keeping the search "inside the selection" didn't work earlier either.
That should be fixed now.

make CppunitTest_sw_uiwriter7 \
CPPUNIT_TEST_NAME=testTdf147583_backwardSearch

Change-Id: I48a72084d277b8c270255de9296a2743162937cf
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164892
Tested-by: Jenkins
Reviewed-by: Justin Luth 
Reviewed-by: Miklos Vajna 
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164982
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/extras/uiwriter/data/tdf147583_backwardSearch.odt 
b/sw/qa/extras/uiwriter/data/tdf147583_backwardSearch.odt
new file mode 100644
index ..9bfde3bfaa6b
Binary files /dev/null and 
b/sw/qa/extras/uiwriter/data/tdf147583_backwardSearch.odt differ
diff --git a/sw/qa/extras/uiwriter/uiwriter7.cxx 
b/sw/qa/extras/uiwriter/uiwriter7.cxx
index 16afe5f205c0..844e9ff06c42 100644
--- a/sw/qa/extras/uiwriter/uiwriter7.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter7.cxx
@@ -358,6 +358,37 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest7, testTextSearch)
  pCursor->GetPointNode().GetTextNode()->GetText());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest7, testTdf147583_backwardSearch)
+{
+createSwDoc("tdf147583_backwardSearch.odt");
+uno::Reference xSearch(mxComponent, uno::UNO_QUERY);
+uno::Reference xSearchDes = 
xSearch->createSearchDescriptor();
+uno::Reference xProp(xSearchDes, uno::UNO_QUERY);
+
+uno::Reference xIndex;
+const sal_Int32 nParas = getParagraphs();
+
+//specifying the search attributes
+uno::Reference xPropSet(xSearchDes, 
uno::UNO_QUERY_THROW);
+xSearchDes->setPropertyValue("SearchRegularExpression", uno::Any(true)); 
// regex
+xSearchDes->setSearchString("$"); // the end of the paragraph pilcrow 
marker
+
+// xSearchDes->setPropertyValue("SearchBackwards", uno::Any(false));
+// xIndex.set(xSearch->findAll(xSearchDes), uno::UNO_SET_THROW);
+// // all paragraphs (including the unselected last one) should be found
+// CPPUNIT_ASSERT_EQUAL(nParas, xIndex->getCount());
+
+xSearchDes->setPropertyValue("SearchBackwards", uno::Any(true));
+xIndex.set(xSearch->findAll(xSearchDes), uno::UNO_SET_THROW);
+// all paragraphs (except the troublesome last one) are found
+CPPUNIT_ASSERT_EQUAL(nParas - 1, xIndex->getCount());
+
+xSearchDes->setSearchString("^$"); // empty paragraphs
+xIndex.set(xSearch->findAll(xSearchDes), uno::UNO_SET_THROW);
+// should actually be 10 (including the empty para with the comment 
marker, and the last para)
+CPPUNIT_ASSERT_EQUAL(sal_Int32(8), xIndex->getCount());
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest7, testTdf69282)
 {
 createSwDoc();
diff --git a/sw/source/core/crsr/findtxt.cxx b/sw/source/core/crsr/findtxt.cxx
index 9d05c3290e50..ca3b19fb0be9 100644
--- a/sw/source/core/crsr/findtxt.cxx
+++ b/sw/source/core/crsr/findtxt.cxx
@@ -730,7 +730,6 @@ bool DoSearch(SwPaM & rSearchPam,
 SwRootFrame const*const pLayout, SwPaM& rPam)
 {
 bool bFound = false;
-SwPosition& rPtPos = *rPam.GetPoint();
 OUString sCleanStr;
 std::vector aFltArr;
 LanguageType eLastLang = LANGUAGE_SYSTEM;
@@ -872,39 +871,43 @@ bool DoSearch(SwPaM & rSearchPam,
 
 if ( bFound )
 return true;
-else if ((bChkEmptyPara && !nStart.GetAnyIndex() && 
!nTextLen.GetAnyIndex())
- || bChkParaEnd)
+
+if (!bChkEmptyPara && !bChkParaEnd)
+return false;
+
+if (bChkEmptyPara && bSrchForward && nTextLen.GetAnyIndex())
+return false; // the length is not zero - there is content here
+
+// move to the end (or start) of the paragraph
+*rSearchPam.GetPoint() = *rPam.GetPoint();
+if (pLayout)
 {
-*rSearchPam.GetPoint() = *rPam.GetPoint();
-if (pLayout)
-{
-*rSearchPam.GetPoint() = pFrame->MapViewToModelPos(
-bChkParaEnd ? nTextLen.GetFrameIndex() : TextFrameIndex(0));
-}
-else
-{
-rSearchPam.GetPoint()->SetContent( 

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-03-07 Thread Miklos Vajna (via logerrit)
 sw/qa/uibase/dochdl/dochdl.cxx   |   26 ++
 sw/source/uibase/dochdl/swdtflvr.cxx |9 +
 2 files changed, 35 insertions(+)

New commits:
commit 5e2e6b44e2496977397ca79b1599d07ffc4a969f
Author: Miklos Vajna 
AuthorDate: Wed Mar 6 11:03:20 2024 +0100
Commit: Caolán McNamara 
CommitDate: Thu Mar 7 09:36:56 2024 +0100

cool#8465 sw lok: classify anchored images as complex selection

Regression from commit 7a8dc25defee31edbb75a2f8c35f92ee2d3f3a83 (sw lok:
simplify SwTransferable::isComplex(), 2021-02-23), in case as-char
imagse were part of a selection, we considered that complex, but at-char
was considered as simple, which is inconsistent.

This was not intentional, simply the rework to avoid copying the
selection to a temporary document lost this functionality.

Fix the problem by using CollectFrameAtNode() to find at-char images,
which tries to use the layout, so is not meant to be too slow.

An alternative would be sw::GetFlysAnchoredAt(), but that doesn't try to
use the layout, so avoid that.

(cherry picked from commit 1bca99617ad54d966625caadd71e52134c70ae44)

Change-Id: I647d0f3934f9553de69afbf2de059631e2b5619c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164521
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/uibase/dochdl/dochdl.cxx b/sw/qa/uibase/dochdl/dochdl.cxx
index 95314b48be1f..2c209a65d3d9 100644
--- a/sw/qa/uibase/dochdl/dochdl.cxx
+++ b/sw/qa/uibase/dochdl/dochdl.cxx
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 
 /// Covers sw/source/uibase/dochdl/ fixes.
 class SwUibaseDochdlTest : public SwModelTestBase
@@ -76,6 +77,31 @@ CPPUNIT_TEST_FIXTURE(SwUibaseDochdlTest, 
testComplexSelection)
 CPPUNIT_ASSERT(!xTransfer->isComplex());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUibaseDochdlTest, testComplexSelectionAtChar)
+{
+// Given a document with an at-char anchored image:
+createSwDoc();
+SwDoc* pDoc = getSwDoc();
+SwDocShell* pDocShell = pDoc->GetDocShell();
+SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+SfxItemSet aFrameSet(pDoc->GetAttrPool(), svl::Items);
+SwFormatAnchor aAnchor(RndStdIds::FLY_AT_CHAR);
+aFrameSet.Put(aAnchor);
+Graphic aGrf;
+pWrtShell->SwFEShell::Insert(OUString(), OUString(), , );
+pWrtShell->UnSelectFrame();
+
+// When checking if the selection is simple or complex:
+pWrtShell->SelAll();
+uno::Reference xTransfer = new 
SwTransferable(*pWrtShell);
+bool bComplex = xTransfer->isComplex();
+
+// Then make sure it's complex:
+// Without the accompanying fix in place, this test would have failed, a 
selection containing an
+// image was considered simple.
+CPPUNIT_ASSERT(bComplex);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx 
b/sw/source/uibase/dochdl/swdtflvr.cxx
index ea419d2326f7..65f68e27d8c3 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -122,6 +122,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -459,6 +460,14 @@ sal_Bool SAL_CALL SwTransferable::isComplex()
 }
 }
 
+FrameClientSortList_t vFrames;
+::CollectFrameAtNode(rNd, vFrames, true);
+if (!vFrames.empty())
+{
+// There is an at-char anchored object to this node, 
that's complex.
+return true;
+}
+
 nTextLength += pTextNode->GetText().getLength();
 if (nTextLength >= 1024 * 512)
 return true; // Complex


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-03-05 Thread Miklos Vajna (via logerrit)
 sw/qa/core/layout/data/floattable-header.docx |binary
 sw/qa/core/layout/tabfrm.cxx  |   21 +
 sw/source/core/layout/tabfrm.cxx  |   12 +++-
 3 files changed, 32 insertions(+), 1 deletion(-)

New commits:
commit 2d6a0e2a354ffeba10f69634835a48d65e601846
Author: Miklos Vajna 
AuthorDate: Thu Feb 29 08:17:41 2024 +0100
Commit: Caolán McNamara 
CommitDate: Tue Mar 5 09:23:21 2024 +0100

tdf#158801 sw floattable: fix crash with headers and interactive editing

Regression from commit ce2fc5eb29b4e252993b549dee002fa8948c8386
(tdf#158341 sw floattable: fix layout loop when fly is below the body
frame, 2023-11-29), open the bugdoc, add an empty paragraph at the
start, Writer layout crashes. The immediate problem is that
SwTabFrame::MakeAll() assumes that in case HasFollowFlowLine() is true,
then GetFollow()->GetFirstNonHeadlineRow() is always non-nullptr,
similar to the situation in commit
223d2fac61e061478721a7a4a89b1362f5037d8f (sw floattable: fix crash by
trying harder to split tables, 2023-11-22).

The deeper problem is that the bugdoc has a repeated table header row,
the fly frame temporarily gets shifted down, so nominally the header
doesn't fit anymore, and this leads to a modification of the doc model,
which creates inconsistency: the model now says we have no header rows
but the layout still contains table row frames where the header bit is
true. This is problematic in theory, but in practice caused no problem
so far.

Fix the problem by disabling this mechanism for floating tables: trying
to have a table header that doesn't fit the table is asking for trouble
anyway, and this way at least we have a layout that is consistent with
the model, which also avoids the crash, now that nobody violates the
"HasFollowFlowLine -> follow's FirstNonHeadlineRow != nullptr"
invariant.

Also extend the layout dump, so it's easier to see when the master's
flag and the follow's row list gets out of sync.

(cherry picked from commit 186de7178c6065e1de13fd216b46ac9b716e44c5)

Change-Id: I52b51f6d86ab4e0bab560f892e9cceb183aecd5f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164366
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/core/layout/data/floattable-header.docx 
b/sw/qa/core/layout/data/floattable-header.docx
new file mode 100644
index ..baddd365ce37
Binary files /dev/null and b/sw/qa/core/layout/data/floattable-header.docx 
differ
diff --git a/sw/qa/core/layout/tabfrm.cxx b/sw/qa/core/layout/tabfrm.cxx
index e0d099c77102..9bfbd1b82e2a 100644
--- a/sw/qa/core/layout/tabfrm.cxx
+++ b/sw/qa/core/layout/tabfrm.cxx
@@ -17,6 +17,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 namespace
 {
@@ -235,6 +237,25 @@ CPPUNIT_TEST_FIXTURE(Test, 
testSplitFlyWrappedByTableNested)
 CPPUNIT_ASSERT_EQUAL(static_cast(3), 
pDoc->GetTableFrameFormats()->GetFormatCount());
 CPPUNIT_ASSERT_EQUAL(static_cast(1), 
pDoc->GetSpzFrameFormats()->GetFormatCount());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyHeader)
+{
+// Given a document with 8 pages: a first page ending in a manual page 
break, then a multi-page
+// floating table on pages 2..8:
+createSwDoc("floattable-header.docx");
+CPPUNIT_ASSERT_EQUAL(8, getPages());
+
+// When creating a new paragraph at doc start:
+SwDocShell* pDocShell = getSwDocShell();
+SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+pWrtShell->SttEndDoc(/*bStt=*/true);
+pWrtShell->SplitNode();
+// Without the accompanying fix in place, this test would have crashed 
here.
+pWrtShell->CalcLayout();
+
+// Then make sure we get one more page, since the first page is now 2 
pages:
+CPPUNIT_ASSERT_EQUAL(9, getPages());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 8c49106364dc..43b633934156 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -1165,7 +1165,13 @@ bool SwTabFrame::Split(const SwTwips nCutPos, bool 
bTryToSplit,
 OSL_ENSURE( !GetIndPrev(), "Table is supposed to be at beginning" );
 if ( !IsInSct() )
 {
-m_pTable->SetRowsToRepeat(0);
+// This would mean the layout modifies the doc model, so 
RowsToRepeat drops to 0 while
+// there are existing row frames with RepeatedHeadline == true. 
Avoid this at least
+// inside split flys, it would lead to a crash in 
SwTabFrame::MakeAll().
+if (!pFly || !pFly->IsFlySplitAllowed())
+{
+m_pTable->SetRowsToRepeat(0);
+}
 return false;
 }
 else
@@ -6371,6 +6377,10 @@ void SwTabFrame::dumpAsXml(xmlTextWriterPtr writer) const
 {
 

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source writerfilter/source

2024-03-04 Thread Miklos Vajna (via logerrit)
 sw/qa/extras/rtfexport/data/listWithLgl.rtf |   23 +
 sw/qa/extras/rtfexport/rtfexport3.cxx   |   26 
 sw/source/filter/ww8/rtfattributeoutput.cxx |7 +-
 writerfilter/source/rtftok/rtfcontrolwords.cxx  |2 -
 writerfilter/source/rtftok/rtfdispatchvalue.cxx |3 ++
 5 files changed, 59 insertions(+), 2 deletions(-)

New commits:
commit ebfd17e47c1bdfd25090fe73495e4e729ac19564
Author: Miklos Vajna 
AuthorDate: Wed Feb 28 08:34:02 2024 +0100
Commit: Caolán McNamara 
CommitDate: Mon Mar 4 09:40:00 2024 +0100

Related: tdf#150408 RTF filter: handle legal numbering

The bugdoc's 2nd para started with 'Sect I.01', while Word rendered this
as 'Sect 1.01'.

The reason for this difference is that there is an "is legal" boolean
property on the numbering that we ignored from RTF during import/export.

Fix the problem by extending RTFDocumentImpl::dispatchTableSprmValue()
for the numbering table import + RtfAttributeOutput::NumberingLevel()
for the export.

The import default for this value was also wrong, given that the default
is to enable it when the control word is present.

(cherry picked from commit e8487bedb20a429565b4a0e4bd2d6806cc603b7f)

Conflicts:
sw/qa/extras/rtfexport/rtfexport3.cxx

Change-Id: I4dcd23768000ba29d4df314b475b412bb371545e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164327
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/extras/rtfexport/data/listWithLgl.rtf 
b/sw/qa/extras/rtfexport/data/listWithLgl.rtf
new file mode 100644
index ..4355049eb3dc
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/listWithLgl.rtf
@@ -0,0 +1,23 @@
+{ tf1
+{\*\listtable
+{\list\listtemplateid197063698
+{\listlevel\levelnfc1\levelnfcn1\leveljc0\leveljcn0\levelfollow2\levelstartat1\levelspace0\levelindent0
+{\leveltext\'04CH \'00;}
+{\levelnumbers\'04;}
+ tlchcs1 f0 \ltrchcs0 \s15i0\li0\lin0 }
+{\listlevel\levelnfc22\levelnfcn22\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0
+{\leveltext\'08Sect \'00.\'01;}
+{\levelnumbers
+\'06\'08;}
+ tlchcs1 f0 \ltrchcs0 \s16i720\li0\jclisttab   x2160\lin0 }
+\listid1297755732}
+}
+{\*\listoverridetable
+{\listoverride\listid1297755732\listoverridecount0\ls1}
+}
+\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440
+\pard\plain\ls1\par
+\pard\plaini720   x2160\ls1\ilvl1 Foo\par
+\pard\plain\ls1\par
+\pard\plaini720   x2160\ls1\ilvl1 Bar\par
+}
diff --git a/sw/qa/extras/rtfexport/rtfexport3.cxx 
b/sw/qa/extras/rtfexport/rtfexport3.cxx
index fd25e7e5758d..d7ab8fc1995e 100644
--- a/sw/qa/extras/rtfexport/rtfexport3.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport3.cxx
@@ -716,6 +716,32 @@ DECLARE_RTFEXPORT_TEST(testTdf158409, "tdf158409.rtf")
 CPPUNIT_ASSERT_EQUAL(8.0, getProperty(xRun, "CharHeight"));
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testLegalNumbering)
+{
+auto verify = [this]() {
+// Second level's numbering should use Arabic numbers for first level 
reference
+auto xPara = getParagraph(1);
+CPPUNIT_ASSERT_EQUAL(OUString("CH I"), getProperty(xPara, 
"ListLabelString"));
+xPara = getParagraph(2);
+// Without the accompanying fix in place, this test would have failed 
with:
+// - Expected: Sect 1.01
+// - Actual  : Sect I.01
+// i.e. \levellegal was ignored on import/export.
+CPPUNIT_ASSERT_EQUAL(OUString("Sect 1.01"),
+ getProperty(xPara, "ListLabelString"));
+xPara = getParagraph(3);
+CPPUNIT_ASSERT_EQUAL(OUString("CH II"), getProperty(xPara, 
"ListLabelString"));
+xPara = getParagraph(4);
+CPPUNIT_ASSERT_EQUAL(OUString("Sect 2.01"),
+ getProperty(xPara, "ListLabelString"));
+};
+
+createSwDoc("listWithLgl.rtf");
+verify();
+saveAndReload(mpFilter);
+verify();
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index de7140f091bc..26203291d6e5 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -1625,7 +1625,7 @@ void RtfAttributeOutput::NumberingLevel(sal_uInt8 nLevel, 
sal_uInt16 nStart,
 const wwFont* pFont, const SfxItemSet* 
pOutSet,
 sal_Int16 nIndentAt, sal_Int16 
nFirstLineIndex,
 sal_Int16 /*nListTabPos*/, const 
OUString& rNumberingString,
-const SvxBrushItem* pBrush, bool 
/*isLegal*/)
+const SvxBrushItem* pBrush, bool 
isLegal)
 {
 m_rExport.Strm().WriteOString(SAL_NEWLINE_STRING);
 if 

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-03-01 Thread Miklos Vajna (via logerrit)
 sw/qa/extras/ww8export/data/listWithLgl.doc |binary
 sw/qa/extras/ww8export/ww8export4.cxx   |   24 
 sw/source/filter/ww8/wrtw8num.cxx   |9 -
 sw/source/filter/ww8/ww8par3.cxx|   11 +++
 4 files changed, 43 insertions(+), 1 deletion(-)

New commits:
commit 36d9d58f6883d1616a6cc9a88485721bf127f2ff
Author: Miklos Vajna 
AuthorDate: Tue Feb 27 08:29:31 2024 +0100
Commit: Caolán McNamara 
CommitDate: Fri Mar 1 15:26:58 2024 +0100

Related: tdf#150408 DOC filter: handle legal numbering

The bugdoc's 2nd para started with 'Sect I.01', while Word rendered this
as 'Sect 1.01'.

The reason for this difference is that there is an "is legal" boolean
property on the numbering that we ignored from [MS-DOC] during
import/export.

Fix the problem by WW8ListManager::ReadLVL() and
WW8AttributeOutput::NumberingLevel() to handle this, building on top of
the existing DOCX work.

RTF still needs doing.

(cherry picked from commit a73b3994fb6a2cc10b2d65cbaad201762610cecc)

Change-Id: I57ec402c1dd829251afa639ddfa7fc6620da1125
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164214
Tested-by: Jenkins CollaboraOffice 
Tested-by: Caolán McNamara 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/extras/ww8export/data/listWithLgl.doc 
b/sw/qa/extras/ww8export/data/listWithLgl.doc
new file mode 100644
index ..94de2967febc
Binary files /dev/null and b/sw/qa/extras/ww8export/data/listWithLgl.doc differ
diff --git a/sw/qa/extras/ww8export/ww8export4.cxx 
b/sw/qa/extras/ww8export/ww8export4.cxx
index d47c934d9dd6..d31bf17a31f6 100644
--- a/sw/qa/extras/ww8export/ww8export4.cxx
+++ b/sw/qa/extras/ww8export/ww8export4.cxx
@@ -228,6 +228,30 @@ DECLARE_WW8EXPORT_TEST(testInlinePageBreakFirstLine, 
"inlinePageBreakFirstLine.d
 CPPUNIT_ASSERT(IsFirstLine(aTextNodes[2]));
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testLegalNumbering)
+{
+auto verify = [this]() {
+// Second level's numbering should use Arabic numbers for first level 
reference
+auto xPara = getParagraph(1);
+CPPUNIT_ASSERT_EQUAL(OUString("CH I"), getProperty(xPara, 
"ListLabelString"));
+xPara = getParagraph(2);
+// Without the accompanying fix in place, this test would have failed 
with:
+// - Expected: Sect 1.01
+// - Actual  : Sect I.01
+// i.e. fLegal was ignored on import/export.
+CPPUNIT_ASSERT_EQUAL(OUString("Sect 1.01"), 
getProperty(xPara, "ListLabelString"));
+xPara = getParagraph(3);
+CPPUNIT_ASSERT_EQUAL(OUString("CH II"), getProperty(xPara, 
"ListLabelString"));
+xPara = getParagraph(4);
+CPPUNIT_ASSERT_EQUAL(OUString("Sect 2.01"), 
getProperty(xPara, "ListLabelString"));
+};
+
+createSwDoc("listWithLgl.doc");
+verify();
+saveAndReload(mpFilter);
+verify();
+}
+
 DECLARE_WW8EXPORT_TEST(testNonInlinePageBreakFirstLine, 
"nonInlinePageBreakFirstLine.doc")
 {
 SwDoc* pDoc = getSwDoc();
diff --git a/sw/source/filter/ww8/wrtw8num.cxx 
b/sw/source/filter/ww8/wrtw8num.cxx
index 8d59434db652..681961a3770c 100644
--- a/sw/source/filter/ww8/wrtw8num.cxx
+++ b/sw/source/filter/ww8/wrtw8num.cxx
@@ -279,7 +279,7 @@ void WW8AttributeOutput::NumberingLevel( sal_uInt8 
/*nLevel*/,
 sal_Int16 nListTabPos,
 const OUString ,
 const SvxBrushItem* pBrush, //For i120928,to transfer graphic of bullet
-bool /*isLegal*/
+bool isLegal
 )
 {
 // Start value
@@ -303,6 +303,13 @@ void WW8AttributeOutput::NumberingLevel( sal_uInt8 
/*nLevel*/,
 nAlign = 0;
 break;
 }
+
+if (isLegal)
+{
+// 3rd bit.
+nAlign |= 0x04;
+}
+
 m_rWW8Export.m_pTableStrm->WriteUChar( nAlign );
 
 // Write the rgbxchNums[9], positions of placeholders for paragraph
diff --git a/sw/source/filter/ww8/ww8par3.cxx b/sw/source/filter/ww8/ww8par3.cxx
index d0a294b14450..41b203f92496 100644
--- a/sw/source/filter/ww8/ww8par3.cxx
+++ b/sw/source/filter/ww8/ww8par3.cxx
@@ -368,6 +368,8 @@ struct WW8LVL   // only THE entries, WE need!
 short   nDxaLeft1;  // first line indent
 
 sal_uInt8   nNFC;   // number format code
+/// Legal numbering: whether this level overrides the nfc of all inherited 
level numbers.
+bool fLegal;
 // Offset of fieldcodes in Num-X-String
 sal_uInt8   aOfsNumsXCH[WW8ListManager::nMaxLevel];
 sal_uInt8   nLenGrpprlChpx; // length, in bytes, of the LVL's grpprlChpx
@@ -662,7 +664,15 @@ bool WW8ListManager::ReadLVL(SwNumFormat& rNumFormat, 
std::unique_ptr(aLVL.nStartAt));
 rNumFormat.SetNumberingType( nType );
+rNumFormat.SetIsLegal(aLVL.fLegal);
 rNumFormat.SetNumAdjust( eAdj );
 
 if( style::NumberingType::CHAR_SPECIAL == nType )


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-03-01 Thread Miklos Vajna (via logerrit)
 sw/qa/core/layout/data/floattable-in-section.docx |binary
 sw/qa/core/layout/layact.cxx  |   22 ++
 sw/source/core/layout/layact.cxx  |6 +-
 3 files changed, 27 insertions(+), 1 deletion(-)

New commits:
commit 6360a32d4fec19ca84253559512e4f6739150c22
Author: Miklos Vajna 
AuthorDate: Fri Feb 23 09:12:17 2024 +0100
Commit: Caolán McNamara 
CommitDate: Fri Mar 1 10:40:11 2024 +0100

Related: tdf#158986 sw floattable: fix unexpected page break with sections

Regression from commit c303981cfd95ce1c3881366023d5495ae2edce97
(tdf#156724 sw: layout: fix tables not splitting due to footnotes
differently, 2023-08-24), the floating table in the DOCX version of the
bugdoc went from page 1 to page 2.

It seems what happens is that the first page has 2 section frames, and
we used to directly recalc the last lower of the first section frame,
which triggered a recalc of the second section frame, so the table moved
from page 2 to page 1 once the top of the second section frame was
reduced (so the table could fit on page 1). But this direct recalc was
removed because it caused problems for split tables and footnotes in
tdf#156724.

Fix the problem by conditionally restoring the OptCalc() call in
SwLayAction::FormatLayout(): only do it for the last lower of section
frames, which is enough for the DOCX version of tdf#158986, but it keeps
the old tdf#156724 use-case working (the layout of that bugdoc doesn't
modify with this change).

The RTF version of the bugdoc (which was the originally reported
problem) still needs more work, but that's hopefully not a layout
problem but an RTF import one.

(cherry picked from commit 397d72e582c725d162c7e0b819dc6c0bb62e42b0)

Change-Id: I1134ec3a27aec8ee871b535d81dedf9d27bd6bd5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164155
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Caolán McNamara 

diff --git a/sw/qa/core/layout/data/floattable-in-section.docx 
b/sw/qa/core/layout/data/floattable-in-section.docx
index a0e9090bcccf..9aab264867f0 100644
Binary files a/sw/qa/core/layout/data/floattable-in-section.docx and 
b/sw/qa/core/layout/data/floattable-in-section.docx differ
diff --git a/sw/qa/core/layout/layact.cxx b/sw/qa/core/layout/layact.cxx
index d432ae52b7c5..8923d6b0e89a 100644
--- a/sw/qa/core/layout/layact.cxx
+++ b/sw/qa/core/layout/layact.cxx
@@ -86,6 +86,28 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf157096)
 
 CPPUNIT_ASSERT_EQUAL(1, getPages());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyInSection)
+{
+// Given a document with multiple sections, the 2nd section on page 1 has 
a one-page floating
+// table:
+createSwDoc("floattable-in-section.docx");
+
+// When laying out that document:
+SwDoc* pDoc = getSwDoc();
+SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+
+// Then make sure the table is on page 1, not on page 2:
+auto pPage1 = pLayout->Lower()->DynCastPageFrame();
+CPPUNIT_ASSERT(pPage1);
+// Without the fix in place, it would have failed, the table was on page 
2, not on page 1.
+CPPUNIT_ASSERT(pPage1->GetSortedObjs());
+SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs();
+CPPUNIT_ASSERT_EQUAL(static_cast(1), rPage1Objs.size());
+auto pPage2 = pPage1->GetNext()->DynCastPageFrame();
+CPPUNIT_ASSERT(pPage2);
+CPPUNIT_ASSERT(!pPage2->GetSortedObjs());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index a705ef251176..06c3027bebc5 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -1433,7 +1433,11 @@ bool SwLayAction::FormatLayout( OutputDevice 
*pRenderContext, SwLayoutFrame *pLa
 PopFormatLayout();
 }
 }
-// else: don't calc content frames any more
+else if (pLay->IsSctFrame() && pLow->IsTextFrame() && pLow == 
pLay->GetLastLower())
+{
+// else: only calc the last text lower of sections
+pLow->OptCalc();
+}
 
 if ( IsAgain() )
 return false;


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-02-26 Thread Justin Luth (via logerrit)
 sw/qa/extras/ww8export/ww8export3.cxx |7 +++
 sw/source/filter/ww8/wrtw8esh.cxx |5 +++--
 2 files changed, 10 insertions(+), 2 deletions(-)

New commits:
commit 9b6754db7659e8b192c36c36807729d6c37cf340
Author: Justin Luth 
AuthorDate: Mon Feb 26 09:56:11 2024 -0500
Commit: Miklos Vajna 
CommitDate: Tue Feb 27 08:38:07 2024 +0100

related tdf#126533 doc export: don't lose "tiled" aspect of image fill.

This affects patterns as well as textures/images.

make CppunitTest_sw_ww8export3 
CPPUNIT_TEST_NAME=testTdf101826_xattrTextBoxFill

Change-Id: I2742a6f333fc6688b3570772a1dbc8371741f210
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163948
Tested-by: Jenkins
Reviewed-by: Justin Luth 
(cherry picked from commit 93b14c1ba3afaf0a734ee5112444f0adbb35c428)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163970
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Miklos Vajna 

diff --git a/sw/qa/extras/ww8export/ww8export3.cxx 
b/sw/qa/extras/ww8export/ww8export3.cxx
index 97ea979d01e8..66c5ae5c471c 100644
--- a/sw/qa/extras/ww8export/ww8export3.cxx
+++ b/sw/qa/extras/ww8export/ww8export3.cxx
@@ -11,6 +11,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -621,6 +622,12 @@ DECLARE_WW8EXPORT_TEST(testTdf101826_xattrTextBoxFill, 
"tdf101826_xattrTextBoxFi
 CPPUNIT_ASSERT_MESSAGE("background color", Color(0xFF, 0xFF, 0x00) != 
getProperty(getShape(4), "BackColor"));
 //Basic Picture Fill: Tux image
 CPPUNIT_ASSERT_EQUAL_MESSAGE("background image", 
drawing::FillStyle_BITMAP, getProperty(getShape(5), 
"FillStyle"));
+// Basic Pattern fill: many thin, green, vertical stripes on yellow 
background
+auto eMode = getProperty(getShapeByName(u"Frame2"), 
"FillBitmapMode");
+CPPUNIT_ASSERT_EQUAL_MESSAGE("tiled pattern", drawing::BitmapMode_REPEAT, 
eMode);
+// Basic Texture fill: tiled blue denim texture
+eMode = getProperty(getShapeByName(u"Frame6"), 
"FillBitmapMode");
+CPPUNIT_ASSERT_EQUAL_MESSAGE("tiled texture", drawing::BitmapMode_REPEAT, 
eMode);
 }
 
 DECLARE_WW8EXPORT_TEST(testTdf123433_fillStyleStop, 
"tdf123433_fillStyleStop.doc")
diff --git a/sw/source/filter/ww8/wrtw8esh.cxx 
b/sw/source/filter/ww8/wrtw8esh.cxx
index 19ac50ccf5c9..f9e1082f9276 100644
--- a/sw/source/filter/ww8/wrtw8esh.cxx
+++ b/sw/source/filter/ww8/wrtw8esh.cxx
@@ -1849,8 +1849,9 @@ void SwBasicEscherEx::WriteBrushAttr(const SvxBrushItem 
,
 nOpaque = 255 - pGraphicObject->GetAttr().GetAlpha();
 if (0 != nOpaque)
 bSetOpacity = true;
-
-rPropOpt.AddOpt( ESCHER_Prop_fillType, ESCHER_FillPicture );
+const ESCHER_FillStyle eFillType
+= rBrush.GetGraphicPos() == GPOS_TILED ? ESCHER_FillTexture : 
ESCHER_FillPicture;
+rPropOpt.AddOpt(ESCHER_Prop_fillType, eFillType);
 rPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
 rPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 );
 }


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source writerfilter/source

2024-02-26 Thread Justin Luth (via logerrit)
 sw/qa/extras/rtfexport/data/tdf159824_gradientAngle1.rtf |   17 
 sw/qa/extras/rtfexport/data/tdf159824_gradientAngle2.rtf |   17 
 sw/qa/extras/rtfexport/rtfexport8.cxx|   57 +--
 sw/source/filter/ww8/rtfattributeoutput.cxx  |9 ++
 writerfilter/source/rtftok/rtfsdrimport.cxx  |4 +
 5 files changed, 97 insertions(+), 7 deletions(-)

New commits:
commit 64398a41f7d4110b58f0496f1237a6778772b05c
Author: Justin Luth 
AuthorDate: Wed Feb 21 16:37:31 2024 -0500
Commit: Miklos Vajna 
CommitDate: Mon Feb 26 09:06:28 2024 +0100

related tdf#159824 RTF import/export gradient angle

The fillAngle is important for obvious visual reasons,
but also significantly because a negative angle
means that the start/end colors should be swapped
(which is the normal case since
LO's 0 degree angle == -180 VML/RTF angle).

There were no existing unit tests with a "fillAngle" specified,
or with a non-180 angle (0 VML/RTF angle) in LO.

make CppunitTest_sw_rtfexport8 \
CPPUNIT_TEST_NAME=testTdf159824_gradientAngle1
make CppunitTest_sw_rtfexport8 \
CPPUNIT_TEST_NAME=testTdf159824_gradientAngle2
make CppunitTest_sw_rtfexport8 \
CPPUNIT_TEST_NAME=testTdf159824_axialGradient

Change-Id: I4bb2c47bd2a79833d11bedac72ba2152b65b7c73
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163714
Tested-by: Jenkins
Reviewed-by: Justin Luth 
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163870
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Miklos Vajna 

diff --git a/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle1.rtf 
b/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle1.rtf
new file mode 100644
index ..37fd8ae2e339
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle1.rtf
@@ -0,0 +1,17 @@
+{ tf1nsi\deff3deflang1025
+
+\landscape\paperh5940\paperw8391
+
+{
+\shp{\*\shpinst\shptop382\shpbottom2737\shpleft759\shpright5064
+{\sp{\sn shapeType}{\sv 202}}
+{\sp{\sn fillType}{\sv 7}}
+{\sp{\sn fillAngle}{\sv 6}}
+{\sp{\sn fillFocus}{\sv 0}}
+{\sp{\sn fillColor}{\sv 1758337}}
+{\sp{\sn fillBackColor}{\sv 16777215}}
+
+{\shptxt\par \pard}}
+}
+
+\par }
diff --git a/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle2.rtf 
b/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle2.rtf
new file mode 100644
index ..223864f3281b
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle2.rtf
@@ -0,0 +1,17 @@
+{ tf1nsi\deff3deflang1025
+
+\landscape\paperh5940\paperw8391
+
+{
+\shp{\*\shpinst\shptop382\shpbottom2737\shpleft759\shpright5064
+{\sp{\sn shapeType}{\sv 202}}
+{\sp{\sn fillType}{\sv 7}}
+{\sp{\sn fillAngle}{\sv -12}}
+{\sp{\sn fillFocus}{\sv 0}}
+{\sp{\sn fillColor}{\sv 1758337}}
+{\sp{\sn fillBackColor}{\sv 16777215}}
+
+{\shptxt\par \pard}}
+}
+
+\par }
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index ab787919dfa9..c0b8cbad9a0a 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -195,8 +195,8 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf159824_axialGradient)
  getProperty(xFrame, "FillStyle"));
 awt::Gradient2 aGradient = getProperty(xFrame, 
"FillGradient");
 
-//const Color aColA(0x127622); // green
-//const Color aColB(0xff); // white
+const Color aColA(0x127622); // green
+const Color aColB(0xff); // white
 
 // MCGR: Use the completely imported transparency gradient to check for 
correctness
 basegfx::BColorStops aColorStops = 
model::gradient::getColorStopsFromUno(aGradient.ColorStops);
@@ -205,11 +205,54 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf159824_axialGradient)
 CPPUNIT_ASSERT_EQUAL(size_t(3), aColorStops.size());
 CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_LINEAR, aGradient.Style);
 CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[0].getStopOffset(), 
0.0));
-//CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[0].getStopColor()));
-// CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[1].getStopOffset(), 
0.5));
-// CPPUNIT_ASSERT_EQUAL(aColA, Color(aColorStops[1].getStopColor()));
-// CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[2].getStopOffset(), 
1.0));
-// CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[2].getStopColor()));
+CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[0].getStopColor()));
+CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[1].getStopOffset(), 
0.5));
+CPPUNIT_ASSERT_EQUAL(aColA, Color(aColorStops[1].getStopColor()));
+CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[2].getStopOffset(), 
1.0));
+CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[2].getStopColor()));
+}
+
+DECLARE_RTFEXPORT_TEST(testTdf159824_gradientAngle1, 
"tdf159824_gradientAngle1.rtf")
+{
+// given a frame with a white (top) to lime (bottom) linear gradient at an 
RTF 1° angle
+

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-02-26 Thread Justin Luth (via logerrit)
 sw/qa/extras/rtfexport/data/tdf159824_axialGradient.odt |binary
 sw/qa/extras/rtfexport/rtfexport8.cxx   |   34 
 sw/source/filter/ww8/rtfattributeoutput.cxx |6 ++
 3 files changed, 40 insertions(+)

New commits:
commit ffaf75303273c3803cce58f887b5fb8bd570ff18
Author: Justin Luth 
AuthorDate: Wed Feb 21 11:52:36 2024 -0500
Commit: Miklos Vajna 
CommitDate: Mon Feb 26 09:03:14 2024 +0100

tdf#159824 MCGR rtf export: don't lose gradient's axial-ness

This fixes alg's 7.6 regression from
commit bb198176684c3d9377e26c04a29ec66deb811949

Found when trying to import these strung-out-linears
as real axials.

make CppunitTest_sw_rtfexport8 \
CPPUNIT_TEST_NAME=testTdf159824_axialGradient

Change-Id: I220f1bf689b4b219bc0ae187e95aedb1a29a7233
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163705
Tested-by: Jenkins
Reviewed-by: Justin Luth 
Reviewed-by: Miklos Vajna 
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163869
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/extras/rtfexport/data/tdf159824_axialGradient.odt 
b/sw/qa/extras/rtfexport/data/tdf159824_axialGradient.odt
new file mode 100644
index ..c1ce5cd31d2a
Binary files /dev/null and 
b/sw/qa/extras/rtfexport/data/tdf159824_axialGradient.odt differ
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index c78298c0..ab787919dfa9 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -10,6 +10,8 @@
 #include 
 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -21,7 +23,9 @@
 #include 
 #include 
 
+#include 
 #include 
+#include 
 #include 
 #include 
 
@@ -178,6 +182,36 @@ DECLARE_RTFEXPORT_TEST(testTdf158826_extraCR, 
"tdf158826_extraCR.rtf")
 uno::Reference xTable(getParagraphOrTable(1), 
uno::UNO_QUERY_THROW);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf159824_axialGradient)
+{
+// given a frame with an axial gradient (white - green - white)
+loadAndReload("tdf159824_axialGradient.odt");
+
+uno::Reference xTextFramesSupplier(mxComponent, 
uno::UNO_QUERY);
+uno::Reference 
xIndexAccess(xTextFramesSupplier->getTextFrames(),
+ uno::UNO_QUERY);
+uno::Reference xFrame(xIndexAccess->getByIndex(0), 
uno::UNO_QUERY);
+CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT,
+ getProperty(xFrame, "FillStyle"));
+awt::Gradient2 aGradient = getProperty(xFrame, 
"FillGradient");
+
+//const Color aColA(0x127622); // green
+//const Color aColB(0xff); // white
+
+// MCGR: Use the completely imported transparency gradient to check for 
correctness
+basegfx::BColorStops aColorStops = 
model::gradient::getColorStopsFromUno(aGradient.ColorStops);
+
+// expected: a 3-color linear gradient (or better yet a 2-color AXIAL 
gradient)
+CPPUNIT_ASSERT_EQUAL(size_t(3), aColorStops.size());
+CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_LINEAR, aGradient.Style);
+CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[0].getStopOffset(), 
0.0));
+//CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[0].getStopColor()));
+// CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[1].getStopOffset(), 
0.5));
+// CPPUNIT_ASSERT_EQUAL(aColA, Color(aColorStops[1].getStopColor()));
+// CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[2].getStopOffset(), 
1.0));
+// CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[2].getStopColor()));
+}
+
 DECLARE_RTFEXPORT_TEST(testTdf158830, "tdf158830.rtf")
 {
 //check centered text in table
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 2d68556e8a23..05e1cbc2cd22 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -3747,6 +3747,12 @@ void RtfAttributeOutput::FormatFillGradient(const 
XFillGradientItem& rFillGradie
 const Color aEndColor(rColorStops.back().getStopColor());
 m_aFlyProperties.push_back(std::make_pair(
 "fillBackColor"_ostr, 
OString::number(wwUtility::RGBToBGR(aEndColor;
+
+if (rGradient.GetGradientStyle() == awt::GradientStyle_AXIAL)
+{
+m_aFlyProperties.push_back(
+std::make_pair("fillFocus"_ostr, 
OString::number(50)));
+}
 }
 else
 {


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-02-26 Thread Justin Luth (via logerrit)
 sw/qa/extras/ooxmlexport/ooxmlexport7.cxx|3 --
 sw/source/filter/ww8/docxattributeoutput.cxx |   32 +--
 2 files changed, 25 insertions(+), 10 deletions(-)

New commits:
commit 8881c7935e79290fedfed812715605d17dde9d22
Author: Justin Luth 
AuthorDate: Tue Feb 20 22:41:22 2024 -0500
Commit: Miklos Vajna 
CommitDate: Mon Feb 26 09:00:52 2024 +0100

related tdf#126533 vml export: fix axial colors

This is a follow-up from the earlier tdf#65295 clone
which removed swapping colors on IMport for axials.
Well, tdf#65295 had also removed EXport swap for the linear case,
so, now that import doesn't swap, remove the axial export swap too.

Additionally, some linear gradients are actually axials,
so identify those symmetrical gradients that have
identical start/end colors to avoid exporting as a "solid" color.

[I tried changing the import to detect it was an axial,
 but got RTF export failures, chart2 false positives,
 and unit-test-the-implementation failures.]

make CppunitTest_sw_ooxmlexport7 \
CPPUNIT_TEST_NAME=testTdf126533_negativeAxialAngle

The only other unit test that hit this code was
textframe-gradient.docx - which is dominated by DML import/export.
I can see with Word 2003 that this patch fixes the VML export
for this unit test file also.

Change-Id: I75e993c7c127a861617b14072a98778ddde03a08
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163676
Tested-by: Justin Luth 
Reviewed-by: Justin Luth 
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163868
Tested-by: Jenkins CollaboraOffice 
Reviewed-by: Miklos Vajna 

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
index ef4bcb2d..a362cb36c221 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport7.cxx
@@ -642,9 +642,6 @@ DECLARE_OOXMLEXPORT_TEST(testTdf77219_backgroundShape, 
"tdf77219_backgroundShape
 
 DECLARE_OOXMLEXPORT_TEST(testTdf126533_negativeAxialAngle, 
"tdf126533_negativeAxialAngle.docx")
 {
-if (isExported())
-return;
-
 // axiel gradient is purple foreground/lime background in the middle 
(top-left to bottom-right)
 uno::Reference 
xPageStyle(getStyles("PageStyles")->getByName("Standard"),
uno::UNO_QUERY);
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index c04a86ab4e55..334e521aba04 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -9653,16 +9653,34 @@ void DocxAttributeOutput::FormatFillGradient( const 
XFillGradientItem& rFillGrad
 switch (rGradient.GetGradientStyle())
 {
 case css::awt::GradientStyle_AXIAL:
-AddToAttrList(m_rExport.SdrExporter().getFlyFillAttrList(), 
XML_type, "gradient");
-AddToAttrList( m_rExport.SdrExporter().getFlyFillAttrList(), 
XML_focus, "50%" );
-// If it is an 'axial' gradient - swap the colors
-// (because in the import process they were imported swapped)
-sColor1 = sEndColor;
-sColor2 = sStartColor;
-break;
 case css::awt::GradientStyle_LINEAR:
+{
+bool bIsSymmetrical = rGradient.GetGradientStyle() == 
css::awt::GradientStyle_AXIAL;
+if (!bIsSymmetrical)
+{
+const basegfx::BColorStops& rColorStops = 
rGradient.GetColorStops();
+if (rColorStops.size() > 2 && rColorStops.isSymmetrical())
+{
+for (auto& rStop : rColorStops)
+{
+if (basegfx::fTools::less(rStop.getStopOffset(), 
0.5))
+continue;
+if (basegfx::fTools::more(rStop.getStopOffset(), 
0.5))
+break;
+
+// the color in the middle is considered the start 
color for focus 50
+sColor1 = 
msfilter::util::ConvertColor(Color(rStop.getStopColor()));
+bIsSymmetrical = true;
+}
+}
+}
+
+if (bIsSymmetrical)
+AddToAttrList( 
m_rExport.SdrExporter().getFlyFillAttrList(), XML_focus, "50%" );
+
 AddToAttrList(m_rExport.SdrExporter().getFlyFillAttrList(), 
XML_type, "gradient");
 break;
+}
 case css::awt::GradientStyle_RADIAL:
 case css::awt::GradientStyle_ELLIPTICAL:
 case css::awt::GradientStyle_SQUARE:


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-02-25 Thread Justin Luth (via logerrit)
 sw/qa/extras/ooxmlexport/ooxmlexport21.cxx   |4 
 sw/source/filter/ww8/docxattributeoutput.cxx |   18 +++---
 2 files changed, 15 insertions(+), 7 deletions(-)

New commits:
commit 7ee5904a12b55eb3abbdf5d0d46f57ffdb7158c7
Author: Justin Luth 
AuthorDate: Wed Feb 14 10:48:08 2024 -0500
Commit: Miklos Vajna 
CommitDate: Mon Feb 26 08:59:03 2024 +0100

related tdf#126533 DOCX: vml export gradientRadial instead of gradient

... for everything except the linear gradients (linear/axial)

Interestingly, there was nothing in make sw.check that hit this.

make CppunitTest_sw_ooxmlexport21 \
CPPUNIT_TEST_NAME=testTdf126533_pageGradient

Change-Id: Id58ed8b312ec29a10ce461ff0e032838b745b11b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163470
Reviewed-by: Justin Luth 
Tested-by: Jenkins
Reviewed-by: Miklos Vajna 
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163867
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
index b9b04eafb0f1..fcdd26b22924 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
@@ -9,6 +9,7 @@
 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -80,6 +81,9 @@ DECLARE_OOXMLEXPORT_TEST(testTdf126533_pageGradient, 
"fill.docx")
uno::UNO_QUERY);
 CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT,
  getProperty(xPageStyle, 
"FillStyle"));
+
+awt::Gradient2 aGradient = getProperty(xPageStyle, 
"FillGradient");
+CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_RECT, aGradient.Style);
 }
 
 DECLARE_OOXMLEXPORT_TEST(testTdf126533_pageBitmap, "tdf126533_pageBitmap.docx")
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 03ada68bcb2d..c04a86ab4e55 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -9632,8 +9632,6 @@ void DocxAttributeOutput::FormatFillGradient( const 
XFillGradientItem& rFillGrad
 {
 if (m_oFillStyle && *m_oFillStyle == drawing::FillStyle_GRADIENT && 
!m_rExport.SdrExporter().getDMLTextFrameSyntax())
 {
-AddToAttrList( m_rExport.SdrExporter().getFlyFillAttrList(), XML_type, 
"gradient" );
-
 const basegfx::BGradient& rGradient = rFillGradient.GetGradientValue();
 OString sStartColor = 
msfilter::util::ConvertColor(Color(rGradient.GetColorStops().front().getStopColor()));
 OString sEndColor = 
msfilter::util::ConvertColor(Color(rGradient.GetColorStops().back().getStopColor()));
@@ -9655,17 +9653,23 @@ void DocxAttributeOutput::FormatFillGradient( const 
XFillGradientItem& rFillGrad
 switch (rGradient.GetGradientStyle())
 {
 case css::awt::GradientStyle_AXIAL:
+AddToAttrList(m_rExport.SdrExporter().getFlyFillAttrList(), 
XML_type, "gradient");
 AddToAttrList( m_rExport.SdrExporter().getFlyFillAttrList(), 
XML_focus, "50%" );
 // If it is an 'axial' gradient - swap the colors
 // (because in the import process they were imported swapped)
 sColor1 = sEndColor;
 sColor2 = sStartColor;
 break;
-case css::awt::GradientStyle_LINEAR: break;
-case css::awt::GradientStyle_RADIAL: break;
-case css::awt::GradientStyle_ELLIPTICAL: break;
-case css::awt::GradientStyle_SQUARE: break;
-case css::awt::GradientStyle_RECT: break;
+case css::awt::GradientStyle_LINEAR:
+AddToAttrList(m_rExport.SdrExporter().getFlyFillAttrList(), 
XML_type, "gradient");
+break;
+case css::awt::GradientStyle_RADIAL:
+case css::awt::GradientStyle_ELLIPTICAL:
+case css::awt::GradientStyle_SQUARE:
+case css::awt::GradientStyle_RECT:
+AddToAttrList(m_rExport.SdrExporter().getFlyFillAttrList(), 
XML_type,
+  "gradientRadial");
+break;
 default:
 break;
 }


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-02-25 Thread Justin Luth (via logerrit)
 sw/qa/extras/ooxmlexport/ooxmlexport21.cxx |3 +--
 sw/source/filter/ww8/docxexport.cxx|   21 +
 2 files changed, 22 insertions(+), 2 deletions(-)

New commits:
commit aca1125350e68d94906074fc075b079d4460ae7f
Author: Justin Luth 
AuthorDate: Tue Feb 13 13:58:08 2024 -0500
Commit: Miklos Vajna 
CommitDate: Mon Feb 26 08:55:59 2024 +0100

tdf#126533 DOCX: export page vml fill gradient

Simplistic export of gradient fill.

I just used the existing docxattribute stuff that textboxes
use to export their background as VML fallback.

Note that docxattribute only knows how to export gradient,
not gradientRadial. (Done in follow-up patch.)

Lots of stuff is missing in terms of properly supporting gradients.
But likely fixing page background will fix
the same problem in textboxes etc.

Given how incredibly different LO and MSO are in terms of gradients,
it makes sense to commit this change and at least get the basics
wired in.

make CppunitTest_sw_ooxmlexport21 \
CPPUNIT_TEST_NAME=testTdf126533_pageGradient

Change-Id: I2ac14fdef2fe29609bc8d5a5d8f65b3f0da71889
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163469
Reviewed-by: Justin Luth 
Tested-by: Jenkins
Reviewed-by: Miklos Vajna 
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163866
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
index d4bc37d5f700..b9b04eafb0f1 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
@@ -73,10 +73,9 @@ DECLARE_OOXMLEXPORT_TEST(testTdf126533_noPageBitmap, 
"tdf126533_noPageBitmap.doc
  getProperty(xPageStyle, 
"FillStyle"));
 }
 
-CPPUNIT_TEST_FIXTURE(Test, testTdf126533_pageGradient)
+DECLARE_OOXMLEXPORT_TEST(testTdf126533_pageGradient, "fill.docx")
 {
 // given a document with a gradient page background
-loadFromFile(u"fill.docx");
 uno::Reference 
xPageStyle(getStyles("PageStyles")->getByName("Standard"),
uno::UNO_QUERY);
 CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT,
diff --git a/sw/source/filter/ww8/docxexport.cxx 
b/sw/source/filter/ww8/docxexport.cxx
index a4c06ab5ac5b..e84bbc48eb20 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -55,6 +55,7 @@
 #include 
 
 #include 
+#include 
 #include 
 
 #include 
@@ -1916,6 +1917,7 @@ void DocxExport::WriteMainText()
   
msfilter::util::ConvertColor(oBrush->GetColor()));
 
 const SwAttrSet& rPageStyleAttrSet = 
m_rDoc.GetPageDesc(0).GetMaster().GetAttrSet();
+const drawing::FillStyle eFillType = 
rPageStyleAttrSet.Get(XATTR_FILLSTYLE).GetValue();
 const GraphicObject* pGraphicObj = oBrush->GetGraphicObject();
 if (pGraphicObj) // image/pattern/texture
 {
@@ -1934,6 +1936,25 @@ void DocxExport::WriteMainText()
 m_pDocumentFS->endElementNS(XML_v, XML_background);
 }
 }
+else if (eFillType == drawing::FillStyle_GRADIENT)
+{
+SfxItemSetFixed 
aSet(m_rDoc.GetAttrPool());
+aSet.Set(rPageStyleAttrSet);
+
+// Collect all of the gradient attributes into SdrExporter() 
AttrLists
+m_pAttrOutput->OutputStyleItemSet(aSet, /*TestForDefault=*/true);
+assert(SdrExporter().getFlyAttrList().is() && "type and fillcolor 
are always provided");
+assert(SdrExporter().getFlyFillAttrList().is() && "color2 is 
always provided");
+
+rtl::Reference 
xFlyAttrList(SdrExporter().getFlyAttrList());
+rtl::Reference 
xFillAttrList(SdrExporter().getFlyFillAttrList());
+m_pDocumentFS->startElementNS(XML_v, XML_background, xFlyAttrList);
+m_pDocumentFS->singleElementNS(XML_v, XML_fill, xFillAttrList);
+m_pDocumentFS->endElementNS(XML_v, XML_background);
+
+SdrExporter().getFlyAttrList().clear();
+SdrExporter().getFlyFillAttrList().clear();
+}
 
 m_pDocumentFS->endElementNS(XML_w, XML_background);
 }


core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-02-25 Thread Justin Luth (via logerrit)
 sw/qa/extras/ooxmlexport/data/tdf126533_pageBitmap.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlexport21.cxx  |   16 +++
 sw/source/filter/ww8/docxexport.cxx |   22 +---
 sw/source/filter/ww8/rtfexport.cxx  |3 +-
 sw/source/filter/ww8/wrtww8.cxx |2 -
 5 files changed, 37 insertions(+), 6 deletions(-)

New commits:
commit 9e623d8d0a1896e679a48b84459dc3b316636aba
Author: Justin Luth 
AuthorDate: Fri Feb 9 15:43:32 2024 -0500
Commit: Miklos Vajna 
CommitDate: Mon Feb 26 08:42:51 2024 +0100

tdf#126533 docx export: page background vml fill: basic image

This is the absolute minimal possible combination
to export an image to page background.

However, none of the other properties
that I see strike me as particularly important
or connected to our image properties.

Plus MSO ignores things like "frame" and tiles anyway.

Import is also pretty basic, so any improvement to imports
can also add the corresponding export component.

For example: it seems like MSO tiles all images
based on somewhat magical sizing (they do always export
o:targetscreensize="999,999" which we ignore).
But note that MSO does pixel display and not logical display
for page background - something we do NOT want to emulate,
so any importing of properties needs to be done intelligently.

But MSO's UI only allows for basic image insertion,
so very few files will have complex settings.

make CppunitTest_sw_ooxmlexport21 \
CPPUNIT_TEST_NAME=testTdf126533_pageBitmap

Change-Id: Ib410594d1e3377aefb8ee94f209a1a1155154b17
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163203
Tested-by: Jenkins
Reviewed-by: Justin Luth 
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163862
Tested-by: Jenkins CollaboraOffice 

diff --git a/sw/qa/extras/ooxmlexport/data/tdf126533_pageBitmap.docx 
b/sw/qa/extras/ooxmlexport/data/tdf126533_pageBitmap.docx
new file mode 100644
index ..67131acd2fd8
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/tdf126533_pageBitmap.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
index ca0cc5438ee6..d4bc37d5f700 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport21.cxx
@@ -83,6 +83,22 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf126533_pageGradient)
  getProperty(xPageStyle, 
"FillStyle"));
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf126533_pageBitmap, "tdf126533_pageBitmap.docx")
+{
+// given a document with a page background image
+uno::Reference 
xPageStyle(getStyles("PageStyles")->getByName("Standard"),
+   uno::UNO_QUERY);
+CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_BITMAP,
+ getProperty(xPageStyle, 
"FillStyle"));
+
+if (!isExported())
+return;
+
+xmlDocUniquePtr pXmlDocRels = parseExport("word/_rels/document.xml.rels");
+assertXPath(pXmlDocRels,
+
"/rels:Relationships/rels:Relationship[@Target='media/image1.jpeg']"_ostr, 1);
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/filter/ww8/docxexport.cxx 
b/sw/source/filter/ww8/docxexport.cxx
index e7c1972ce9c0..46e66a4a42a0 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -1911,11 +1911,25 @@ void DocxExport::WriteMainText()
 // Write background page color
 if (std::unique_ptr oBrush = getBackground(); oBrush)
 {
-Color backgroundColor = oBrush->GetColor();
-OString aBackgroundColorStr = 
msfilter::util::ConvertColor(backgroundColor);
+m_pDocumentFS->startElementNS(XML_w, XML_background, FSNS(XML_w, 
XML_color),
+  
msfilter::util::ConvertColor(oBrush->GetColor()));
 
-m_pDocumentFS->singleElementNS(XML_w, XML_background, FSNS(XML_w, 
XML_color),
-   aBackgroundColorStr);
+const GraphicObject* pGraphicObj = oBrush->GetGraphicObject();
+if (pGraphicObj) // image/pattern/texture
+{
+const OUString aRelId = 
m_pDrawingML->writeGraphicToStorage(pGraphicObj->GetGraphic());
+if (!aRelId.isEmpty())
+{
+m_pDocumentFS->startElementNS(XML_v, XML_background);
+
+m_pDocumentFS->singleElementNS(XML_v, XML_fill, FSNS(XML_r, 
XML_id), aRelId,
+XML_type, "frame");
+
+m_pDocumentFS->endElementNS(XML_v, XML_background);
+}
+}
+
+m_pDocumentFS->endElementNS(XML_w, XML_background);
 }
 
 // body
diff --git a/sw/source/filter/ww8/rtfexport.cxx 
b/sw/source/filter/ww8/rtfexport.cxx
index 

core.git: Branch 'distro/collabora/co-24.04' - sw/qa sw/source

2024-01-31 Thread Miklos Vajna (via logerrit)
 sw/qa/core/text/itrform2.cxx |   40 +++
 sw/source/core/text/itrform2.cxx |9 ++--
 2 files changed, 47 insertions(+), 2 deletions(-)

New commits:
commit 03f8e1c7549a3909fa64f9cd9dfc4cc4c8cc6124
Author: Miklos Vajna 
AuthorDate: Tue Jan 30 16:51:49 2024 +0100
Commit: Miklos Vajna 
CommitDate: Wed Jan 31 09:32:46 2024 +0100

tdf#159452 sw content control, PDF export: fix checked checkboxes

Regression from commit 9bad5be0ffdcdee92d40162b598ed2ab2815e5d5 (sw
content controls, checkbox: add PDF export, 2022-09-13), we used to
export checkbox content controls as plain text, but once checkbox
content controls are exported as forms, the state of the checkboxes are
lost.

Writer content control checkboxes support custom values for the checked
and unchecked states, but the PDF export does not. On one hand,
PDFWriterImpl::createDefaultCheckBoxAppearance() assumes that the
checked state should be a checkmark, not the Writer default 'BALLOT BOX
WITH X' (U+2612). On the other hand, the PDF spec section 12.7.4.2.3
"Check Boxes" says that the checked state should be "Yes", which
explains why our checked state is not recognized by PDF readers.

Fix the problem by making the export of checked/unchecked states
conditional in SwContentControlPortion::DescribePDFControl(): the
checked state then shows up as expected.

Leave the unchecked case unchanged, the current markup there doesn't
cause problems.

(cherry picked from commit 256e2c679bcbb3ea446884d0ff4e3f8687b82ede)

Change-Id: I9063d8607c8cccfa080921af38b3cbfe40905115

diff --git a/sw/qa/core/text/itrform2.cxx b/sw/qa/core/text/itrform2.cxx
index fc8e981dcf5f..6d59140f97f0 100644
--- a/sw/qa/core/text/itrform2.cxx
+++ b/sw/qa/core/text/itrform2.cxx
@@ -16,6 +16,10 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
 namespace
 {
@@ -166,6 +170,42 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyAnchorLeftMargin)
 // i.e. the left margin was lost.
 CPPUNIT_ASSERT_EQUAL(static_cast(6480), 
pLastPara->getFramePrintArea().Left());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testCheckedCheckboxContentControlPDF)
+{
+std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get();
+if (!pPDFium)
+return;
+
+// Given a file with a checked checkbox content control:
+createSwDoc();
+SwDoc* pDoc = getSwDoc();
+SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);
+// Toggle it, so we get a checked one:
+SwTextContentControl* pTextContentControl = 
pWrtShell->CursorInsideContentControl();
+const SwFormatContentControl& rFormatContentControl = 
pTextContentControl->GetContentControl();
+pWrtShell->GotoContentControl(rFormatContentControl);
+
+// When exporting to PDF:
+save("writer_pdf_Export");
+
+// Then make sure that a checked checkbox form widget is emitted:
+std::unique_ptr pPdfDocument = parsePDFExport();
+std::unique_ptr pPage = pPdfDocument->openPage(0);
+CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
+std::unique_ptr pAnnotation = 
pPage->getAnnotation(0);
+CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, 
pAnnotation->getSubType());
+CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::CheckBox,
+ pAnnotation->getFormFieldType(pPdfDocument.get()));
+OUString aActual = pAnnotation->getFormFieldValue(pPdfDocument.get());
+// Without the accompanying fix in place, this test would have failed with:
+// - Expected: Yes
+// - Actual  : Off
+// i.e. the /AP -> /N key of the checkbox widget annotation object didn't 
have a sub-key that
+// would match /V, leading to not showing the checked state.
+CPPUNIT_ASSERT_EQUAL(OUString("Yes"), aActual);
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index f38bba2ef751..6623000c335f 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -1018,8 +1018,13 @@ bool SwContentControlPortion::DescribePDFControl(const 
SwTextPaintInfo& rInf) co
 pDescriptor = std::make_unique();
 auto pCheckBoxWidget = 
static_cast(pDescriptor.get());
 pCheckBoxWidget->Checked = pContentControl->GetChecked();
-pCheckBoxWidget->OnValue = pContentControl->GetCheckedState();
-pCheckBoxWidget->OffValue = pContentControl->GetUncheckedState();
+// If it's checked already, then leave the default "Yes" OnValue 
unchanged, so the
+// appropriate appearance is found by PDF readers.
+if (!pCheckBoxWidget->Checked)
+{
+pCheckBoxWidget->OnValue = pContentControl->GetCheckedState();
+pCheckBoxWidget->OffValue =