Rebased ref, commits from common ancestor:
commit fc02d828a25af509e1791093f1700f3b3310da1e
Author: Dennis Francis <[email protected]>
AuthorDate: Mon Feb 9 22:54:55 2026 +0530
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:07 2026 +0100
lok: sw: chart wizard updates the chart only...
... if the chart is activated like it is done in the desktop version.
Note: Chart wizard never worked properly after jsdialog migration.
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: Ic569424b12323283105320fa62037f337b848847
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199066
Reviewed-by: Miklos Vajna <[email protected]>
Tested-by: Jenkins CollaboraOffice <[email protected]>
(cherry picked from commit eeb5f37e264c9f9a93fd3b99d58a09f67d217577)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199139
diff --git a/sw/source/uibase/table/tablemgr.cxx
b/sw/source/uibase/table/tablemgr.cxx
index cebeb659987d..f7a7ab13f97a 100644
--- a/sw/source/uibase/table/tablemgr.cxx
+++ b/sw/source/uibase/table/tablemgr.cxx
@@ -230,10 +230,9 @@ uno::Reference< frame::XModel > SwTableFUNC::InsertChart(
}
m_pSh->EndAllAction();
- if (xObj.is() && !comphelper::LibreOfficeKit::isActive())
+ if (xObj.is())
{
- // Let the chart be activated after the inserting (unless
- // via LibreOfficeKit)
+ // Let the chart be activated after the inserting
SfxInPlaceClient* pClient = m_pSh->GetView().FindIPClient( xObj,
&m_pSh->GetView().GetEditWin() );
if ( !pClient )
{
commit fca4420f4480be536f593c85a891361c8607e52d
Author: Dennis Francis <[email protected]>
AuthorDate: Mon Feb 9 22:52:36 2026 +0530
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
lok: sw: empty parent causes irresponsive chart jsdialog
Clicking any of the chart wizard buttons 'Next', 'Cancel', 'Finish' etc
does not perform any action.
With this patch the wizard buttons when clicked performs corresponding
actions.
To reproduce:
1. Create a .odt file
2. Create a 2x2 table and insert data (first col can be a, b; second col
can be 1, 2)
3. Select the data, click insert Chart.
4. press Finish, The dialog is not closed.
Signed-off-by: Dennis Francis <[email protected]>
Change-Id: I5af8ba00a0b55b3d2ed10fa0f020ac21c4922afb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199065
Tested-by: Jenkins CollaboraOffice <[email protected]>
Reviewed-by: Miklos Vajna <[email protected]>
(cherry picked from commit 5e0b9f2ac68100eac288d08a30154f41f8925656)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199138
diff --git a/sw/source/uibase/table/chartins.cxx
b/sw/source/uibase/table/chartins.cxx
index 453e8ef03f44..140514787ab7 100644
--- a/sw/source/uibase/table/chartins.cxx
+++ b/sw/source/uibase/table/chartins.cxx
@@ -21,6 +21,7 @@
#include <sfx2/dispatch.hxx>
#include <IDocumentChartDataProviderAccess.hxx>
#include <osl/diagnose.h>
+#include <vcl/weldutils.hxx>
#include <swmodule.hxx>
#include <wrtsh.hxx>
@@ -174,10 +175,16 @@ SwInsertChart::SwInsertChart( const
Link<css::ui::dialogs::DialogClosedEvent*, v
uno::Reference< lang::XInitialization > xInit( xDialog, uno::UNO_QUERY );
if( xInit.is() )
{
+ css::uno::Reference< css::awt::XWindow > xParent;
+ vcl::Window* pWin = rWrtShell.GetWin();
+ if (pWin)
+ {
+ xParent = new weld::TransportAsXWindow(pWin->GetFrameWeld());
+ }
// initialize dialog
uno::Sequence<uno::Any> aSeq(comphelper::InitAnyPropertySequence(
{
- {"ParentWindow", uno::Any(uno::Reference< awt::XWindow >())},
+ {"ParentWindow", uno::Any(xParent)},
{"ChartModel", uno::Any(xChartModel)}
}));
xInit->initialize( aSeq );
commit 3e156642f3f44d033d77985861ea0278a9a8c47c
Author: Miklos Vajna <[email protected]>
AuthorDate: Mon Feb 9 09:05:55 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
sd: fix crash in AnalyzeRenderingRedirector
gdb on the crashreport core dump:
#0 0x000071590be5da30 in o3tl::cow_wrapper<OutlinerParaObjData,
o3tl::UnsafeRefCountingPolicy>::operator-> (this=<optimized out>)
at include/o3tl/cow_wrapper.hxx:331
#1 OutlinerParaObject::Count (this=0x0) at
editeng/source/outliner/outlobj.cxx:168
#2 0x00007158fd9ccb0a in sd::(anonymous
namespace)::AnalyzeRenderingRedirector::createRedirectedPrimitive2DSequence
(this=0x7ffc29a67820, rOriginal=..., rDisplayInfo=...)
at sd/source/ui/tools/SlideshowLayerRenderer.cxx:550
#3 0x000071590d4469ee in
sdr::contact::ViewObjectContact::getPrimitive2DSequence
(this=this@entry=0x560c9e40, rDisplayInfo=...)
at svx/source/sdr/contact/viewobjectcontact.cxx:477
#4 0x000071590d447109 in
sdr::contact::ViewObjectContact::getPrimitive2DSequenceHierarchy
(this=0x560c9e40, rDisplayInfo=..., rVisitor=...)
at svx/source/sdr/contact/viewobjectcontact.cxx:551
I.e. it's possible that in
AnalyzeRenderingRedirector::createRedirectedPrimitive2DSequence(),
pTextObject is non-nullptr but pTextObject->GetOutlinerParaObject() is
nullptr, check for this.
Change-Id: I1013809f134115fbeb56a9962d71380aaee17b22
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199059
Reviewed-by: Miklos Vajna <[email protected]>
Tested-by: Jenkins
(cherry picked from commit 7096036e38958a493fef7708677721cb3243bca6)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199074
Reviewed-by: Xisco Fauli <[email protected]>
diff --git a/sd/source/ui/tools/SlideshowLayerRenderer.cxx
b/sd/source/ui/tools/SlideshowLayerRenderer.cxx
index 7f025300dde0..8675630ced5f 100644
--- a/sd/source/ui/tools/SlideshowLayerRenderer.cxx
+++ b/sd/source/ui/tools/SlideshowLayerRenderer.cxx
@@ -543,7 +543,7 @@ public:
if (!aInfo.maParagraphs.empty()) // we need to render paragraphs
{
auto* pTextObject = dynamic_cast<SdrTextObj*>(pObject);
- if (pTextObject)
+ if (pTextObject && pTextObject->GetOutlinerParaObject())
{
sal_Int32 nNumberOfParagraphs =
pTextObject->GetOutlinerParaObject()->Count();
commit b5a3f3187f8ad58ebe3cd984548c57d8feb41723
Author: Heiko Tietze <[email protected]>
AuthorDate: Sat Jan 31 16:32:44 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
Resolves tdf#170143 - Set ButtonTextColor on theme change (macOS)
Change-Id: I054efdbbefc5a9f233abe7bae5429dd7e30c3e24
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198456
Reviewed-by: Heiko Tietze <[email protected]>
Tested-by: Jenkins
(cherry picked from commit 7e0c4230e8e854adc4d85d195af0ed683ee210bb)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198613
Reviewed-by: Xisco Fauli <[email protected]>
diff --git a/vcl/osx/salframe.cxx b/vcl/osx/salframe.cxx
index ca5938b48431..e2b331061c91 100644
--- a/vcl/osx/salframe.cxx
+++ b/vcl/osx/salframe.cxx
@@ -1525,6 +1525,7 @@ static void lcl_LoadColorsFromTheme(StyleSettings&
rStyleSet)
rStyleSet.SetFieldColor(rThemeColors.GetBaseColor());
rStyleSet.SetMenuBarTextColor(rThemeColors.GetMenuBarTextColor());
rStyleSet.SetMenuTextColor(rThemeColors.GetMenuTextColor());
+ rStyleSet.SetButtonTextColor(rThemeColors.GetButtonTextColor());
rStyleSet.SetDefaultActionButtonTextColor(rThemeColors.GetButtonTextColor());
rStyleSet.SetActionButtonTextColor(rThemeColors.GetButtonTextColor());
rStyleSet.SetShadowColor(rThemeColors.GetShadeColor());
commit 2ca9a9a62a18b990391b09fc90751ac97d1845c6
Author: Justin Luth <[email protected]>
AuthorDate: Tue Feb 3 15:46:17 2026 -0500
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
tdf#170588 docx export: stop duplicating bookmark in empty w:r
The comment says
// Append bookmarks in this range after flys,
// exclusive of final position of this range
but it did nothing to exclude a final position of zero.
When nNextAttr == nEnd, then AppendBookmark is run
It is guarantined to run once at the end,
and thus it is safe to eliminate it here.
Probably worth noting that normally by definition
nCurrentPos is exclusive of final position.
The only time nCurrentPos == nEnd is when nEnd == 0
(since it loops while nCurrentPos < nEnd),
so it seemed the clearest to say '0 != nEnd'
instead of 'nCurrentPos == nEnd'.
Change-Id: I5da3bc2a17c98faa7a73604e8a640ed456f25dd5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198628
Reviewed-by: Justin Luth <[email protected]>
Tested-by: Jenkins
(cherry picked from commit fb273cf50f9fca0d0d561a6011299502f55f464e)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198998
Reviewed-by: Xisco Fauli <[email protected]>
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
b/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
index c39ae316a796..ff797a81db86 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
@@ -315,7 +315,7 @@ CPPUNIT_TEST_FIXTURE(Test, testFdo77129)
// tdf#170588: stop duplicating bookmarkStarts
// Counts of bookmark Starts and Ends really ought to be identical...
assertXPath(pXmlDoc, "//w:bookmarkEnd", 4);
- assertXPath(pXmlDoc, "//w:bookmarkStart", 5);
+ assertXPath(pXmlDoc, "//w:bookmarkStart", 4);
}
// Test the same testdoc used for testFdo77129.
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx
b/sw/source/filter/ww8/wrtw8nds.cxx
index 1cfbb8cf0adc..db55d80e73c9 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -2535,10 +2535,14 @@ void MSWordExportBase::OutputTextNode( SwTextNode&
rNode )
// Append bookmarks in this range after flys, exclusive of final
// position of this range
- AppendBookmarks( rNode, nCurrentPos, nNextAttr - nCurrentPos,
pRedlineData );
- // Sadly only possible for main or glossary document parts:
ECMA-376 Part 1 sect. 11.3.2
- if ( m_nTextTyp == TXT_MAINTEXT )
- AppendAnnotationMarks(aAttrIter, nCurrentPos, nNextAttr -
nCurrentPos);
+ if (0 != nEnd) // start == final position is written when
nNextAttr == nEnd
+ {
+ AppendBookmarks(rNode, nCurrentPos, nNextAttr - nCurrentPos,
pRedlineData);
+ // Sadly, comments are only possible
+ // for main or glossary document parts: ECMA-376 Part 1 sect.
11.3.2
+ if (m_nTextTyp == TXT_MAINTEXT)
+ AppendAnnotationMarks(aAttrIter, nCurrentPos, nNextAttr -
nCurrentPos);
+ }
// At the moment smarttags are only written for paragraphs, at the
// beginning of the paragraph.
commit 6440a038da415f391048627ba15688aea3a75345
Author: Justin Luth <[email protected]>
AuthorDate: Tue Feb 3 13:05:08 2026 -0500
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
tdf#170588 docx export: stop duplicating bookmark starts
Bookmarks can span multiple nodes.
Since we weren't checking the node
we were often adding the bookmark start multiple times,
once for the start node and again for the end node.
This is guaranteed to happen for any bookmark
starting at position zero, and possible for the other positions.
An extra end bookmark doesn't matter,
because it isn't written if it doesn't find the name in the starts.
A similar fix was needed for comments in bug 170457.
make CppunitTest_sw_ooxmlexport20 CPPUNIT_TEST_NAME=testFdo77129
Change-Id: I595595a2b48aabf861179ade1b3097fc31e2a12e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198620
Reviewed-by: Justin Luth <[email protected]>
Tested-by: Jenkins
(cherry picked from commit fe67e1899b3d3322b4e6721349af51a0c0416383)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198997
Reviewed-by: Xisco Fauli <[email protected]>
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
b/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
index f77f9aa65a4e..c39ae316a796 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport20.cxx
@@ -311,6 +311,11 @@ CPPUNIT_TEST_FIXTURE(Test, testFdo77129)
// Data was lost from this paragraph.
assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[4]/w:r[1]/w:t",
u"Abstract");
+
+ // tdf#170588: stop duplicating bookmarkStarts
+ // Counts of bookmark Starts and Ends really ought to be identical...
+ assertXPath(pXmlDoc, "//w:bookmarkEnd", 4);
+ assertXPath(pXmlDoc, "//w:bookmarkStart", 5);
}
// Test the same testdoc used for testFdo77129.
diff --git a/sw/source/filter/ww8/docxexport.cxx
b/sw/source/filter/ww8/docxexport.cxx
index 63a084c6a44a..d06f58e228f3 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -177,10 +177,10 @@ void DocxExport::AppendBookmarks( const SwTextNode&
rNode, sal_Int32 nCurrentPos
const sal_Int32 nStart = pMark->GetMarkStart().GetContentIndex();
const sal_Int32 nEnd = pMark->GetMarkEnd().GetContentIndex();
- if ( nStart == nCurrentPos )
+ if (nStart == nCurrentPos && rNode ==
pMark->GetMarkStart().GetNode())
aStarts.push_back( pMark->GetName().toString() );
- if ( nEnd == nCurrentPos )
+ if (nEnd == nCurrentPos && rNode == pMark->GetMarkEnd().GetNode())
aEnds.push_back( pMark->GetName().toString() );
}
}
commit c7ab5163d92293ba58d09cd45ed73558e8b292ba
Author: Mike Kaganski <[email protected]>
AuthorDate: Tue Feb 10 12:18:06 2026 +0500
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
tdf#170701: only enable [Accept]/[Reject] for top-level changes
Regression after commit 6fe35fdbd39cee17cb1f4fc9494520e2bdcabcba
(tdf#167128: SwRedlineAcceptDlg: move enabling controls after
selection, 2025-06-20). The previous code, that enabled these
controls in GotoHdl, only set bSel to true for top-level items.
This change implements the same logic in EnableControls.
Change-Id: I70414ece801312d1b5e873db0440c0e28b76ef02
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199019
Reviewed-by: Mike Kaganski <[email protected]>
Tested-by: Jenkins
Signed-off-by: Xisco Fauli <[email protected]>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199039
diff --git a/sw/source/uibase/misc/redlndlg.cxx
b/sw/source/uibase/misc/redlndlg.cxx
index 3f7fd3a5cde8..bbe55c85fc9c 100644
--- a/sw/source/uibase/misc/redlndlg.cxx
+++ b/sw/source/uibase/misc/redlndlg.cxx
@@ -380,10 +380,14 @@ void SwRedlineAcceptDlg::EnableControls(const SwView*
pView)
bool const bEnable = isAcceptRejectCommandsEnabled(*pView)
&& rTreeView.n_children() != 0
&&
!pSh->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
- bool bSel = rTreeView.get_selected(nullptr);
+ bool bAcceptReject = false;
bool bIsNotFormated = false;
- rTreeView.selected_foreach([this, pSh, &bIsNotFormated](weld::TreeIter&
rEntry){
+ rTreeView.selected_foreach([this, pSh, &bIsNotFormated,
&bAcceptReject](weld::TreeIter& rEntry){
+ // Only enable these controls for top-level redlines
+ if (m_pTable->GetWidget().get_iter_depth(rEntry) == 0)
+ bAcceptReject = true;
+
// find the selected redline
// (fdo#57874: ignore, if the redline is already gone)
SwRedlineTable::size_type nPos = GetRedlinePos(rEntry);
@@ -396,9 +400,9 @@ void SwRedlineAcceptDlg::EnableControls(const SwView* pView)
return false;
});
- m_pTPView->EnableAccept( bEnable && bSel );
- m_pTPView->EnableReject( bEnable && bSel );
- m_pTPView->EnableClearFormat( bEnable && !bIsNotFormated && bSel );
+ m_pTPView->EnableAccept( bEnable && bAcceptReject );
+ m_pTPView->EnableReject( bEnable && bAcceptReject );
+ m_pTPView->EnableClearFormat( bEnable && !bIsNotFormated && bAcceptReject
);
m_pTPView->EnableAcceptAll( bEnable );
m_pTPView->EnableRejectAll( bEnable );
m_pTPView->EnableClearFormatAll( bEnable &&
commit 7e732e0bc62eb1364601287a4431bef777d8bca2
Author: Mike Kaganski <[email protected]>
AuthorDate: Mon Feb 9 14:50:16 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
tdf#170682: Use Skia/raster in safe mode on Windows and macOS
After commits 07f480b7c85ccd7492428d5da96d68602c516eb8 (make skia
mandatory on MS-Windows, disable GDI backend, 2025-07-03) and
e7bd446baa292b65c8b0141f404ce9b684b0abff (tdf#167642 Restart in
safe mode doesn't launch safe mode on macOS, 2025-07-25), Skia is
enabled in safe mode on these platforms. After enabling it, there
was no code to handle safe mode - so initRenderMethodToUse would
enable HW acceleration (and potentially crash, if the reason to
start safe mode was crash caused by Vulkan / Metal).
This change returns RenderRaster from initRenderMethodToUse in
safe mode on these platforms.
Change-Id: Ie80938f28985cb60e3936f274f26c3dcfa838616
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198993
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <[email protected]>
(cherry picked from commit bc3376e82baf9d6a8000a40b34a9ec0cb788f585)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199012
Reviewed-by: Xisco Fauli <[email protected]>
diff --git a/vcl/skia/SkiaHelper.cxx b/vcl/skia/SkiaHelper.cxx
index ff80f4a6dd22..613b70248ce7 100644
--- a/vcl/skia/SkiaHelper.cxx
+++ b/vcl/skia/SkiaHelper.cxx
@@ -247,6 +247,11 @@ static RenderMethod initRenderMethodToUse()
{
if (Application::IsBitmapRendering())
return RenderRaster;
+#if defined(MACOSX) || defined(_WIN32)
+ // macOS/win can __only__ render via skia - there, we can only disable HW
acceleration
+ if (Application::IsSafeModeEnabled())
+ return RenderRaster;
+#endif
if (const char* env = getenv("SAL_SKIA"))
{
commit d71ee70ca26c823cc78d35ecc3d539486729578d
Author: Andras Timar <[email protected]>
AuthorDate: Sun Feb 8 12:09:12 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
tdf#142226 emfio: implement EMR_SMALLTEXTOUT
Change-Id: Ib031c0d771045b80c99274974de8267e759e8557
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198903
Tested-by: Jenkins
Reviewed-by: Andras Timar <[email protected]>
(cherry picked from commit aad62f783bd1bced7a6f850058be9c833f998ec1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198947
Reviewed-by: Xisco Fauli <[email protected]>
diff --git a/emfio/README.md b/emfio/README.md
index f9f33a2ba4e1..b1a0de61c888 100644
--- a/emfio/README.md
+++ b/emfio/README.md
@@ -82,7 +82,7 @@ EMR_SETPALETTEENTRIES EMR_RESIZEPALETTE
EMR_EXTFLOODFILL EMR_ANGLEARC EMR_SETCOLORADJUSTMENT EMR_POLYDRAW16
EMR_CREATECOLORSPACE EMR_SETCOLORSPACE EMR_DELETECOLORSPACE
EMR_GLSRECORD EMR_GLSBOUNDEDRECORD EMR_PIXELFORMAT EMR_DRAWESCAPE
-EMR_EXTESCAPE EMR_STARTDOC EMR_SMALLTEXTOUT EMR_FORCEUFIMAPPING
+EMR_EXTESCAPE EMR_STARTDOC EMR_FORCEUFIMAPPING
EMR_NAMEDESCAPE EMR_COLORCORRECTPALETTE EMR_SETICMPROFILEA
EMR_SETICMPROFILEW EMR_TRANSPARENTBLT EMR_TRANSPARENTDIB
EMR_GRADIENTFILL EMR_SETLINKEDUFIS EMR_SETMAPPERFLAGS EMR_SETICMMODE
diff --git a/emfio/inc/mtftools.hxx b/emfio/inc/mtftools.hxx
index 47c556b16038..7d1c99923b24 100644
--- a/emfio/inc/mtftools.hxx
+++ b/emfio/inc/mtftools.hxx
@@ -264,6 +264,7 @@ namespace emfio
ETO_RTLREADING = 0x0080,
/* _WIN32_WINNT >= 0x0500 */
ETO_NO_RECT = 0x0100,
+ ETO_SMALL_CHARS = 0x0200,
ETO_PDY = 0x2000
};
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx
b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index c11f6b41c7c2..7eef19cea5b5 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -1702,6 +1702,38 @@ CPPUNIT_TEST_FIXTURE(Test, testAlignRtlReading)
assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion[3]", "rtl",
u"true");
}
+CPPUNIT_TEST_FIXTURE(Test, testSmallTextOut)
+{
+ // EMR_SMALLTEXTOUT with Unicode text (no ETO_SMALL_CHARS), ETO_NO_RECT.
+ // Verifies the text "SmallTextOut" is correctly imported.
+ OUString aUrl =
m_directories.getURLFromSrc(u"/emfio/qa/cppunit/emf/data/TestSmallTextOut.emf");
+ SvFileStream aFileStream(aUrl, StreamMode::READ);
+ GDIMetaFile aGDIMetaFile;
+ ReadWindowMetafile(aFileStream, aGDIMetaFile);
+
+ MetafileXmlDump dumper;
+ xmlDocUniquePtr pDoc = dumpAndParse(dumper, aGDIMetaFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPathContent(pDoc, "/metafile/push[2]/textarray/text",
u"SmallTextOut");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSmallTextOutAnsi)
+{
+ // EMR_SMALLTEXTOUT with ETO_SMALL_CHARS (8-bit text) and bounds rectangle.
+ OUString aUrl
+ =
m_directories.getURLFromSrc(u"/emfio/qa/cppunit/emf/data/TestSmallTextOutAnsi.emf");
+ SvFileStream aFileStream(aUrl, StreamMode::READ);
+ GDIMetaFile aGDIMetaFile;
+ ReadWindowMetafile(aFileStream, aGDIMetaFile);
+
+ MetafileXmlDump dumper;
+ xmlDocUniquePtr pDoc = dumpAndParse(dumper, aGDIMetaFile);
+ CPPUNIT_ASSERT(pDoc);
+
+ assertXPathContent(pDoc, "/metafile/push[2]/textarray/text", u"AnsiSmall");
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/emfio/qa/cppunit/emf/data/TestSmallTextOut.emf
b/emfio/qa/cppunit/emf/data/TestSmallTextOut.emf
new file mode 100644
index 000000000000..2505d2d65f2c
Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestSmallTextOut.emf
differ
diff --git a/emfio/qa/cppunit/emf/data/TestSmallTextOutAnsi.emf
b/emfio/qa/cppunit/emf/data/TestSmallTextOutAnsi.emf
new file mode 100644
index 000000000000..cfba2f8e1a4f
Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestSmallTextOutAnsi.emf
differ
diff --git a/emfio/source/reader/emfreader.cxx
b/emfio/source/reader/emfreader.cxx
index 57e715fad4ea..bd5defcd1cc7 100644
--- a/emfio/source/reader/emfreader.cxx
+++ b/emfio/source/reader/emfreader.cxx
@@ -1879,6 +1879,81 @@ namespace emfio
}
break;
+ case EMR_SMALLTEXTOUT :
+ {
+ sal_Int32 ptlReferenceX, ptlReferenceY;
+ sal_uInt32 nLen, nOptions, nGfxMode;
+ float nXScale, nYScale;
+
+ mpInputStream->ReadInt32( ptlReferenceX ).ReadInt32(
ptlReferenceY )
+ .ReadUInt32( nLen ).ReadUInt32( nOptions )
+ .ReadUInt32( nGfxMode ).ReadFloat( nXScale
).ReadFloat( nYScale );
+ SAL_INFO("emfio", " Reference: (" <<
ptlReferenceX << ", " << ptlReferenceY << ")");
+ SAL_INFO("emfio", " cChars: " << nLen);
+ SAL_INFO("emfio", " fuOptions: 0x" <<
std::hex << nOptions << std::dec);
+ SAL_INFO("emfio", " iGraphicsMode: 0x" <<
std::hex << nGfxMode << std::dec);
+ SAL_INFO("emfio", " Scale: " << nXScale <<
" x " << nYScale);
+
+ // Read optional bounding rectangle (present only if
ETO_NO_RECT is NOT set)
+ tools::Rectangle aRect;
+ if ( !( nOptions & ETO_NO_RECT ) )
+ {
+ sal_Int32 nLeftRect, nTopRect, nRightRect,
nBottomRect;
+ mpInputStream->ReadInt32( nLeftRect ).ReadInt32(
nTopRect ).ReadInt32( nRightRect ).ReadInt32( nBottomRect );
+ aRect = tools::Rectangle( nLeftRect, nTopRect,
nRightRect, nBottomRect );
+ SAL_INFO("emfio", " Bounds: " <<
nLeftRect << ", " << nTopRect << ", " << nRightRect << ", " << nBottomRect);
+ }
+
+ if (!mpInputStream->good())
+ {
+ bStatus = false;
+ }
+ else
+ {
+ const BackgroundMode mnBkModeBackup = mnBkMode;
+ if ( nOptions & ETO_NO_RECT )
+ mnBkMode = BackgroundMode::Transparent;
+ else if ( nOptions & ETO_OPAQUE )
+ DrawRectWithBGColor( aRect );
+
+ vcl::text::ComplexTextLayoutFlags nTextLayoutMode
= vcl::text::ComplexTextLayoutFlags::Default;
+ if ( nOptions & ETO_RTLREADING )
+ nTextLayoutMode =
vcl::text::ComplexTextLayoutFlags::BiDiRtl |
vcl::text::ComplexTextLayoutFlags::TextOriginLeft;
+ SetTextLayoutMode( nTextLayoutMode );
+
+ Point aPos( ptlReferenceX, ptlReferenceY );
+ OUString aText;
+ if ( nOptions & ETO_SMALL_CHARS )
+ {
+ if ( nLen <= ( mnEndPos -
mpInputStream->Tell() ) )
+ {
+ std::vector<char> pBuf( nLen );
+ mpInputStream->ReadBytes(pBuf.data(),
nLen);
+ aText = OUString(pBuf.data(), nLen,
GetCharSet());
+ }
+ }
+ else
+ {
+ if ( ( nLen * sizeof(sal_Unicode) ) <= (
mnEndPos - mpInputStream->Tell() ) )
+ {
+ aText =
read_uInt16s_ToOUString(*mpInputStream, nLen);
+ }
+ }
+ SAL_INFO("emfio", " Text: " <<
aText);
+
+ if ( nOptions & ETO_CLIPPED )
+ {
+ Push();
+ IntersectClipRect( aRect );
+ }
+ DrawText(aPos, aText, nullptr, nullptr,
mbRecordPath, static_cast<GraphicsMode>(nGfxMode));
+ if ( nOptions & ETO_CLIPPED )
+ Pop();
+ mnBkMode = mnBkModeBackup;
+ }
+ }
+ break;
+
case EMR_POLYTEXTOUTA :
case EMR_EXTTEXTOUTA :
bFlag = true;
@@ -2219,7 +2294,6 @@ namespace emfio
case EMR_DRAWESCAPE :
case EMR_EXTESCAPE :
case EMR_STARTDOC :
- case EMR_SMALLTEXTOUT :
case EMR_FORCEUFIMAPPING :
case EMR_NAMEDESCAPE :
case EMR_COLORCORRECTPALETTE :
commit 6118d9fad308ec724b926cea4396f038438813dc
Author: Andras Timar <[email protected]>
AuthorDate: Sun Feb 8 16:46:30 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
Revert tdf#159306 EMF: fix PS_COSMETIC pen width regression
Commit be9d6e414e4b forced all PS_COSMETIC pen widths to 1 in both
EMR_CREATEPEN and EMR_EXTCREATEPEN handlers. Since PS_COSMETIC is
0x00000000 (same value as PS_SOLID), the check
"if (nPenStyle == PS_COSMETIC)" matched every simple PS_SOLID pen,
causing all line widths to be lost. This made all lines render as
hairlines regardless of the actual width specified in the EMF file.
The style sanitization check for invalid PS_STYLE_MASK values is
retained, but the width forcing is removed. Pen widths from the
file are now used as-is: width=0 produces a hairline, width>=1
produces a scaled line. This effectively reverts to the behavior
established by tdf#140271 (commit 8932c8906ff3), which recognized
that real-world EMF producers use EMR_CREATEPEN with widths > 1
and expect them to be honored.
Change-Id: I9a3acf83ce03b4e646e9b95fe0db54f8ce403a49
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198904
Reviewed-by: Andras Timar <[email protected]>
Tested-by: Jenkins
(cherry picked from commit aa616d930e7078b4226203c7c894e382c6f449b8)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198946
Reviewed-by: Xisco Fauli <[email protected]>
diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx
b/emfio/qa/cppunit/emf/EmfImportTest.cxx
index 2a5aa8ab9968..c11f6b41c7c2 100644
--- a/emfio/qa/cppunit/emf/EmfImportTest.cxx
+++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx
@@ -1601,7 +1601,7 @@ CPPUNIT_TEST_FIXTURE(Test, testRoundRect)
CPPUNIT_TEST_FIXTURE(Test, testCreatePen)
{
// Check import of EMF image with records: RESTOREDC, SAVEDC, MOVETOEX,
LINETO, POLYLINE16, EXTTEXTOUTW with DxBuffer
- // The CREATEPEN record is used with PS_COSMETIC line style, and in this
case width must be set to 0
+ // The CREATEPEN record is used with PS_COSMETIC line style, which
sometimes will be displayed as solid hairline
Primitive2DSequence aSequence =
parseEmf(u"/emfio/qa/cppunit/emf/data/TestCreatePen.emf");
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
drawinglayer::Primitive2dXmlDump dumper;
@@ -1610,23 +1610,23 @@ CPPUNIT_TEST_FIXTURE(Test, testCreatePen)
assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "path", u"m0
0h31250v18192h-31250z");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke", 758);
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke", 748);
assertXPathContent(pDocument, aXPathPrefix +
"mask/polygonstroke[1]/polygon",
- u"0,0 31225,0 31225,17742 0,17742");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line",
"color", u"#ffffff");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line",
"width", u"25");
+ u"27875,16523 27875,1453");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line",
"color", u"#ff0000");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[1]/line",
"width", u"6");
assertXPathContent(pDocument, aXPathPrefix +
"mask/polygonstroke[2]/polygon",
- u"25,23 31200,23 31200,17719 25,17719");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line",
"color", u"#ffffff");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line",
"width", u"25");
+ u"27975,16453 27875,16453");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line",
"color", u"#ff0000");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[2]/line",
"width", u"6");
assertXPathContent(pDocument, aXPathPrefix +
"mask/polygonstroke[3]/polygon",
- u"27875,16523 27875,1453");
+ u"27925,16078 27875,16078");
assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[3]/line",
"color", u"#ff0000");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[3]/line",
"width", u"3");
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonstroke[3]/line",
"width", u"6");
- assertXPath(pDocument, aXPathPrefix + "mask/polygonhairline", 0);
+ assertXPath(pDocument, aXPathPrefix + "mask/polygonhairline", 10);
assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion", 69);
assertXPath(pDocument, aXPathPrefix + "mask/textsimpleportion[1]",
"width", u"374");
diff --git a/emfio/source/reader/emfreader.cxx
b/emfio/source/reader/emfreader.cxx
index c90db53b7dbc..57e715fad4ea 100644
--- a/emfio/source/reader/emfreader.cxx
+++ b/emfio/source/reader/emfreader.cxx
@@ -1259,10 +1259,8 @@ namespace emfio
SAL_INFO("emfio", " Index: " <<
nIndex << " Style: 0x" << std::hex
<< nPenStyle <<
std::dec
<< " PenWidth: "
<< nPenWidth);
- // PS_COSMETIC width is always fixed at one
logical unit
- // and is not affected by any geometric
transformations like scaling
- if (nPenStyle == PS_COSMETIC)
- nPenWidth = 1;
+ if ((nPenStyle & PS_STYLE_MASK) > PS_INSIDEFRAME)
+ nPenStyle = PS_COSMETIC;
CreateObjectIndexed(nIndex,
std::make_unique<WinMtfLineStyle>(ReadColor(), nPenStyle, nPenWidth));
}
}
@@ -1285,10 +1283,8 @@ namespace emfio
else
{
SAL_INFO("emfio", " Style: 0x" <<
std::hex << nPenStyle << std::dec);
- // PS_COSMETIC width is always fixed at one
logical unit
- // and is not affected by any geometric
transformations like scaling
- if (nPenStyle == PS_COSMETIC)
- nWidth = 1;
+ if ((nPenStyle & PS_STYLE_MASK) >
PS_INSIDEFRAME)
+ nPenStyle = PS_COSMETIC;
SAL_INFO("emfio", " Width: " <<
nWidth);
CreateObjectIndexed(nIndex,
std::make_unique<WinMtfLineStyle>(aColorRef, nPenStyle, nWidth));
}
commit e17c8f56512ee339cefb10a5b12af8389462d325
Author: Mike Kaganski <[email protected]>
AuthorDate: Sun Feb 8 17:08:52 2026 +0500
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
tdf#169607: Do split when learned that it wasn't an empty master split
Commit ae9e8f3f6d10b0be2fe5b9b238a531b17e0d67da prevented splitting
master frame at the beginning of page, because there shouldn't be an
empty frame there. But the actual number of characters that goes to
the master frame will only be known after FindBreak, at which point
it may turn out that the suppression was wrong.
This change checks this situation, and splits anyway. It is similar
to what happens below, where SplitFrame is also called.
Change-Id: If32fe2817a91724d704a096111a963f63deee593
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198902
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <[email protected]>
Signed-off-by: Xisco Fauli <[email protected]>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198955
diff --git a/sw/qa/extras/layout/data/tdf169607-big-letters.fodt
b/sw/qa/extras/layout/data/tdf169607-big-letters.fodt
new file mode 100644
index 000000000000..1875781f248d
--- /dev/null
+++ b/sw/qa/extras/layout/data/tdf169607-big-letters.fodt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:ooo="http://openoffice.org/2004/office"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:settings>
+ <config:config-item-set config:name="ooo:configuration-settings">
+ <config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation"
config:type="boolean">true</config:config-item>
+ </config:config-item-set>
+ </office:settings>
+ <office:automatic-styles>
+ <style:style style:name="T1" style:family="text">
+ <style:text-properties fo:font-size="500pt"/>
+ </style:style>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="297mm" fo:page-height="210mm"
style:print-orientation="landscape" fo:margin-top="20mm"
fo:margin-bottom="20mm" fo:margin-left="20mm" fo:margin-right="20mm"
style:writing-mode="lr-tb"/>
+ </style:page-layout>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+ <text:p loext:marker-style-name="T1"><text:span
text:style-name="T1">FOOBAR</text:span></text:p>
+ </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/layout/layout6.cxx b/sw/qa/extras/layout/layout6.cxx
index 1217dc28ff87..bebc6deb7563 100644
--- a/sw/qa/extras/layout/layout6.cxx
+++ b/sw/qa/extras/layout/layout6.cxx
@@ -2183,6 +2183,19 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf167946)
assertXPath(pXmlDoc, "//SwLineLayout[2]/child::*[81]", "portion", u",");
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf169607)
+{
+ // Given a document with a sequence of huge letters, each of which don't
fit to page vertically:
+ createSwDoc("tdf169607-big-letters.fodt");
+
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ CPPUNIT_ASSERT(pXmlDoc);
+
+ // There must be three pages, because the sequence must split two
characters per page. Before
+ // the fix, there was only one page:
+ assertXPath(pXmlDoc, "//page", 3);
+}
+
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index dc4e06c89292..7afd83430384 100644
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -1233,6 +1233,7 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine,
GetDrawObjs() && GetDrawObjs()->size() == 1 &&
(*GetDrawObjs())[0]->GetFrameFormat()->GetAnchor().GetAnchorId()
== RndStdIds::FLY_AS_CHAR;
+ bool bCreateNewSuppressedByEmptySplit = false;
if (bLoneAsCharAnchoredObj)
{
// Still try split text frame if we have columns.
@@ -1263,7 +1264,10 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine,
// frame if we have columns.
if (pBodyFrame && !FindColFrame() &&
isFirstVisibleFrameInPageBody(this)
&& !hasFly(this) && !hasAtPageFly(pBodyFrame))
+ {
createNew = false;
+ bCreateNewSuppressedByEmptySplit = true;
+ }
}
}
@@ -1317,6 +1321,15 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine,
if( !bDelta )
GetFollow()->ManipOfst( nEnd );
}
+ else
+ {
+ if (bCreateNewSuppressedByEmptySplit && nEnd != nOld)
+ {
+ // Not empty split: nEnd moved
+ SplitFrame(nEnd);
+ dontJoin = true;
+ }
+ }
}
else
{ // If we pass over lines, we must not call Join in Follows, instead we
even
commit 367ef7c1dca300b1966093de5bbfca8ea97d403a
Author: Mike Kaganski <[email protected]>
AuthorDate: Sat Feb 7 14:57:33 2026 +0500
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
tdf#167946: reimplement the fix for tdf#120677
Commit 4bb28ad217ea9d6511b6921dcd3d28328edcb4d6 (tdf#120677: restore
treatment of blanks in SwTextGuess::Guess, 2018-11-12) made NBSPs
behave like ordinary spaces for line breaking purposes. But that is
wrong; NBSPs are explicitly defined in UAX #14 to behave differently.
It turns out, that the problem in tdf#120677 was caused by specifics
of handling of SwBlankPortion, which was defined as descendant of
SwExpandPortion (since initial import). SwExpandPortion::Format uses
special logic to change the passed SwTextFormatInfo using SwTextSlot,
to allow formatting text that is different from what was initially
passed to SwTextFormatInfo. This logic isn't needed for blanks, and
happens to confuse the normal line-breaking algorithm to return zero
for blank portions with NBSP. SwExpandPortion::Paint method, also
previously used by SwBlankPortion, doesn't seem to include any logic
specifically useful for blanks as well, and respective methods of
SwTextPortion can be used instead.
This change reverts the functional change of the previous fix for
tdf#120677 (the unit test is kept), and makes SwBlankPortion inherit
from SwTextPortion, which fixes both tdf#120677 and tdf#167946.
Change-Id: I9109069093a7f58a997a93723f81137d1a6bd7f8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198882
Reviewed-by: Mike Kaganski <[email protected]>
Tested-by: Jenkins
Signed-off-by: Xisco Fauli <[email protected]>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198954
diff --git a/sw/qa/extras/layout/data/nbsp-moved-to-new-line.fodt
b/sw/qa/extras/layout/data/nbsp-moved-to-new-line.fodt
new file mode 100644
index 000000000000..63ad3180eca5
--- /dev/null
+++ b/sw/qa/extras/layout/data/nbsp-moved-to-new-line.fodt
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:font-face-decls>
+ <style:font-face style:name="Liberation Serif"
svg:font-family="'Liberation Serif'"
style:font-family-generic="roman" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+ <style:default-style style:family="paragraph">
+ <style:paragraph-properties style:text-autospace="ideograph-alpha"
style:punctuation-wrap="hanging" style:line-break="strict"
style:writing-mode="page"/>
+ <style:text-properties style:font-name="Liberation Serif"
fo:font-size="12pt" fo:hyphenate="false"/>
+ </style:default-style>
+ <style:style style:name="Standard" style:family="paragraph"
style:class="text"/>
+ </office:styles>
+ <office:automatic-styles>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="210mm" fo:page-height="297mm"
style:print-orientation="portrait" fo:margin-top="20mm" fo:margin-bottom="20mm"
fo:margin-left="20mm" fo:margin-right="20mm" style:writing-mode="lr-tb"/>
+ </style:page-layout>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+ <!-- The first space after "elit." is a normal space; all the following up
to comma are NBSPs -->
+ <text:p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
,</text:p>
+ </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/layout/layout6.cxx b/sw/qa/extras/layout/layout6.cxx
index 8a2a23af6634..1217dc28ff87 100644
--- a/sw/qa/extras/layout/layout6.cxx
+++ b/sw/qa/extras/layout/layout6.cxx
@@ -2144,6 +2144,45 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf170630)
assertXPath(pXmlDoc, "//page[1]/body/txt[3]/anchored/fly", 2);
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf167946)
+{
+ // Given a document with a sequence of non-breaking spaces after a text
and a space, which
+ // sequence doesn't fit the rest of the line. Before the fix, only the
comma was moved to the
+ // second line, and all NBSPs were elided as a hole portion at the end of
the first line:
+ createSwDoc("nbsp-moved-to-new-line.fodt");
+
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ CPPUNIT_ASSERT(pXmlDoc);
+
+ // One page:
+ assertXPath(pXmlDoc, "//page", 1);
+
+ // One paragraph:
+ assertXPath(pXmlDoc, "//txt", 1);
+
+ // Two lines in the paragraph:
+ assertXPath(pXmlDoc, "//txt/SwParaPortion/SwLineLayout", 2);
+ assertXPath(pXmlDoc, "//SwLineLayout", 2);
+
+ // First line consists of a text portion with, and a hole portion for the
following space:
+ assertXPath(pXmlDoc, "//SwLineLayout[1]/child::*[1]", "type",
u"PortionType::Text");
+ assertXPath(pXmlDoc, "//SwLineLayout[1]/child::*[1]", "portion",
+ u"Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
+ assertXPath(pXmlDoc, "//SwLineLayout[1]/child::*[2]", "type",
u"PortionType::Hole");
+ assertXPath(pXmlDoc, "//SwLineLayout[1]/child::*[2]", "portion", u" ");
+
+ // Second line has blank portions for the leading NBSPs, followed by a
text portion with comma:
+ assertXPathChildren(pXmlDoc, "//SwLineLayout[2]", 81);
+ for (int i = 1; i <= 80; ++i)
+ {
+ OString aXPath = "//SwLineLayout[2]/child::*[" + OString::number(i) +
"]";
+ assertXPath(pXmlDoc, aXPath, "type", u"PortionType::Blank");
+ assertXPath(pXmlDoc, aXPath, "portion", u"\xA0");
+ }
+ assertXPath(pXmlDoc, "//SwLineLayout[2]/child::*[81]", "type",
u"PortionType::Text");
+ assertXPath(pXmlDoc, "//SwLineLayout[2]/child::*[81]", "portion", u",");
+}
+
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/text/guess.cxx b/sw/source/core/text/guess.cxx
index a7db9c2c13bb..efaf2b5005b7 100644
--- a/sw/source/core/text/guess.cxx
+++ b/sw/source/core/text/guess.cxx
@@ -43,7 +43,8 @@ using namespace ::com::sun::star::linguistic2;
namespace{
-bool IsBlank(sal_Unicode ch) { return ch == CH_BLANK || ch == CH_FULL_BLANK ||
ch == CH_NB_SPACE || ch == CH_SIX_PER_EM; }
+// UAX #14: spaces from SP and BA classes (elided in the end of a line)
+bool IsBlank(sal_Unicode ch) { return ch == CH_BLANK || ch == CH_FULL_BLANK ||
ch == CH_SIX_PER_EM; }
// Used when spaces should not be counted in layout
// Returns adjusted cut position
diff --git a/sw/source/core/text/porexp.cxx b/sw/source/core/text/porexp.cxx
index afdf71da21c0..a9bb3add21b0 100644
--- a/sw/source/core/text/porexp.cxx
+++ b/sw/source/core/text/porexp.cxx
@@ -195,7 +195,7 @@ void SwBlankPortion::FormatEOL( SwTextFormatInfo &rInf )
*/
bool SwBlankPortion::Format( SwTextFormatInfo &rInf )
{
- const bool bFull = rInf.IsUnderflow() || SwExpandPortion::Format( rInf );
+ const bool bFull = rInf.IsUnderflow() || SwTextPortion::Format(rInf);
if( bFull && MayUnderflow( rInf, rInf.GetIdx(), rInf.IsUnderflow() ) )
{
Truncate();
@@ -211,7 +211,7 @@ void SwBlankPortion::Paint( const SwTextPaintInfo &rInf )
const
// Draw field shade (can be disabled individually)
if (!m_bMulti) // No gray background for multiportion brackets
rInf.DrawViewOpt(*this, PortionType::Blank);
- SwExpandPortion::Paint(rInf);
+ SwTextPortion::Paint(rInf);
if (rInf.GetOpt().IsViewMetaChars() && rInf.GetOpt().IsHardBlank())
{
diff --git a/sw/source/core/text/porexp.hxx b/sw/source/core/text/porexp.hxx
index baf45c7cf2dd..22b1347f78c3 100644
--- a/sw/source/core/text/porexp.hxx
+++ b/sw/source/core/text/porexp.hxx
@@ -39,7 +39,7 @@ public:
};
/// Non-breaking space or non-breaking hyphen.
-class SwBlankPortion : public SwExpandPortion
+class SwBlankPortion final : public SwTextPortion
{
sal_Unicode m_cChar;
bool m_bMulti; // For multiportion brackets
commit 95d420cffc7e10346469c82b208de5bfb68f8167
Author: Mike Kaganski <[email protected]>
AuthorDate: Fri Feb 6 19:23:28 2026 +0500
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
sw floattable: sort split fly frames in SwSortedObjs from start to end
Previously, there was no rule in ObjAnchorOrder to define the order
of such split fly frames, that share everything that was previously
compared there. Therefore, new follows were added to front of the
vector, making it effectively sorted in the reverse direction. That
meant, that all loops over elements of GetSortedObjs() handled the
objects in the opposite direction (first follows, then precedes).
This change adds a sorting rule to handle related split fly frames.
To handle previous follow flys, that have already been removed from
the chain, but are still in a sorted list, the sorting rules move
these to the end, to guarantee correct partitioning.
Incidentally, this allowed to fix a pre-existing unit test to test
page 3, as intended.
Change-Id: I79f3a3f32630d72f098d34a2b1ade1262b1c66b8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198842
Reviewed-by: Mike Kaganski <[email protected]>
Tested-by: Jenkins
Signed-off-by: Xisco Fauli <[email protected]>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198953
diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index e390f0a7e3c9..0eb297393502 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -229,7 +229,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFly3Pages)
// No vert offset on the second page:
CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(0), nPage2FlyTop -
nPage2AnchorTop);
// 3rd page:
- auto pPage3 = dynamic_cast<SwPageFrame*>(pPage1->GetNext());
+ auto pPage3 = dynamic_cast<SwPageFrame*>(pPage2->GetNext());
CPPUNIT_ASSERT(pPage3);
const SwSortedObjs& rPage3Objs = *pPage3->GetSortedObjs();
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage3Objs.size());
@@ -241,6 +241,17 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFly3Pages)
SwTwips nPage3FlyTop = pPage3Fly->getFrameArea().Top();
// No vert offset on the 3rd page:
CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(0), nPage3FlyTop -
nPage3AnchorTop);
+
+ // Check that the split fly frames, that are all registered at the same
(first fly's) anchor,
+ // are sorted there from precede to follow (previously, the order was the
opposite):
+ auto pRootAnchor = pPage3Fly->GetAnchorFrame(); // Unlike
FindAnchorCharFrame, this gives root
+ CPPUNIT_ASSERT(pRootAnchor);
+ CPPUNIT_ASSERT_EQUAL(pPage1Fly->GetAnchorFrame(), pRootAnchor);
+ const auto& rAnchoredObjects = *pRootAnchor->GetDrawObjs();
+ CPPUNIT_ASSERT_EQUAL(size_t(3), rAnchoredObjects.size());
+ CPPUNIT_ASSERT_EQUAL(static_cast<SwAnchoredObject*>(pPage1Fly),
rAnchoredObjects[0]);
+ CPPUNIT_ASSERT_EQUAL(static_cast<SwAnchoredObject*>(pPage2Fly),
rAnchoredObjects[1]);
+ CPPUNIT_ASSERT_EQUAL(static_cast<SwAnchoredObject*>(pPage3Fly),
rAnchoredObjects[2]);
}
CPPUNIT_TEST_FIXTURE(Test, testSplitFlyRow)
diff --git a/sw/source/core/inc/sortedobjs.hxx
b/sw/source/core/inc/sortedobjs.hxx
index 4ffcd69b3a24..395d7831a922 100644
--- a/sw/source/core/inc/sortedobjs.hxx
+++ b/sw/source/core/inc/sortedobjs.hxx
@@ -42,6 +42,8 @@ class SwAnchoredObject;
- order 1: to-paragraph, 2: to-character, 3: as-character
- anchor node position
- internal anchor order number
+ - split fly precede / follow relation
+ - order 1: precede, 2: follow
If one of the sort criteria attributes of an anchored object changes,
the sorting has to be updated - use method <Update(..)>
*/
diff --git a/sw/source/core/layout/sortedobjs.cxx
b/sw/source/core/layout/sortedobjs.cxx
index d15c4e79db2b..f74ba71b675b 100644
--- a/sw/source/core/layout/sortedobjs.cxx
+++ b/sw/source/core/layout/sortedobjs.cxx
@@ -21,6 +21,8 @@
#include <algorithm>
#include <anchoredobject.hxx>
+#include <flyfrm.hxx>
+#include <flyfrms.hxx>
#include <fmtanchr.hxx>
#include <fmtsrnd.hxx>
#include <fmtwrapinfluenceonobjpos.hxx>
@@ -198,7 +200,47 @@ struct ObjAnchorOrder
// objects anchored at the same content position/page/fly with same
// wrap influence.
// Thus, compare anchor order number
- return pAnchorListed->GetOrder() < pAnchorNew->GetOrder();
+ if (pAnchorListed->GetOrder() != pAnchorNew->GetOrder())
+ return pAnchorListed->GetOrder() < pAnchorNew->GetOrder();
+
+ // return true, when _pListedAnchoredObj is a precede split fly of
_pNewAnchoredObj
+ {
+ auto pLHFly = _pListedAnchoredObj->DynCastFlyFrame();
+ auto pLHSplitFly = pLHFly && pLHFly->IsFlySplitAllowed()
+ ? static_cast<const
SwFlyAtContentFrame*>(pLHFly)
+ : nullptr;
+ auto pRHFly = _pNewAnchoredObj->DynCastFlyFrame();
+ auto pRHSplitFly = pRHFly && pRHFly->IsFlySplitAllowed()
+ ? static_cast<const
SwFlyAtContentFrame*>(pRHFly)
+ : nullptr;
+
+ // split fly after others
+ if (!pLHSplitFly && pRHSplitFly)
+ return true;
+ if (pLHSplitFly && !pRHSplitFly)
+ return false;
+
+ if (pLHSplitFly && pRHSplitFly)
+ {
+ // standalone split fly after grouped
+ auto isInGroup
+ = [](const SwFlyAtContentFrame* p) { return p->HasFollow()
|| p->IsFollow(); };
+ if (isInGroup(pLHSplitFly) && !isInGroup(pRHSplitFly))
+ return true;
+ if (!isInGroup(pLHSplitFly) && isInGroup(pRHSplitFly))
+ return false;
+
+ if (pLHSplitFly->HasFollow() && pRHSplitFly->IsFollow())
+ {
+ for (auto p = pRHSplitFly->GetPrecede(); p; p =
p->GetPrecede())
+ {
+ if (p == pLHSplitFly)
+ return true;
+ }
+ }
+ }
+ }
+ return false;
}
};
commit aaa0ae4525556903b1135967e6f89b6a31069c87
Author: Mike Kaganski <[email protected]>
AuthorDate: Fri Feb 6 11:08:35 2026 +0500
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:06 2026 +0100
tdf#170630: consider not-yet-moved flys in cell height as "too high"
As the bugdoc demonstrated, it is not enough to split too high inner
floating table: after the split, the follow anchor and follow fly
may not cause the outer table to require an own split.
This change introduces a shortcut in CalcHeightWithFlys_Impl (used
to calculate cell heights considering anchored objects): if a lower
is a follow anchor with a follow fly that hasn't yet moved, do not
continue calculating accurate cell height, just return a huge height
of this lower. This means that cells with such not-yet-moved anchors
will never fit, and will always cause their table to be split. After
that, the heights will be calculated accurately.
Change-Id: Id81e69c08cfa58ffddfa771fa768f78735433d91
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198811
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <[email protected]>
Signed-off-by: Xisco Fauli <[email protected]>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198952
diff --git a/sw/qa/extras/layout/data/tdf170630.docx
b/sw/qa/extras/layout/data/tdf170630.docx
new file mode 100644
index 000000000000..99a8a8eb961d
Binary files /dev/null and b/sw/qa/extras/layout/data/tdf170630.docx differ
diff --git a/sw/qa/extras/layout/layout6.cxx b/sw/qa/extras/layout/layout6.cxx
index 9e7886f7768f..8a2a23af6634 100644
--- a/sw/qa/extras/layout/layout6.cxx
+++ b/sw/qa/extras/layout/layout6.cxx
@@ -2116,6 +2116,34 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6,
testTdf170620_float_table_after_keep_with_
assertXPath(pXmlDoc, aP1OuterFlyTab + "/row/cell/txt[2]/anchored/fly", 2);
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf170630)
+{
+ // Given a document with a keep-with-next paragraph, followed by floating
table containing
+ // two keep-with-next paragraphs and another floating table which is split
across pages:
+ createSwDoc("tdf170630.docx");
+
+ // The keep-with-next paragraph and the floating table must start on page
1:
+
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ CPPUNIT_ASSERT(pXmlDoc);
+
+ // Exactly two pages (without the fix, there was only one):
+ assertXPath(pXmlDoc, "//page", 2);
+
+ // "Keep-with-next paragraph" is on the first page:
+ assertXPath(pXmlDoc, "//page[1]/body/txt[2]//SwLineLayout", "portion",
+ u"Keep-with-next paragraph");
+
+ // Exactly two objects anchored at each page (without the fix, the first
page had three: one
+ // outer, and two inner, where the follow frame never moved forward):
+ assertXPath(pXmlDoc, "//page[1]/sorted_objs/fly", 2);
+ assertXPath(pXmlDoc, "//page[2]/sorted_objs/fly", 2);
+
+ // Page 1's paragraph 3 has two anchored flys (without the fix, it was
one: the outer table
+ // never split):
+ assertXPath(pXmlDoc, "//page[1]/body/txt[3]/anchored/fly", 2);
+}
+
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 9f25d14641e0..1a5d0c191aa5 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -4844,10 +4844,21 @@ static tools::Long CalcHeightWithFlys_Impl(const
SwFrame* pTmp, const SwFrame* p
{
// #i26945# - if <pTmp> is follow, the
// anchor character frame has to be <pTmp>.
- if ( bIsFollow &&
- pAnchoredObj->FindAnchorCharFrame() != pTmp )
+ if (bIsFollow)
{
- continue;
+ if (pAnchoredObj->FindAnchorCharFrame() != pTmp)
+ continue;
+
+ if (SwFlyFrame* pFly = pAnchoredObj->DynCastFlyFrame())
+ {
+ if (pFly->IsSplitButNotYetMovedFollow())
+ {
+ // A follow split fly, that is yet to move forward:
upper's height is not
+ // correct yet - just return a huge value to signal
"too large". This will
+ // eventually force split / move to the next page.
+ return SAL_MAX_INT32 / 2; // ~19 km
+ }
+ }
}
// #i26945# - consider also drawing objects
{
commit fcdad64c35d75dd48ee7a7d399a33fd6824ad052
Author: Mike Kaganski <[email protected]>
AuthorDate: Thu Feb 5 18:58:53 2026 +0500
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:05 2026 +0100
tdf#170620: CheckMoveFwd: only ignore empty master without split fly
SwFlowFrame::CheckMoveFwd decides if a keep-with-next paragraph should
move to next page. When bKeep is true, and the keep-with-next frame
is followed by an empty master, it ignores that empty master, and may
decide to move.
To check if the frame returned by GetIndNext was empty master, a call
to IsEmptyMaster was used. But that function doesn't consider if the
empty master (having a follow, but not having any text) is an anchor
of a split fly. The bugdoc demonstrated, that in such case, keep-with-
next frame would ignore the following split fly on the current page,
and will move forward; that would naturally move the split fly forward,
too.
This change improves the check to also use HasNonLastSplitFlyDrawObj.
Change-Id: I08771d7a3e48f88f4272ae8f1718615bc89a5bf4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198757
Reviewed-by: Mike Kaganski <[email protected]>
Tested-by: Jenkins
Signed-off-by: Xisco Fauli <[email protected]>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198951
diff --git a/sw/qa/extras/layout/data/tdf170620.docx
b/sw/qa/extras/layout/data/tdf170620.docx
new file mode 100644
index 000000000000..2565a36b4391
Binary files /dev/null and b/sw/qa/extras/layout/data/tdf170620.docx differ
diff --git a/sw/qa/extras/layout/layout6.cxx b/sw/qa/extras/layout/layout6.cxx
index 88fd08d5113e..9e7886f7768f 100644
--- a/sw/qa/extras/layout/layout6.cxx
+++ b/sw/qa/extras/layout/layout6.cxx
@@ -2049,6 +2049,73 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf170477)
calcLayout();
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter6,
testTdf170620_float_table_after_keep_with_next_para)
+{
+ // Given a document with a keep-with-next paragraph, followed by floating
table containing
+ // another floating table which is split across pages:
+ createSwDoc("tdf170620.docx");
+
+ // The keep-with-next paragraph and the floating table must start on page
1:
+
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ CPPUNIT_ASSERT(pXmlDoc);
+
+ // Exactly two pages:
+ assertXPath(pXmlDoc, "//page", 2);
+
+ // "Keep-with-next paragraph" is on the first page:
+ assertXPath(pXmlDoc, "//page[1]/body/txt[2]//SwLineLayout", "portion",
+ u"Keep-with-next paragraph");
+
+ // Exactly two objects anchored at each page:
+ assertXPath(pXmlDoc, "//page[1]/sorted_objs/fly", 2);
+ assertXPath(pXmlDoc, "//page[2]/sorted_objs/fly", 2);
+
+ // Get master/follow paragraph isd:
+ assertXPath(pXmlDoc, "//page[1]/body/txt", 3);
+ assertXPath(pXmlDoc, "//page[2]/body/txt", 1);
+ assertXPath(pXmlDoc, "//page[1]/body/txt[3]", "follow",
+ getXPath(pXmlDoc, "//page[2]/body/txt", "id"));
+ assertXPath(pXmlDoc, "//page[2]/body/txt", "precede",
+ getXPath(pXmlDoc, "//page[1]/body/txt[3]", "id"));
+
+ // Page 1's paragraph 3 has two anchored flys:
+ assertXPath(pXmlDoc, "//page[1]/body/txt[3]/anchored/fly", 2);
+
+ // Get the ids of the two outer flys.
+ // Page 1:
+ OString f1 = getXPath(pXmlDoc, "//page[1]/sorted_objs/fly[1]",
"ptr").toUtf8();
+ OString f2 = getXPath(pXmlDoc, "//page[1]/sorted_objs/fly[2]",
"ptr").toUtf8();
+ CPPUNIT_ASSERT(f1 != f2);
+ OString filter1 = "@ptr='" + f1 + "' or @ptr='" + f2 + "'";
+ OUString id = getXPath(pXmlDoc, "//page[1]/body/txt[3]/anchored/fly[" +
filter1 + "]", "id");
+ OString aP1OuterFlyTab = "//anchored/fly[@id='" + id.toUtf8() + "']/tab";
+
+ // Page 2:
+ f1 = getXPath(pXmlDoc, "//page[2]/sorted_objs/fly[1]", "ptr").toUtf8();
+ f2 = getXPath(pXmlDoc, "//page[2]/sorted_objs/fly[2]", "ptr").toUtf8();
+ CPPUNIT_ASSERT(f1 != f2);
+ OString filter2 = "@ptr='" + f1 + "' or @ptr='" + f2 + "'";
+ id = getXPath(pXmlDoc, "//page[1]/body/txt[3]/anchored/fly[" + filter2 +
"]", "id");
+ OString aP2OuterFlyTab = "//anchored/fly[@id='" + id.toUtf8() + "']/tab";
+
+ // One row in top-level floating table on page 1, four rows on page 2:
+ assertXPath(pXmlDoc, aP1OuterFlyTab + "/row", 1);
+ assertXPath(pXmlDoc, aP2OuterFlyTab + "/row", 4);
+
+ // One cell in top-level floating table on page 1, four cells on page 2:
+ assertXPath(pXmlDoc, aP1OuterFlyTab + "/row/cell", 1);
+ assertXPath(pXmlDoc, aP2OuterFlyTab + "/row/cell", 4);
+
+ // First page's top-level floating table's cell has two paragraphs:
+ assertXPath(pXmlDoc, aP1OuterFlyTab + "/row/cell/txt", 2);
+ // Check text in the first paragraph:
+ assertXPath(pXmlDoc, aP1OuterFlyTab + "/row/cell/txt[1]//SwLineLayout",
"portion",
+ u"Something");
+ // The second paragraph has two attached inner floating tables:
+ assertXPath(pXmlDoc, aP1OuterFlyTab + "/row/cell/txt[2]/anchored/fly", 2);
+}
+
} // end of anonymous namespace
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/layout/flowfrm.cxx
b/sw/source/core/layout/flowfrm.cxx
index 441da753f810..33f6dc793c04 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -1995,10 +1995,23 @@ bool SwFlowFrame::CheckMoveFwd( bool& rbMakePage, bool
bKeep, bool bIgnoreMyOwnK
{
if (m_rThis.IsHiddenNow())
return false;
- const SwFrame* pNxt = m_rThis.GetIndNext();
+ auto isIgnoredIndNext = [](const SwFrame* pNxt)
+ {
+ if (!pNxt)
+ return true;
+ // We ignore non-null next, when it's empty master, than doesn't host
a split fly:
+ if (pNxt->IsTextFrame())
+ {
+ auto pTextFrame = static_cast<const SwTextFrame*>(pNxt);
+ if (pTextFrame->IsEmptyMaster() &&
!pTextFrame->HasNonLastSplitFlyDrawObj())
+ return true;
+ }
+ return false;
+ };
- if ( bKeep && //!bMovedBwd &&
- ( !pNxt || ( pNxt->IsTextFrame() && static_cast<const
SwTextFrame*>(pNxt)->IsEmptyMaster() ) ) &&
+ if ( const SwFrame* pNxt;
+ bKeep && //!bMovedBwd &&
+ isIgnoredIndNext(m_rThis.GetIndNext()) &&
( nullptr != (pNxt = m_rThis.FindNext()) ) &&
IsKeepFwdMoveAllowed(bIgnoreMyOwnKeepValue) )
{
if( pNxt->IsSctFrame() )
commit 6ac299dd0e988ba210d726786173638a8353e34f
Author: Miklos Vajna <[email protected]>
AuthorDate: Thu Feb 5 15:13:12 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:05 2026 +0100
cool#13988 sw redline render mode: handle number portions
Open the bugdoc, switch to non-standard redline render mode (e.g.
dispatch .uno:RedlineRenderMode), the "2." number portion is still
underlined, while this mode doesn't underline insertions otherwise.
The reason this happens is because number portions don't decide redline
coloring/markup at render time, like SwTextPainter::DrawTextLine()
does, instead the font to be used is decided earlier at layout time in
SwTextFormatter::NewNumberPortion().
Fix the problem by creating two fonts in
SwTextFormatter::NewNumberPortion(), one without the redline markup and
one with it. And then later in SwNumberPortion::Paint() use the font
that matches the current rendline render mode. This works, because
changing the redline render mode means SwNumberPortion::Paint() will be
invoked, but the layout's portions won't be re-created for performance
reasons.
Note that similar to table redlines, this just disables the unwanted
standard redline render decoration. That is probably fine, since the
surrounding "real" text is still colored gray/red/green. But we possibly
this can be improved in the future to apply similar coloring even for
the number portion.
Change-Id: I16b4123d20bf0c14c76bb23e574eb21a719d15df
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198822
Reviewed-by: Miklos Vajna <[email protected]>
Tested-by: Jenkins
(cherry picked from commit e609c44293ca7ba5658459aec15b6b084cb1bfd1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198957
Reviewed-by: Xisco Fauli <[email protected]>
diff --git a/sw/CppunitTest_sw_core_text.mk b/sw/CppunitTest_sw_core_text.mk
index 42be7e727b0c..e90c77e5f38f 100644
--- a/sw/CppunitTest_sw_core_text.mk
+++ b/sw/CppunitTest_sw_core_text.mk
@@ -18,6 +18,7 @@ $(eval $(call
gb_CppunitTest_add_exception_objects,sw_core_text, \
sw/qa/core/text/itratr \
sw/qa/core/text/itrpaint \
sw/qa/core/text/itrform2 \
+ sw/qa/core/text/porfld \
sw/qa/core/text/porlay \
sw/qa/core/text/porrst \
sw/qa/core/text/text \
diff --git a/sw/qa/core/text/data/redline-number-portion.docx
b/sw/qa/core/text/data/redline-number-portion.docx
new file mode 100644
index 000000000000..26ba473e8085
Binary files /dev/null and b/sw/qa/core/text/data/redline-number-portion.docx
differ
diff --git a/sw/qa/core/text/porfld.cxx b/sw/qa/core/text/porfld.cxx
new file mode 100644
index 000000000000..6ab3d3f3c550
--- /dev/null
+++ b/sw/qa/core/text/porfld.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <memory>
+
+#include <vcl/gdimtf.hxx>
+
+#include <docsh.hxx>
+#include <wrtsh.hxx>
+
+namespace
+{
+/// Covers sw/source/core/text/porfld.cxx fixes.
+class Test : public SwModelTestBase
+{
+public:
+ Test()
+ : SwModelTestBase(u"/sw/qa/core/text/data/"_ustr)
+ {
+ }
+};
+
+CPPUNIT_TEST_FIXTURE(Test, testNumberPortionRedlineRenderMode)
+{
+ // Given a document with redlines, the "2." number portion is inserted:
+ createSwDoc("redline-number-portion.docx");
+
+ // When redline render mode is standard:
+ SwDocShell* pDocShell = getSwDocShell();
+ std::shared_ptr<GDIMetaFile> xMetaFile = pDocShell->GetPreviewMetaFile();
+
+ // Then make sure we paint an underline:
+ MetafileXmlDump aDumper;
+ xmlDocUniquePtr pXmlDoc = dumpAndParse(aDumper, *xMetaFile);
+ OUString aContent = getXPathContent(pXmlDoc, "(//textarray)[3]/text");
+ CPPUNIT_ASSERT_EQUAL(u"2."_ustr, aContent);
+ OUString aUnderline
+ = getXPath(pXmlDoc, "(//textarray)[3]/preceding-sibling::font[1]",
"underline");
+ CPPUNIT_ASSERT_EQUAL(u"1"_ustr, aUnderline);
+
+ // And given "omit inserts" redline render mode:
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ SwViewOption aOpt(*pWrtShell->GetViewOptions());
+ aOpt.SetRedlineRenderMode(SwRedlineRenderMode::OmitInserts);
+ pWrtShell->ApplyViewOptions(aOpt);
+
+ // When rendering:
+ xMetaFile = pDocShell->GetPreviewMetaFile();
+
+ // Then make sure we don't paint an underline:
+ pXmlDoc = dumpAndParse(aDumper, *xMetaFile);
+ aContent = getXPathContent(pXmlDoc, "(//textarray)[3]/text");
+ CPPUNIT_ASSERT_EQUAL(u"2."_ustr, aContent);
+ aUnderline = getXPath(pXmlDoc,
"(//textarray)[3]/preceding-sibling::font[1]", "underline");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 1
+ // i.e. there was an unexpected underline.
+ CPPUNIT_ASSERT_EQUAL(u"0"_ustr, aUnderline);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 47fbfc4b4335..109e86af965f 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -1267,7 +1267,7 @@ SwTextPortion *SwTextFormatter::WhichTextPor(
SwTextFormatInfo &rInf ) const
}
}
assert(2 <= sal_Int32(nFieldLen));
- pPor = new
SwFieldPortion(SwFieldType::GetTypeStr(SwFieldTypesEnum::Input), nullptr,
nFieldLen);
+ pPor = new
SwFieldPortion(SwFieldType::GetTypeStr(SwFieldTypesEnum::Input), nullptr,
nullptr, nFieldLen);
}
else
{
diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx
index f95b04c2009e..4eaa3cf0b187 100644
--- a/sw/source/core/text/porfld.cxx
+++ b/sw/source/core/text/porfld.cxx
@@ -79,8 +79,8 @@ void SwFieldPortion::TakeNextOffset( const SwFieldPortion*
pField )
m_bFollow = true;
}
-SwFieldPortion::SwFieldPortion(OUString aExpand, std::unique_ptr<SwFont>
pFont, TextFrameIndex const nFieldLen)
- : m_aExpand(std::move(aExpand)), m_pFont(std::move(pFont)),
m_nNextOffset(0)
+SwFieldPortion::SwFieldPortion(OUString aExpand, std::unique_ptr<SwFont>
pFont, std::unique_ptr<SwFont> pRedlineRenderModeFont, TextFrameIndex const
nFieldLen)
+ : m_aExpand(std::move(aExpand)), m_pFont(std::move(pFont)),
m_pRedlineRenderModeFont(std::move(pRedlineRenderModeFont)), m_nNextOffset(0)
, m_nNextScriptChg(COMPLETE_STRING), m_nFieldLen(nFieldLen),
m_nViewWidth(0)
, m_bFollow( false ), m_bLeft( false), m_bHide( false)
, m_bCenter (false), m_bHasFollow( false )
@@ -110,6 +110,8 @@ SwFieldPortion::SwFieldPortion( const SwFieldPortion&
rField )
{
if ( rField.HasFont() )
m_pFont.reset( new SwFont( *rField.GetFont() ) );
+ if (rField.m_pRedlineRenderModeFont)
+ m_pRedlineRenderModeFont.reset(new
SwFont(*rField.m_pRedlineRenderModeFont));
SetWhichPor( PortionType::Field );
}
@@ -520,6 +522,12 @@ void SwFieldPortion::dumpAsXml(xmlTextWriterPtr pWriter,
const OUString& rText,
{
m_pFont->dumpAsXml(pWriter);
}
+ if (m_pRedlineRenderModeFont)
+ {
+ (void)xmlTextWriterStartElement(pWriter,
BAD_CAST("redline-render-mode-font"));
+ m_pRedlineRenderModeFont->dumpAsXml(pWriter);
+ (void)xmlTextWriterEndElement(pWriter);
+ }
(void)xmlTextWriterEndElement(pWriter);
}
@@ -557,10 +565,11 @@ bool SwHiddenPortion::GetExpText( const SwTextSizeInfo
&rInf, OUString &rText )
SwNumberPortion::SwNumberPortion( const OUString &rExpand,
std::unique_ptr<SwFont> pFont,
+ std::unique_ptr<SwFont>
pRedlineRenderModeFont,
const bool bLft,
const bool bCntr, const SwTwips nMinDst,
const bool
bLabelAlignmentPosAndSpaceModeActive )
- : SwFieldPortion(rExpand, std::move(pFont), TextFrameIndex(0))
+ : SwFieldPortion(rExpand, std::move(pFont),
std::move(pRedlineRenderModeFont), TextFrameIndex(0))
, m_nFixWidth(0)
, m_nMinDist(nMinDst)
,
mbLabelAlignmentPosAndSpaceModeActive(bLabelAlignmentPosAndSpaceModeActive)
@@ -581,8 +590,11 @@ SwFieldPortion *SwNumberPortion::Clone( const OUString
&rExpand ) const
std::unique_ptr<SwFont> pNewFnt;
if( m_pFont )
pNewFnt.reset(new SwFont( *m_pFont ));
+ std::unique_ptr<SwFont> pNewRedlineRenderModeFont;
+ if (m_pRedlineRenderModeFont)
+ pNewRedlineRenderModeFont.reset(new SwFont(*m_pRedlineRenderModeFont));
- return new SwNumberPortion( rExpand, std::move(pNewFnt), IsLeft(),
IsCenter(),
+ return new SwNumberPortion( rExpand, std::move(pNewFnt),
std::move(pNewRedlineRenderModeFont), IsLeft(), IsCenter(),
m_nMinDist,
mbLabelAlignmentPosAndSpaceModeActive );
}
@@ -741,7 +753,17 @@ void SwNumberPortion::Paint( const SwTextPaintInfo &rInf )
const
STRIKEOUT_NONE != m_pFont->GetStrikeout() ) &&
!m_pFont->IsWordLineMode();
- SwFontSave aSave( rInf, m_pFont.get() );
+ const SwViewShell* pViewShell = rInf.GetVsh();
+ const SwViewOption* pViewOptions = pViewShell ?
pViewShell->GetViewOptions() : nullptr;
+ SwRedlineRenderMode eRedlineRenderMode = pViewOptions ?
pViewOptions->GetRedlineRenderMode() : SwRedlineRenderMode::Standard;
+ SwFont* pFont = m_pFont.get();
+ if (eRedlineRenderMode != SwRedlineRenderMode::Standard)
+ {
+ // Non-standard redline render mode: avoid using the font which is
decorated with
+ // underline/strike-through.
+ pFont = m_pRedlineRenderModeFont.get();
+ }
+ SwFontSave aSave(rInf, pFont);
if( m_nFixWidth == Width() && ! HasFollow() )
SwExpandPortion::Paint( rInf );
@@ -809,7 +831,7 @@ SwBulletPortion::SwBulletPortion( const sal_UCS4 cBullet,
const SwTwips nMinDst,
const bool
bLabelAlignmentPosAndSpaceModeActive )
: SwNumberPortion( OUString(&cBullet, 1) + rBulletFollowedBy,
- std::move(pFont), bLft, bCntr, nMinDst,
+ std::move(pFont), nullptr, bLft, bCntr, nMinDst,
bLabelAlignmentPosAndSpaceModeActive )
{
SetWhichPor( PortionType::Bullet );
@@ -823,7 +845,7 @@ SwGrfNumPortion::SwGrfNumPortion(
const SwFormatVertOrient* pGrfOrient, const Size& rGrfSize,
const bool bLft, const bool bCntr, const SwTwips nMinDst,
const bool bLabelAlignmentPosAndSpaceModeActive ) :
- SwNumberPortion( rGraphicFollowedBy, nullptr, bLft, bCntr, nMinDst,
+ SwNumberPortion( rGraphicFollowedBy, nullptr, nullptr, bLft, bCntr,
nMinDst,
bLabelAlignmentPosAndSpaceModeActive ),
m_pBrush( new SvxBrushItem(RES_BACKGROUND) ), m_nId( 0 )
{
diff --git a/sw/source/core/text/porfld.hxx b/sw/source/core/text/porfld.hxx
index da9624ffd854..8d31c000487b 100644
--- a/sw/source/core/text/porfld.hxx
+++ b/sw/source/core/text/porfld.hxx
@@ -39,6 +39,7 @@ class SwFieldPortion : public SwExpandPortion
protected:
OUString m_aExpand; // The expanded field
std::unique_ptr<SwFont> m_pFont; // For multi-line fields
+ std::unique_ptr<SwFont> m_pRedlineRenderModeFont;
TextFrameIndex m_nNextOffset; // Offset of the follow in the original
string
TextFrameIndex m_nNextScriptChg;
TextFrameIndex m_nFieldLen; //< Length of field text, 1 for normal fields,
any number for input fields
@@ -61,7 +62,7 @@ protected:
public:
SwFieldPortion( const SwFieldPortion& rField );
- SwFieldPortion(OUString aExpand, std::unique_ptr<SwFont> pFnt = nullptr,
TextFrameIndex nLen = TextFrameIndex(1));
+ SwFieldPortion(OUString aExpand, std::unique_ptr<SwFont> pFnt = nullptr,
std::unique_ptr<SwFont> pRedlineRenderModeFont = nullptr, TextFrameIndex nLen =
TextFrameIndex(1));
virtual ~SwFieldPortion() override;
void TakeNextOffset( const SwFieldPortion* pField );
@@ -141,6 +142,7 @@ protected:
public:
SwNumberPortion( const OUString &rExpand,
std::unique_ptr<SwFont> pFnt,
+ std::unique_ptr<SwFont> pRedlineRenderModeFont,
const bool bLeft,
const bool bCenter, const SwTwips nMinDst,
const bool bLabelAlignmentPosAndSpaceModeActive );
diff --git a/sw/source/core/text/porftn.hxx b/sw/source/core/text/porftn.hxx
index b22deb6ca4a2..32ae1ab4159b 100644
--- a/sw/source/core/text/porftn.hxx
+++ b/sw/source/core/text/porftn.hxx
@@ -54,7 +54,7 @@ class SwFootnoteNumPortion : public SwNumberPortion
{
public:
SwFootnoteNumPortion( const OUString &rExpand, std::unique_ptr<SwFont>
pFntL )
- : SwNumberPortion( rExpand, std::move(pFntL), true, false, 0, false )
+ : SwNumberPortion( rExpand, std::move(pFntL), nullptr, true, false,
0, false )
{ SetWhichPor( PortionType::FootnoteNum ); }
};
diff --git a/sw/source/core/text/txtfld.cxx b/sw/source/core/text/txtfld.cxx
index dbb178c66d10..4eb0934bd979 100644
--- a/sw/source/core/text/txtfld.cxx
+++ b/sw/source/core/text/txtfld.cxx
@@ -692,13 +692,21 @@ SwNumberPortion *SwTextFormatter::NewNumberPortion(
SwTextFormatInfo &rInf ) con
checkApplyParagraphMarkFormatToNumbering(pNumFnt.get(),
rInf, pIDSA, pFormat);
+ auto pNumRedlineRenderModeFont =
std::make_unique<SwFont>(*pNumFnt);
+
if ( !lcl_setRedlineAttr( rInf, *pTextNd, pNumFnt ) &&
bHasHiddenNum )
+ {
pNumFnt->SetColor(SwViewOption::GetCurrentViewOptions().GetNonPrintingCharacterColor());
+ pNumRedlineRenderModeFont->SetColor(
+
SwViewOption::GetCurrentViewOptions().GetNonPrintingCharacterColor());
+ }
// we do not allow a vertical font
pNumFnt->SetVertical( pNumFnt->GetOrientation(),
m_pFrame->IsVertical() );
+ pNumRedlineRenderModeFont->SetVertical(
+ pNumRedlineRenderModeFont->GetOrientation(),
m_pFrame->IsVertical());
- pRet = new SwNumberPortion( aTextNow, std::move(pNumFnt),
+ pRet = new SwNumberPortion( aTextNow, std::move(pNumFnt),
std::move(pNumRedlineRenderModeFont),
bLeft, bCenter, nMinDist,
bLabelAlignmentPosAndSpaceModeActive );
}
diff --git a/sw/source/core/txtnode/swfont.cxx
b/sw/source/core/txtnode/swfont.cxx
index 07dfef5d43c7..ef33a4e6bae8 100644
--- a/sw/source/core/txtnode/swfont.cxx
+++ b/sw/source/core/txtnode/swfont.cxx
@@ -365,6 +365,11 @@ void SwFont::dumpAsXml(xmlTextWriterPtr writer) const
ss << GetWeight();
(void)xmlTextWriterWriteAttribute(writer, BAD_CAST("weight"),
BAD_CAST(ss.str().c_str()));
}
+ {
+ std::stringstream ss;
+ ss << GetUnderline();
+ (void)xmlTextWriterWriteAttribute(writer, BAD_CAST("underline"),
BAD_CAST(ss.str().c_str()));
+ }
(void)xmlTextWriterEndElement(writer);
}
commit f21c9bbaa5f077fe134f61d181e3dec41e3fc83a
Author: Michael Weghorn <[email protected]>
AuthorDate: Mon Feb 9 13:40:13 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:05 2026 +0100
tdf#170603 vcl: Rework IconView entry width calculation
Instead of starting with an initial width of 100 pixels
for each vcl IconView entry (as set in the IconView ctor so
far), start with an initial entry width of 0 and update
the width in IconView::UpdateEntrySize to be large
enough for the newly inserted entry.
In IconView::UpdateEntrySize, calculate the
width and height by taking the new entry's data
into account, but at least keeping the previous size.
Ensure a minimum width of 100 if the item has any
text.
Also, call Resize() when the entry size was changed,
to ensure items are layed out using the new entry size.
This complements
commit 01d275a80da4a7d1e83fbcd728e1691f48593351
Author: Michael Weghorn <[email protected]>
Date: Thu Aug 7 10:17:57 2025 +0200
tdf#167658 Update vcl IconView entry size when inserting item
by restoring a minimum size of 100 pixels for the
IconView items in the Impress transition side bar panel
that contain text and ensuring items are layed out
according to the current entry size.
It also fixes the problem of the IconViews used for the
recently used and favorite special characters in the
special character dialogs become too large when there
is no entry yet, as the minimum size of 100 for the items
in each of the 16 columns used since
commit c184cd984865a0406940b9f39ac1cd538b922e8f
Author: Michael Weghorn <[email protected]>
Date: Sat Dec 20 22:25:15 2025 +0100
tdf#168594 tdf#119931 a11y special chars: Use IconView for
recent/favorites
would result in too much space getting allocated until
the first entry gets inserted (and item width got
recalculated).
Change-Id: I3fb98e82f462f293753c35617601dcf6fa8e92c9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198988
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <[email protected]>
(cherry picked from commit d41832024b5c69f096ffa323fb114b2fcd529b3e)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199010
Reviewed-by: Ilmari Lauhakangas <[email protected]>
diff --git a/vcl/inc/iconview.hxx b/vcl/inc/iconview.hxx
index bb18bedea45f..559a8d8444fe 100644
--- a/vcl/inc/iconview.hxx
+++ b/vcl/inc/iconview.hxx
@@ -56,8 +56,8 @@ public:
/// returns string with encoded image for an entry
OUString renderEntry(int pos, int dpix, int dpiy) const;
- /// Update entry size based on image size
- void UpdateEntrySize(const Image& rImage);
+ /// Update entry size based on the given entry's image size and text
+ void UpdateEntrySize(const SvTreeListEntry& rEntry);
protected:
virtual void CalcEntryHeight(SvTreeListEntry const* pEntry) override;
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 28c81ab62207..af023f86845e 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -5309,7 +5309,7 @@ void SalInstanceIconView::do_insert(int pos, const
OUString* pStr, const OUStrin
pEntry->SetUserData(pUserData);
m_xIconView->Insert(pEntry, nullptr, nInsertPos);
if (!m_bFixedItemWidth)
- m_xIconView->UpdateEntrySize(rImage);
+ m_xIconView->UpdateEntrySize(*pEntry);
if (pRet)
{
@@ -5534,7 +5534,7 @@ void SalInstanceIconView::set_image(int pos,
VirtualDevice& rIcon)
pItem->SetBitmap1(aImage);
pItem->SetBitmap2(aImage);
if (!m_bFixedItemWidth)
- m_xIconView->UpdateEntrySize(aImage);
+ m_xIconView->UpdateEntrySize(*pEntry);
m_xIconView->ModelHasEntryInvalidated(pEntry);
}
}
diff --git a/vcl/source/treelist/iconview.cxx b/vcl/source/treelist/iconview.cxx
index 5acb148688de..f6005b2e8ede 100644
--- a/vcl/source/treelist/iconview.cxx
+++ b/vcl/source/treelist/iconview.cxx
@@ -41,7 +41,7 @@ IconView::IconView(vcl::Window* pParent, WinBits nBits)
{
m_nColumnCount = 1;
mbCenterAndClipText = true;
- SetEntryWidth(100);
+ SetEntryWidth(0);
pImpl.reset(new IconViewImpl(this, GetModel(), GetStyle()));
}
@@ -59,11 +59,32 @@ void IconView::SetFixedColumnCount(short nColumnCount)
m_nColumnCount = nColumnCount;
}
-void IconView::UpdateEntrySize(const Image& rImage)
+void IconView::UpdateEntrySize(const SvTreeListEntry& rEntry)
{
+ const SvLBoxContextBmp* pBitmapItem
+ = static_cast<const
SvLBoxContextBmp*>(rEntry.GetFirstItem(SvLBoxItemType::ContextBmp));
+ const Size aImageSize = pBitmapItem ?
pBitmapItem->GetBitmap1().GetSizePixel() : Size();
+ // provide some minimum width if text exists (will be ellipsized if it
doesn't fit completely)
+ const tools::Long nMinTextWidth =
rEntry.GetFirstItem(SvLBoxItemType::String) ? 100 : 0;
+
int spacing = nSpacing * 2;
- SetEntryHeight(rImage.GetSizePixel().getHeight() + spacing);
- SetEntryWidth(rImage.GetSizePixel().getWidth() + spacing);
+ const short nMinHeight = aImageSize.getHeight() + spacing;
+ const short nMinWidth = std::max(aImageSize.getWidth() + spacing,
nMinTextWidth);
+
+ bool bChanged = false;
+ if (nMinWidth > GetEntryWidth())
+ {
+ SetEntryWidth(nMinWidth);
+ bChanged = true;
+ }
+ if (nMinHeight > GetEntryHeight())
+ {
+ SetEntryHeight(nMinHeight);
+ bChanged = true;
+ }
+
+ if (bChanged)
+ Resize();
}
bool IconView::HasSeparatorEntry() const
commit 4230a95f07e6f85bf8313c81bf28ec9309299cf8
Author: Michael Weghorn <[email protected]>
AuthorDate: Mon Feb 9 12:01:31 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:05 2026 +0100
vcl IconView: Use "p" instead of "a" prefix for pointers, etc
Adhere to variable naming convention:
"p" is for pointers, "r" for references.
Change-Id: I7ae102cea9ce4fd9cfd1c737634d59f1d7a50db2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198984
Reviewed-by: Michael Weghorn <[email protected]>
Tested-by: Jenkins
(cherry picked from commit f6d3bf57ebef5f6960087eb9261060f296ef1683)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199009
Reviewed-by: Ilmari Lauhakangas <[email protected]>
diff --git a/vcl/inc/iconview.hxx b/vcl/inc/iconview.hxx
index 67908deafe9d..bb18bedea45f 100644
--- a/vcl/inc/iconview.hxx
+++ b/vcl/inc/iconview.hxx
@@ -57,7 +57,7 @@ public:
OUString renderEntry(int pos, int dpix, int dpiy) const;
/// Update entry size based on image size
- void UpdateEntrySize(const Image& pImage);
+ void UpdateEntrySize(const Image& rImage);
protected:
virtual void CalcEntryHeight(SvTreeListEntry const* pEntry) override;
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index c2ec14eb68c3..28c81ab62207 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -5518,24 +5518,24 @@ OUString SalInstanceIconView::get_id(int pos) const
void SalInstanceIconView::set_image(int pos, VirtualDevice& rIcon)
{
- SvTreeListEntry* aEntry = m_xIconView->GetEntry(nullptr, pos);
- if (aEntry == nullptr)
+ SvTreeListEntry* pEntry = m_xIconView->GetEntry(nullptr, pos);
+ if (pEntry == nullptr)
return;
- SvLBoxContextBmp* aItem
- =
static_cast<SvLBoxContextBmp*>(aEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
+ SvLBoxContextBmp* pItem
+ =
static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
Image aImage = createImage(rIcon);
- if (aItem == nullptr)
+ if (pItem == nullptr)
{
- aEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aImage, aImage,
false));
+ pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aImage, aImage,
false));
}
else
{
- aItem->SetBitmap1(aImage);
- aItem->SetBitmap2(aImage);
+ pItem->SetBitmap1(aImage);
+ pItem->SetBitmap2(aImage);
if (!m_bFixedItemWidth)
m_xIconView->UpdateEntrySize(aImage);
- m_xIconView->ModelHasEntryInvalidated(aEntry);
+ m_xIconView->ModelHasEntryInvalidated(pEntry);
}
}
diff --git a/vcl/source/treelist/iconview.cxx b/vcl/source/treelist/iconview.cxx
index 3e65cf847a0b..5acb148688de 100644
--- a/vcl/source/treelist/iconview.cxx
+++ b/vcl/source/treelist/iconview.cxx
@@ -59,11 +59,11 @@ void IconView::SetFixedColumnCount(short nColumnCount)
m_nColumnCount = nColumnCount;
}
-void IconView::UpdateEntrySize(const Image& pImage)
+void IconView::UpdateEntrySize(const Image& rImage)
{
int spacing = nSpacing * 2;
- SetEntryHeight(pImage.GetSizePixel().getHeight() + spacing);
- SetEntryWidth(pImage.GetSizePixel().getWidth() + spacing);
+ SetEntryHeight(rImage.GetSizePixel().getHeight() + spacing);
+ SetEntryWidth(rImage.GetSizePixel().getWidth() + spacing);
}
bool IconView::HasSeparatorEntry() const
commit 2083739f3ecce899184b914728748996e16a25cd
Author: Xisco Fauli <[email protected]>
AuthorDate: Tue Feb 10 09:11:33 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:05 2026 +0100
libpng: upgrade to 1.6.55
Downloaded from
https://sourceforge.net/projects/libpng/files/libpng16/1.6.55/libpng-1.6.55.tar.xz/download
Change-Id: Ieef76e5e408add87ffdccfbfacbedc3ef58a5aea
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199022
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <[email protected]>
(cherry picked from commit e8572b7d946834c0f7775b0489327f7b9f62c69d)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199051
Reviewed-by: Michael Stahl <[email protected]>
diff --git a/download.lst b/download.lst
index 121d0d13d4ed..473ca0f2f103 100644
--- a/download.lst
+++ b/download.lst
@@ -657,8 +657,8 @@ PIXMAN_TARBALL := pixman-0.46.4.tar.xz
# three static lines
# so that git cherry-pick
# will not run into conflicts
-LIBPNG_SHA256SUM :=
01c9d8a303c941ec2c511c14312a3b1d36cedb41e2f5168ccdaa85d53b887805
-LIBPNG_TARBALL := libpng-1.6.54.tar.xz
+LIBPNG_SHA256SUM :=
d925722864837ad5ae2a82070d4b2e0603dc72af44bd457c3962298258b8e82d
+LIBPNG_TARBALL := libpng-1.6.55.tar.xz
# three static lines
# so that git cherry-pick
# will not run into conflicts
commit 1ede0b40703820373774c2c379d971c070542d66
Author: Xisco Fauli <[email protected]>
AuthorDate: Fri Feb 6 00:53:12 2026 +0100
Commit: Andras Timar <[email protected]>
CommitDate: Wed Feb 11 23:42:05 2026 +0100
poppler: upgrade to 26.02.0
* external/poppler/missinginclude.patch has been fixed upstream
Downloaded from https://poppler.freedesktop.org/poppler-26.02.0.tar.x
Change-Id: I7641b7b544e853a86563dbe312af4b36444dea8e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198803
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <[email protected]>
(cherry picked from commit 3c29b709cd2b5b18776b3c15638b66bd8a7dcb07)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198958
Reviewed-by: Caolán McNamara <[email protected]>
diff --git a/download.lst b/download.lst
index 0f035d0227d9..121d0d13d4ed 100644
--- a/download.lst
+++ b/download.lst
@@ -667,8 +667,8 @@ LIBTIFF_TARBALL := tiff-4.7.1.tar.xz
# three static lines
# so that git cherry-pick
# will not run into conflicts
-POPPLER_SHA256SUM :=
1cb944a4b88847f5fb6551683bc799db59f04990f5d8be07aba2acbf38601089
-POPPLER_TARBALL := poppler-26.01.0.tar.xz
+POPPLER_SHA256SUM :=
dded8621f7b2f695c91063aab1558691c8418374cd583501e89ed39487e7ab77
+POPPLER_TARBALL := poppler-26.02.0.tar.xz
POPPLER_DATA_SHA256SUM :=
c835b640a40ce357e1b83666aabd95edffa24ddddd49b8daff63adb851cdab74
POPPLER_DATA_TARBALL := poppler-data-0.4.12.tar.gz
# three static lines
diff --git a/external/poppler/disable-freetype.patch.1
b/external/poppler/disable-freetype.patch.1
index 98e00cd4b406..49a76ec41426 100644
--- a/external/poppler/disable-freetype.patch.1
+++ b/external/poppler/disable-freetype.patch.1
@@ -32,25 +32,25 @@ disable freetype dependent code
if (!filepath.ends_with(".ttf") && !filepath.ends_with(".ttc") &&
!filepath.ends_with(".otf")) {
error(errIO, -1, "We only support embedding ttf/ttc/otf fonts for
now. The font file for {0:s} {1:s} was {2:s}", fontFamily.c_str(),
fontStyle.c_str(), filepath.c_str());
return {};
-@@ -2994,6 +2996,7 @@
+@@ -2974,6 +2974,7 @@
}
- return { dictFontName, fontDictRef };
+ return { .fontName = dictFontName, .ref = fontDictRef };
+#endif
}
std::string Form::getFallbackFontForChar(Unicode uChar, const GfxFont
&fontToEmulate) const
--- poppler/splash/SplashFontEngine.cc.orig 2024-02-21 01:28:10.479645185
+0000
+++ popller/splash/SplashFontEngine.cc 2023-09-05 22:15:14.000000000 +0100
-@@ -66,7 +66,7 @@
+@@ -59,8 +59,6 @@
+ for (auto *font : fontCache) {
delete font;
}
-
+-
- delete ftEngine;
-+ //delete ftEngine;
}
- SplashFontFile *SplashFontEngine::getFontFile(const SplashFontFileID &id)
+ std::shared_ptr<SplashFontFile> SplashFontEngine::getFontFile(const
SplashFontFileID &id)
--- poppler/splash/SplashFTFontEngine.h.orig 2023-09-05 22:15:14.000000000
+0100
+++ poppler/splash/SplashFTFontEngine.h 2024-02-21 13:53:29.715423742
+0000
@@ -27,8 +27,6 @@
@@ -71,23 +71,23 @@ disable freetype dependent code
~SplashFTFontEngine();
-@@ -51,22 +49,20 @@
+@@ -49,22 +49,20 @@
SplashFTFontEngine &operator=(const SplashFTFontEngine &) = delete;
// Load fonts.
-- SplashFontFile *loadType1Font(std::unique_ptr<SplashFontFileID> idA,
SplashFontSrc *src, const char **enc, int faceIndex);
-- SplashFontFile *loadType1CFont(std::unique_ptr<SplashFontFileID> idA,
SplashFontSrc *src, const char **enc, int faceIndex);
-- SplashFontFile *loadOpenTypeT1CFont(std::unique_ptr<SplashFontFileID>
idA, SplashFontSrc *src, const char **enc, int faceIndex);
-- SplashFontFile *loadCIDFont(std::unique_ptr<SplashFontFileID> idA,
SplashFontSrc *src, int faceIndex);
-- SplashFontFile *loadOpenTypeCFFFont(std::unique_ptr<SplashFontFileID>
idA, SplashFontSrc *src, std::vector<int> &&codeToGID, int faceIndex);
-- SplashFontFile *loadTrueTypeFont(std::unique_ptr<SplashFontFileID> idA,
SplashFontSrc *src, std::vector<int> &&codeToGID, int faceIndex);
-+ SplashFontFile *loadType1Font(std::unique_ptr<SplashFontFileID> idA,
SplashFontSrc *src, const char **enc, int faceIndex) { return nullptr; };
-+ SplashFontFile *loadType1CFont(std::unique_ptr<SplashFontFileID> idA,
SplashFontSrc *src, const char **enc, int faceIndex) { return nullptr; };
-+ SplashFontFile *loadOpenTypeT1CFont(std::unique_ptr<SplashFontFileID>
idA, SplashFontSrc *src, const char **enc, int faceIndex) { return nullptr; };
-+ SplashFontFile *loadCIDFont(std::unique_ptr<SplashFontFileID> idA,
SplashFontSrc *src, int faceIndex) { return nullptr; };
-+ SplashFontFile *loadOpenTypeCFFFont(std::unique_ptr<SplashFontFileID>
idA, SplashFontSrc *src, std::vector<int> &&codeToGID, int faceIndex) { return
nullptr; };
-+ SplashFontFile *loadTrueTypeFont(std::unique_ptr<SplashFontFileID> idA,
SplashFontSrc *src, std::vector<int> &&codeToGID, int faceIndex) { return
nullptr; };
- bool getAA() { return aa; }
+- std::shared_ptr<SplashFontFile>
loadType1Font(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, const char **enc, int faceIndex);
+- std::shared_ptr<SplashFontFile>
loadType1CFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, const char **enc, int faceIndex);
+- std::shared_ptr<SplashFontFile>
loadOpenTypeT1CFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, const char **enc, int faceIndex);
+- std::shared_ptr<SplashFontFile>
loadCIDFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, int faceIndex);
+- std::shared_ptr<SplashFontFile>
loadOpenTypeCFFFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, std::vector<int> &&codeToGID, int
faceIndex);
+- std::shared_ptr<SplashFontFile>
loadTrueTypeFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, std::vector<int> &&codeToGID, int
faceIndex);
++ std::shared_ptr<SplashFontFile>
loadType1Font(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, const char **enc, int faceIndex) { return
nullptr; };
++ std::shared_ptr<SplashFontFile>
loadType1CFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, const char **enc, int faceIndex) { return
nullptr; };
++ std::shared_ptr<SplashFontFile>
loadOpenTypeT1CFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, const char **enc, int faceIndex) { return
nullptr; };
++ std::shared_ptr<SplashFontFile>
loadCIDFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, int faceIndex) { return nullptr; };
++ std::shared_ptr<SplashFontFile>
loadOpenTypeCFFFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, std::vector<int> &&codeToGID, int
faceIndex) { return nullptr; };
++ std::shared_ptr<SplashFontFile>
loadTrueTypeFont(std::unique_ptr<SplashFontFileID> idA,
std::unique_ptr<SplashFontSrc> src, std::vector<int> &&codeToGID, int
faceIndex) { return nullptr; };
+ bool getAA() const { return aa; }
void setAA(bool aaA) { aa = aaA; }
private:
diff --git a/external/poppler/poppler-config.patch.1
b/external/poppler/poppler-config.patch.1
index edf04d4af2ef..53685b1c8712 100644
--- a/external/poppler/poppler-config.patch.1
+++ b/external/poppler/poppler-config.patch.1
-e
... etc. - the rest is truncated