basic/qa/basic_coverage/test_cdbl_method.bas               |   42 +-
 basic/qa/vba_tests/cdbl.vb                                 |    5 
 basic/source/runtime/methods1.cxx                          |    2 
 basic/source/runtime/stdobj.cxx                            |    2 
 basic/source/sbx/sbxscan.cxx                               |    3 
 basic/source/sbx/sbxvar.cxx                                |    5 
 canvas/source/vcl/canvashelper_texturefill.cxx             |   12 
 configure.ac                                               |   31 +
 dbaccess/source/ui/querydesign/QueryTextView.cxx           |    1 
 distro-configs/Jenkins/linux_clang_dbgutil_64              |    1 
 emfio/qa/cppunit/emf/EmfImportTest.cxx                     |   11 
 include/svl/srchitem.hxx                                   |    3 
 include/tools/cpuid.hxx                                    |    2 
 include/tools/simdsupport.hxx                              |   41 +-
 include/vcl/gdimtf.hxx                                     |    2 
 sc/Library_sc.mk                                           |   13 
 sc/inc/arraysumfunctor.hxx                                 |   30 +
 sc/inc/arraysumfunctorinternal.hxx                         |   36 --
 sc/inc/clipcontext.hxx                                     |   11 
 sc/inc/column.hxx                                          |    2 
 sc/inc/document.hxx                                        |   28 +
 sc/inc/kahan.hxx                                           |    8 
 sc/qa/uitest/calc_tests/autofill.py                        |   30 +
 sc/qa/uitest/data/autofill.ods                             |binary
 sc/qa/unit/functions_statistical.cxx                       |   22 -
 sc/qa/unit/ucalc_copypaste.cxx                             |    2 
 sc/source/core/data/clipcontext.cxx                        |    8 
 sc/source/core/data/column2.cxx                            |    7 
 sc/source/core/data/column3.cxx                            |   25 +
 sc/source/core/data/column4.cxx                            |   56 ++-
 sc/source/core/data/document.cxx                           |   22 -
 sc/source/core/data/table2.cxx                             |    7 
 sc/source/core/data/table4.cxx                             |   20 -
 sc/source/core/tool/arraysum.hxx                           |   18 -
 sc/source/core/tool/arraysumAVX.cxx                        |  121 -------
 sc/source/core/tool/arraysumAVX512.cxx                     |  120 -------
 sc/source/core/tool/arraysumSSE2.cxx                       |   20 -
 sc/source/core/tool/interpr1.cxx                           |   39 +-
 sc/source/ui/inc/undoblk.hxx                               |    4 
 sc/source/ui/inc/viewfunc.hxx                              |   30 +
 sc/source/ui/undo/undoblk.cxx                              |    2 
 sc/source/ui/view/viewfun3.cxx                             |   38 +-
 sd/inc/Outliner.hxx                                        |    2 
 sd/qa/uitest/findReplace/findReplace.py                    |    7 
 sd/source/core/CustomAnimationEffect.cxx                   |    1 
 sd/source/ui/animations/CustomAnimationList.cxx            |   13 
 sd/source/ui/animations/CustomAnimationPane.cxx            |   36 ++
 sd/source/ui/view/Outliner.cxx                             |   21 -
 sdext/source/pdfimport/inc/wrapper.hxx                     |   12 
 sdext/source/pdfimport/wrapper/wrapper.cxx                 |   26 +
 shell/source/unix/exec/shellexec.cxx                       |    1 
 solenv/flatpak-manifest.in                                 |    1 
 solenv/gdb/libreoffice/sw.py                               |   15 
 svl/source/items/srchitem.cxx                              |   21 -
 svtools/source/control/ctrltool.cxx                        |    2 
 svx/source/unodraw/UnoGraphicExporter.cxx                  |   92 ++---
 svx/source/unodraw/unoshtxt.cxx                            |    5 
 sw/qa/core/layout/data/double-border-horizontal.docx       |binary
 sw/qa/core/layout/data/double-border-vertical.docx         |binary
 sw/qa/core/layout/data/double-page-border.docx             |binary
 sw/qa/core/layout/data/inner-border.docx                   |binary
 sw/qa/core/layout/data/para-border-in-cell-clip.docx       |binary
 sw/qa/core/layout/layout.cxx                               |  217 +++++++++++++
 sw/qa/extras/ooxmlexport/data/tdf126287.docx               |binary
 sw/qa/extras/ooxmlexport/data/tdf132752.docx               |binary
 sw/qa/extras/ooxmlexport/data/testParaListRightIndent.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlexport16.cxx                 |   32 +
 sw/qa/extras/ooxmlexport/ooxmlexport17.cxx                 |   13 
 sw/qa/extras/uiwriter/uiwriter3.cxx                        |   65 +++
 sw/qa/extras/uiwriter/uiwriter4.cxx                        |  197 +++++++++++
 sw/source/core/doc/DocumentRedlineManager.cxx              |    3 
 sw/source/core/edit/edredln.cxx                            |   46 ++
 sw/source/core/layout/paintfrm.cxx                         |  153 +++++++--
 sw/source/core/layout/tabfrm.cxx                           |    7 
 sw/source/filter/ww8/wrtw8sty.cxx                          |   28 -
 sw/source/filter/ww8/wrtww8.hxx                            |    4 
 sw/source/ui/frmdlg/frmpage.cxx                            |   10 
 sw/source/uibase/dochdl/swdtflvr.cxx                       |  123 ++++++-
 sw/source/uibase/inc/swdtflvr.hxx                          |    7 
 sw/source/uibase/uiview/view2.cxx                          |   14 
 sw/uiconfig/swriter/ui/frmtypepage.ui                      |    4 
 vcl/qa/cppunit/pdfexport/pdfexport.cxx                     |   42 ++
 vcl/source/gdi/gdimtf.cxx                                  |  100 ++---
 vcl/source/gdi/impgraph.cxx                                |   27 -
 vcl/source/gdi/pdfwriter_impl.cxx                          |    2 
 vcl/unx/gtk3/gtkinst.cxx                                   |   51 ++-
 wizards/source/scriptforge/SF_Utils.xba                    |    3 
 writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx |   28 +
 writerfilter/qa/cppunittests/dmapper/data/paste-ole.rtf    |   30 +
 writerfilter/source/dmapper/DomainMapper.cxx               |   44 ++
 writerfilter/source/dmapper/DomainMapper_Impl.cxx          |  116 ++++++
 writerfilter/source/dmapper/DomainMapper_Impl.hxx          |    4 
 xmloff/qa/unit/data/table-in-shape.fodt                    |   22 +
 xmloff/qa/unit/draw.cxx                                    |   24 +
 xmloff/source/draw/ximpshap.cxx                            |    4 
 95 files changed, 1734 insertions(+), 823 deletions(-)

New commits:
commit 1bb82a29b464f494a423aad38e3279f3e528c9aa
Author:     Armin Le Grand (Allotropia) <armin.le.gr...@me.com>
AuthorDate: Mon Jan 31 19:44:19 2022 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:06 2022 +0100

    tdf#126319 Corrected bitmap creation from metafile
    
    The conversion from Metafile to Bitmap in GraphicExporter
    is based on metafiles which does just not deliver enough
    precision when getting the bounds to do the correct size
    calculation for the target Bitmap.
    So I changed that to use Primitive functionality what
    produces better data. That old fix/correction itself was
    based on hairlines only which is anyways no longer
    sufficient since LO uses less hairlines nowadays, what
    is good in general (They are a relic of non-AA times
    when it was not possible to paint/work with lines taller
    than one pixel).
    Thus, cases need to be solved more generic based on
    better data. It would also be good to change this
    to primitives completely, but that is too much for now.
    
    Change-Id: I71bd136b106ef8ff3ba51458c46df08269773c01
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129235
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@me.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129810

diff --git a/include/vcl/gdimtf.hxx b/include/vcl/gdimtf.hxx
index 614d77369d1f..f8637675482d 100644
--- a/include/vcl/gdimtf.hxx
+++ b/include/vcl/gdimtf.hxx
@@ -125,7 +125,7 @@ public:
      * - coordinates of actions will be transformed to preferred mapmode
      * - the returned rectangle is relative to the preferred mapmode of the 
metafile
     */
-    tools::Rectangle       GetBoundRect( OutputDevice& i_rReference, 
tools::Rectangle* pHairline = nullptr ) const;
+    tools::Rectangle       GetBoundRect( OutputDevice& i_rReference ) const;
 
     void            Adjust( short nLuminancePercent, short nContrastPercent,
                             short nChannelRPercent = 0,  short 
nChannelGPercent = 0,
diff --git a/svx/source/unodraw/UnoGraphicExporter.cxx 
b/svx/source/unodraw/UnoGraphicExporter.cxx
index d6029dde6d29..b807154f9d67 100644
--- a/svx/source/unodraw/UnoGraphicExporter.cxx
+++ b/svx/source/unodraw/UnoGraphicExporter.cxx
@@ -178,7 +178,7 @@ namespace {
 
     /** creates a bitmap that is optionally transparent from a metafile
     */
-    BitmapEx GetBitmapFromMetaFile( const GDIMetaFile& rMtf,bool bIsSelection, 
const Size* pSize )
+    BitmapEx GetBitmapFromMetaFile( const GDIMetaFile& rMtf, const Size* pSize 
)
     {
         // use new primitive conversion tooling
         basegfx::B2DRange aRange(basegfx::B2DPoint(0.0, 0.0));
@@ -204,55 +204,7 @@ namespace {
             aRange.expand(basegfx::B2DPoint(aSize100th.Width(), 
aSize100th.Height()));
         }
 
-        // get hairline and full bound rect to evtl. correct logic size by the
-        // equivalent of one pixel to make those visible at right and bottom
-        tools::Rectangle aHairlineRect;
-        const tools::Rectangle 
aRect(rMtf.GetBoundRect(*Application::GetDefaultDevice(), &aHairlineRect));
-
-        if(!aRect.IsEmpty())
-        {
-            GDIMetaFile aMtf(rMtf);
-
-            if (bIsSelection)
-            {
-                // tdf#105998 Correct the Metafile using information from it's 
real sizes measured
-                // using rMtf.GetBoundRect above and a copy
-                const Size aOnePixelInMtf(
-                    Application::GetDefaultDevice()->PixelToLogic(
-                        Size(1, 1),
-                        rMtf.GetPrefMapMode()));
-                const Size aHalfPixelInMtf(
-                    (aOnePixelInMtf.getWidth() + 1) / 2,
-                    (aOnePixelInMtf.getHeight() + 1) / 2);
-
-                // tdf#126319 take bounds into account individually
-                const bool bHairlineRight(!aHairlineRect.IsEmpty() && 
aRect.Right() == aHairlineRect.Right());
-                const bool bHairlineBottom(!aHairlineRect.IsEmpty() && 
aRect.Bottom() == aHairlineRect.Bottom());
-                const bool bHairlineLeft(!aHairlineRect.IsEmpty() && 
aRect.Left() == aHairlineRect.Left());
-                const bool bHairlineTop(!aHairlineRect.IsEmpty() && 
aRect.Top() == aHairlineRect.Top());
-
-                // tdf#126319 Move the content dependent on Top/Left hairline
-                aMtf.Move(
-                    (bHairlineLeft ? -aHalfPixelInMtf.getWidth() : 
aHalfPixelInMtf.getWidth()),
-                    (bHairlineTop ? -aHalfPixelInMtf.getHeight() : 
aHalfPixelInMtf.getHeight()));
-
-                // Do not Scale, but set the PrefSize. Some levels deeper the
-                // MetafilePrimitive will add a mapping to the decomposition
-                // (and possibly a clipping) to map the graphic content to
-                // a unit coordinate system.
-                // tdf#126319 Size is the previous already correct size plus 
one
-                // pixel if needed (dependent on Righ/Bottom hairline) and the
-                // already moved half pixel from above
-                aMtf.SetPrefSize(
-                    Size(
-                        aMtf.GetPrefSize().Width() + (bHairlineRight ? 
aHalfPixelInMtf.getWidth() : 0),
-                        aMtf.GetPrefSize().Height() + (bHairlineBottom ? 
aHalfPixelInMtf.getHeight() : 0)));
-            }
-
-            return convertMetafileToBitmapEx(aMtf, aRange, 
nMaximumQuadraticPixels);
-        }
-
-        return BitmapEx();
+        return convertMetafileToBitmapEx(rMtf, aRange, 
nMaximumQuadraticPixels);
     }
 
     Size* CalcSize( sal_Int32 nWidth, sal_Int32 nHeight, const Size& 
aBoundSize, Size& aOutSize )
@@ -779,7 +731,7 @@ bool GraphicExporter::GetGraphic( ExportSettings const & 
rSettings, Graphic& aGr
                 if( rSettings.mbTranslucent )
                 {
                     Size aOutSize;
-                    aGraphic = GetBitmapFromMetaFile( 
aGraphic.GetGDIMetaFile(), false, CalcSize( rSettings.mnWidth, 
rSettings.mnHeight, aNewSize, aOutSize ) );
+                    aGraphic = GetBitmapFromMetaFile( 
aGraphic.GetGDIMetaFile(), CalcSize( rSettings.mnWidth, rSettings.mnHeight, 
aNewSize, aOutSize ) );
                 }
             }
         }
@@ -903,16 +855,22 @@ bool GraphicExporter::GetGraphic( ExportSettings const & 
rSettings, Graphic& aGr
             ScopedVclPtrInstance< VirtualDevice > aOut;
 
             // calculate bound rect for all shapes
-            tools::Rectangle aBound;
+            // tdf#126319 I did not convert all rendering to primities,
+            // that would be to much for this fix. But I  did so for the
+            // range calculation to get a valid high quality range.
+            // Based on that the conversion is reliable. With the BoundRect
+            // fetched from the Metafile it was just not possible to get the
+            // examples from the task handled in a way to fit all cases -
+            // due to bad-quality range data from it.
+            basegfx::B2DRange aBound;
+            const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
 
             {
                 for( SdrObject* pObj : aShapes )
                 {
-                    tools::Rectangle aR1(pObj->GetCurrentBoundRect());
-                    if (aBound.IsEmpty())
-                        aBound=aR1;
-                    else
-                        aBound.Union(aR1);
+                    drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                    aSequence = 
pObj->GetViewContact().getViewIndependentPrimitive2DContainer();
+                    aBound.expand(aSequence.getB2DRange(aViewInformation2D));
                 }
             }
 
@@ -926,7 +884,20 @@ bool GraphicExporter::GetGraphic( ExportSettings const & 
rSettings, Graphic& aGr
             aMtf.Record( aOut );
 
             MapMode aOutMap( aMap );
-            aOutMap.SetOrigin( Point( -aBound.Left(), -aBound.Top() ) );
+            const Size aOnePixelInMtf(
+                Application::GetDefaultDevice()->PixelToLogic(
+                    Size(1, 1),
+                    aMap));
+            const Size aHalfPixelInMtf(
+                (aOnePixelInMtf.getWidth() + 1) / 2,
+                (aOnePixelInMtf.getHeight() + 1) / 2);
+
+            // tdf#126319 Immediately add needed offset to create metafile,
+            // that avoids to do it later by Metafile::Move what would be 
expensive
+            aOutMap.SetOrigin(
+                Point(
+                    basegfx::fround(-aBound.getMinX() - 
aHalfPixelInMtf.getWidth()),
+                    basegfx::fround(-aBound.getMinY() - 
aHalfPixelInMtf.getHeight()) ) );
             aOut->SetRelativeMapMode( aOutMap );
 
             sdr::contact::DisplayInfo aDisplayInfo;
@@ -955,9 +926,10 @@ bool GraphicExporter::GetGraphic( ExportSettings const & 
rSettings, Graphic& aGr
             aMtf.Stop();
             aMtf.WindStart();
 
-            const Size  aExtSize( aOut->PixelToLogic( Size( 0, 0  ) ) );
-            Size        aBoundSize( aBound.GetWidth() + ( aExtSize.Width() ),
-                                    aBound.GetHeight() + ( aExtSize.Height() ) 
);
+            // tdf#126319 Immediately add needed size to target's PrefSize
+            const Size aBoundSize(
+                basegfx::fround(aBound.getWidth() + 
aHalfPixelInMtf.getWidth()),
+                basegfx::fround(aBound.getHeight() + 
aHalfPixelInMtf.getHeight()));
 
             aMtf.SetPrefMapMode( aMap );
             aMtf.SetPrefSize( aBoundSize );
@@ -965,7 +937,7 @@ bool GraphicExporter::GetGraphic( ExportSettings const & 
rSettings, Graphic& aGr
             if( !bVectorType )
             {
                 Size aOutSize;
-                aGraphic = GetBitmapFromMetaFile( aMtf, true, CalcSize( 
rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) );
+                aGraphic = GetBitmapFromMetaFile( aMtf, CalcSize( 
rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) );
             }
             else
             {
diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx
index 105798f51446..5aba0452296e 100644
--- a/vcl/source/gdi/gdimtf.cxx
+++ b/vcl/source/gdi/gdimtf.cxx
@@ -1277,8 +1277,7 @@ void GDIMetaFile::Rotate( Degree10 nAngle10 )
 
 static void ImplActionBounds( tools::Rectangle& o_rOutBounds,
                               const tools::Rectangle& i_rInBounds,
-                              const std::vector<tools::Rectangle>& 
i_rClipStack,
-                              tools::Rectangle* o_pHairline )
+                              const std::vector<tools::Rectangle>& 
i_rClipStack )
 {
     tools::Rectangle aBounds( i_rInBounds );
     if( ! i_rInBounds.IsEmpty() && ! i_rClipStack.empty() && ! 
i_rClipStack.back().IsEmpty() )
@@ -1290,17 +1289,9 @@ static void ImplActionBounds( tools::Rectangle& 
o_rOutBounds,
         o_rOutBounds.Union( aBounds );
     else
         o_rOutBounds = aBounds;
-
-    if(o_pHairline)
-    {
-        if( ! o_pHairline->IsEmpty() )
-            o_pHairline->Union( aBounds );
-        else
-            *o_pHairline = aBounds;
-    }
 }
 
-tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference, 
tools::Rectangle* pHairline ) const
+tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& i_rReference ) const
 {
     ScopedVclPtrInstance< VirtualDevice > aMapVDev(  i_rReference  );
 
@@ -1311,17 +1302,12 @@ tools::Rectangle GDIMetaFile::GetBoundRect( 
OutputDevice& i_rReference, tools::R
     std::vector<vcl::PushFlags> aPushFlagStack;
 
     tools::Rectangle aBound;
-
-    if(pHairline)
-        *pHairline = tools::Rectangle();
-
     const sal_uLong nCount(GetActionSize());
 
     for(sal_uLong a(0); a < nCount; a++)
     {
         MetaAction* pAction = GetAction(a);
         const MetaActionType nActionType = pAction->GetType();
-        tools::Rectangle* pUseHairline = (pHairline && 
aMapVDev->IsLineColor()) ? pHairline : nullptr;
 
         switch( nActionType )
         {
@@ -1331,7 +1317,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
             ImplActionBounds( aBound,
                               tools::Rectangle( OutputDevice::LogicToLogic( 
pAct->GetPoint(), aMapVDev->GetMapMode(), GetPrefMapMode() ),
                                        aMapVDev->PixelToLogic( Size( 1, 1 ), 
GetPrefMapMode() ) ),
-                             aClipStack, pUseHairline );
+                             aClipStack );
         }
         break;
 
@@ -1341,7 +1327,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
             ImplActionBounds( aBound,
                               tools::Rectangle( OutputDevice::LogicToLogic( 
pAct->GetPoint(), aMapVDev->GetMapMode(), GetPrefMapMode() ),
                                        aMapVDev->PixelToLogic( Size( 1, 1 ), 
GetPrefMapMode() ) ),
-                             aClipStack, pUseHairline );
+                             aClipStack );
         }
         break;
 
@@ -1352,36 +1338,28 @@ tools::Rectangle GDIMetaFile::GetBoundRect( 
OutputDevice& i_rReference, tools::R
             tools::Rectangle aRect( aP1, aP2 );
             aRect.Justify();
 
-            if(pUseHairline)
-            {
-                const LineInfo& rLineInfo = pAct->GetLineInfo();
-
-                if(0 != rLineInfo.GetWidth())
-                    pUseHairline = nullptr;
-            }
-
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
         case MetaActionType::RECT:
         {
             MetaRectAction* pAct = static_cast<MetaRectAction*>(pAction);
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, 
pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
         case MetaActionType::ROUNDRECT:
         {
             MetaRoundRectAction*    pAct = 
static_cast<MetaRoundRectAction*>(pAction);
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, 
pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
         case MetaActionType::ELLIPSE:
         {
             MetaEllipseAction*      pAct = 
static_cast<MetaEllipseAction*>(pAction);
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, 
pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1390,7 +1368,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
             MetaArcAction*  pAct = static_cast<MetaArcAction*>(pAction);
             // FIXME: this is imprecise
             // e.g. for small arcs the whole rectangle is WAY too large
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, 
pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1399,7 +1377,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
             MetaPieAction*  pAct = static_cast<MetaPieAction*>(pAction);
             // FIXME: this is imprecise
             // e.g. for small arcs the whole rectangle is WAY too large
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, 
pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1408,7 +1386,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
             MetaChordAction*    pAct = static_cast<MetaChordAction*>(pAction);
             // FIXME: this is imprecise
             // e.g. for small arcs the whole rectangle is WAY too large
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, 
pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( 
pAct->GetRect(), aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1417,15 +1395,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( 
OutputDevice& i_rReference, tools::R
             MetaPolyLineAction* pAct = 
static_cast<MetaPolyLineAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
 
-            if(pUseHairline)
-            {
-                const LineInfo& rLineInfo = pAct->GetLineInfo();
-
-                if(0 != rLineInfo.GetWidth())
-                    pUseHairline = nullptr;
-            }
-
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1433,7 +1403,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaPolygonAction* pAct = static_cast<MetaPolygonAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPolygon().GetBoundRect() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1441,7 +1411,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaPolyPolygonAction* pAct = 
static_cast<MetaPolyPolygonAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, pUseHairline );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1453,7 +1423,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
             aMapVDev->GetTextBoundRect( aRect, pAct->GetText(), 
pAct->GetIndex(), pAct->GetIndex(), pAct->GetLen() );
             Point aPt( pAct->GetPoint() );
             aRect.Move( aPt.X(), aPt.Y() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1466,7 +1436,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
                                        0, pAct->GetDXArray() );
             Point aPt( pAct->GetPoint() );
             aRect.Move( aPt.X(), aPt.Y() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1479,7 +1449,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
                                        pAct->GetWidth() );
             Point aPt( pAct->GetPoint() );
             aRect.Move( aPt.X(), aPt.Y() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1495,7 +1465,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
             Point aPt( pAct->GetStartPoint() );
             aRect.Move( aPt.X(), aPt.Y() );
             aRect.SetRight( aRect.Left() + pAct->GetWidth() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1503,7 +1473,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaBmpScaleAction* pAct = 
static_cast<MetaBmpScaleAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1511,7 +1481,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaBmpScalePartAction* pAct = 
static_cast<MetaBmpScalePartAction*>(pAction);
             tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() 
);
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1519,7 +1489,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaBmpExScaleAction*   pAct = 
static_cast<MetaBmpExScaleAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1527,7 +1497,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaBmpExScalePartAction*   pAct = 
static_cast<MetaBmpExScalePartAction*>(pAction);
             tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() 
);
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1535,7 +1505,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaGradientAction* pAct = 
static_cast<MetaGradientAction*>(pAction);
             tools::Rectangle aRect( pAct->GetRect() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1543,7 +1513,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaGradientExAction* pAct = 
static_cast<MetaGradientExAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1557,7 +1527,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaHatchAction*    pAct = static_cast<MetaHatchAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1565,7 +1535,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaTransparentAction* pAct = 
static_cast<MetaTransparentAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPolyPolygon().GetBoundRect() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1575,7 +1545,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
             // MetaFloatTransparentAction is defined limiting its content 
Metafile
             // to its geometry definition(Point, Size), so use these directly
             const tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1583,7 +1553,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaEPSAction*  pAct = static_cast<MetaEPSAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPoint(), pAct->GetSize() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1623,7 +1593,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( 
pAct->GetBitmap().GetSizePixel() ) );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1631,7 +1601,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( 
pAct->GetBitmapEx().GetSizePixel() ) );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1639,7 +1609,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pAction);
             tools::Rectangle aRect( pAct->GetPoint(), aMapVDev->PixelToLogic( 
pAct->GetBitmap().GetSizePixel() ) );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1647,7 +1617,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaMaskScalePartAction* pAct = 
static_cast<MetaMaskScalePartAction*>(pAction);
             tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() 
);
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1655,7 +1625,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaMaskScalePartAction* pAct = 
static_cast<MetaMaskScalePartAction*>(pAction);
             tools::Rectangle aRect( pAct->GetDestPoint(), pAct->GetDestSize() 
);
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1663,7 +1633,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaWallpaperAction* pAct = 
static_cast<MetaWallpaperAction*>(pAction);
             tools::Rectangle aRect( pAct->GetRect() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
@@ -1671,7 +1641,7 @@ tools::Rectangle GDIMetaFile::GetBoundRect( OutputDevice& 
i_rReference, tools::R
         {
             MetaTextRectAction* pAct = 
static_cast<MetaTextRectAction*>(pAction);
             tools::Rectangle aRect( pAct->GetRect() );
-            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack, nullptr );
+            ImplActionBounds( aBound, OutputDevice::LogicToLogic( aRect, 
aMapVDev->GetMapMode(), GetPrefMapMode() ), aClipStack );
         }
         break;
 
diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx
index 137bd50d283c..f964d1d7bef5 100644
--- a/vcl/source/gdi/impgraph.cxx
+++ b/vcl/source/gdi/impgraph.cxx
@@ -590,23 +590,16 @@ Bitmap ImpGraphic::getBitmap(const 
GraphicConversionParameters& rParameters) con
 
             if(GraphicType::GdiMetafile == getType())
             {
-                // get hairline and full bound rect
-                tools::Rectangle aHairlineRect;
-                const tools::Rectangle aRect(maMetaFile.GetBoundRect(*aVDev, 
&aHairlineRect));
-
-                if(!aRect.IsEmpty() && !aHairlineRect.IsEmpty())
-                {
-                    // expand if needed to allow bottom and right hairlines to 
be added
-                    if(aRect.Right() == aHairlineRect.Right())
-                    {
-                        aPixelSize.setWidth(aPixelSize.getWidth() + 1);
-                    }
-
-                    if(aRect.Bottom() == aHairlineRect.Bottom())
-                    {
-                        aPixelSize.setHeight(aPixelSize.getHeight() + 1);
-                    }
-                }
+                // tdf#126319 Removed correction based on 
hairline-at-the-extremes of
+                // the metafile. The task shows that this is no longer 
sufficient since
+                // less hairlines get used in general - what is good, but 
breaks that
+                // old fix. Anyways, hairlines are a left-over from non-AA 
times
+                // when it was not possible to paint lines taller than one 
pixel.
+                // This might need to be corrected further using primitives and
+                // the possibility to get better-quality ranges for 
correction. For
+                // now, always add that one pixel.
+                aPixelSize.setWidth(aPixelSize.getWidth() + 1);
+                aPixelSize.setHeight(aPixelSize.getHeight() + 1);
             }
 
             if(aVDev->SetOutputSizePixel(aPixelSize))
commit 6e34a487ae85b830b510bdaf26a0a9e426880362
Author:     Armin Le Grand (Allotropia) <armin.le.gr...@me.com>
AuthorDate: Wed Jan 26 18:02:27 2022 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:05 2022 +0100

    tdf#126319 Correct area(s) on selection export
    
    For shapes like TextFrames the export of the selected
    object(s) to Bitmap needed to be adapted. It should
    not reduce to minimal geometric necessary size.
    
    While reduction seems good initially as an idea this
    may change aspect ratio and expected size of the result
    by cutting off visually empty areas, e.g. the text
    distance areas to the shape's logical bounds.
    
    This also needed to be adapted to multi-selections
    accordingly.
    
    Change-Id: I85bffe60fcfc2e8da87f69936af30f64c26deead
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129002
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@me.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129809

diff --git a/svx/source/unodraw/UnoGraphicExporter.cxx 
b/svx/source/unodraw/UnoGraphicExporter.cxx
index 73d77cb54ea8..d6029dde6d29 100644
--- a/svx/source/unodraw/UnoGraphicExporter.cxx
+++ b/svx/source/unodraw/UnoGraphicExporter.cxx
@@ -224,25 +224,29 @@ namespace {
                 const Size aHalfPixelInMtf(
                     (aOnePixelInMtf.getWidth() + 1) / 2,
                     (aOnePixelInMtf.getHeight() + 1) / 2);
-                const bool bHairlineBR(
-                    !aHairlineRect.IsEmpty() && (aRect.Right() == 
aHairlineRect.Right() || aRect.Bottom() == aHairlineRect.Bottom()));
 
-                // Move the content to (0,0), usually TopLeft ist slightly
-                // negative. For better visualization, add a half pixel, too
+                // tdf#126319 take bounds into account individually
+                const bool bHairlineRight(!aHairlineRect.IsEmpty() && 
aRect.Right() == aHairlineRect.Right());
+                const bool bHairlineBottom(!aHairlineRect.IsEmpty() && 
aRect.Bottom() == aHairlineRect.Bottom());
+                const bool bHairlineLeft(!aHairlineRect.IsEmpty() && 
aRect.Left() == aHairlineRect.Left());
+                const bool bHairlineTop(!aHairlineRect.IsEmpty() && 
aRect.Top() == aHairlineRect.Top());
+
+                // tdf#126319 Move the content dependent on Top/Left hairline
                 aMtf.Move(
-                    aHalfPixelInMtf.getWidth() - aRect.Left(),
-                    aHalfPixelInMtf.getHeight() - aRect.Top());
+                    (bHairlineLeft ? -aHalfPixelInMtf.getWidth() : 
aHalfPixelInMtf.getWidth()),
+                    (bHairlineTop ? -aHalfPixelInMtf.getHeight() : 
aHalfPixelInMtf.getHeight()));
 
                 // Do not Scale, but set the PrefSize. Some levels deeper the
                 // MetafilePrimitive will add a mapping to the decomposition
                 // (and possibly a clipping) to map the graphic content to
                 // a unit coordinate system.
-                // Size is the measured size plus one pixel if needed 
(bHairlineBR)
-                // and the moved half pixwel from above
+                // tdf#126319 Size is the previous already correct size plus 
one
+                // pixel if needed (dependent on Righ/Bottom hairline) and the
+                // already moved half pixel from above
                 aMtf.SetPrefSize(
                     Size(
-                        aRect.getWidth() + (bHairlineBR ? 
aOnePixelInMtf.getWidth() : 0) + aHalfPixelInMtf.getWidth(),
-                        aRect.getHeight() + (bHairlineBR ? 
aOnePixelInMtf.getHeight() : 0) + aHalfPixelInMtf.getHeight()));
+                        aMtf.GetPrefSize().Width() + (bHairlineRight ? 
aHalfPixelInMtf.getWidth() : 0),
+                        aMtf.GetPrefSize().Height() + (bHairlineBottom ? 
aHalfPixelInMtf.getHeight() : 0)));
             }
 
             return convertMetafileToBitmapEx(aMtf, aRange, 
nMaximumQuadraticPixels);
commit 2c05c823cb91a8b849b60cba0d8ae853fe43b120
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Feb 10 19:43:08 2022 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:05 2022 +0100

    sw: fix layout loop on soffice --convert-to pdf ooo95698-1.odt
    
    For unknown reasons, this loops since commit
    32902f66e7749b2d06d13f50416be5323a0c0ea9a
    "sw_redlinehide: make layout based Show/Hide mode the default"
    
    The problem is that when page 1 is layouted for the first time, it
    splits into 6 pages, and then the SwTabFrame 47 decides that it wants
    to move its follow flow line because it fits onto page 1.
    
    Then splitting the SwTabFrame again fails, but for this
    RemoveFollowFlowLine() was called a 2nd time and removed the one on
    page 3.
    
    The result is a layout with content on page 1, nothing on page 2, 3
    and again content on page 4.  This seems to reoccur every time page 1
    is formatted.
    
    But the first RemoveFollowFlowLine() was wrong because
    CalcHeightOfFirstContentLine() returns 0 because
    lcl_CalcHeightOfFirstContentLine() didn't handle the case of
    SwSectionFrame containing SwTabFrame.
    
    This is similar to commit e024cad7c1365da6a198656c3ca0c32b28938e87
    doing the same thing for text frames in section.
    
    Change-Id: I23fb4d1d56622039f461bb2d357a9c88db140605
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129800
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit b4271e028686d729189afc5e42a9c310f81144f3)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129828
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 95388db5c9ac..f0ad11a0653a 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -5833,9 +5833,12 @@ static SwTwips lcl_CalcHeightOfFirstContentLine( const 
SwRowFrame& rSourceLine )
                 const SwRowFrame* pTmpSourceRow = static_cast<const 
SwRowFrame*>(pCurrSourceCell->Lower());
                 nTmpHeight = lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow 
);
             }
-            else if ( pTmp->IsTabFrame() )
+            else if (pTmp->IsTabFrame() || (pTmp->IsSctFrame() && 
pTmp->GetLower() && pTmp->GetLower()->IsTabFrame()))
             {
-                nTmpHeight = static_cast<const 
SwTabFrame*>(pTmp)->CalcHeightOfFirstContentLine();
+                SwTabFrame const*const pTabFrame(pTmp->IsTabFrame()
+                        ? static_cast<SwTabFrame const*>(pTmp)
+                        : static_cast<SwTabFrame const*>(pTmp->GetLower()));
+                nTmpHeight = pTabFrame->CalcHeightOfFirstContentLine();
             }
             else if (pTmp->IsTextFrame() || (pTmp->IsSctFrame() && 
pTmp->GetLower() && pTmp->GetLower()->IsTextFrame()))
             {
commit e99ea6c511f6fe42e157eeb8c444563e1e798a0e
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Fri Feb 11 14:54:45 2022 +0000
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:05 2022 +0100

    Resolves: tdf#147325 "Edit in SQL View" should accept tab
    
    Change-Id: I286281c317c30e5c189747f2d4844a0d5dd0828f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129829
    Tested-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>

diff --git a/dbaccess/source/ui/querydesign/QueryTextView.cxx 
b/dbaccess/source/ui/querydesign/QueryTextView.cxx
index 9805c2aca62e..daeb6ee14f7d 100644
--- a/dbaccess/source/ui/querydesign/QueryTextView.cxx
+++ b/dbaccess/source/ui/querydesign/QueryTextView.cxx
@@ -42,6 +42,7 @@ OQueryTextView::OQueryTextView(OQueryContainerWindow* 
pParent, OQueryController&
     m_xSQL->DisableInternalUndo();
     m_xSQL->SetHelpId(HID_CTL_QRYSQLEDIT);
     m_xSQL->SetModifyHdl(LINK(this, OQueryTextView, ModifyHdl));
+    m_xSQL->SetAcceptsTab(true);
 
     m_timerUndoActionCreation.SetTimeout(1000);
     m_timerUndoActionCreation.SetInvokeHandler(LINK(this, OQueryTextView, 
OnUndoActionTimer));
commit cfe6e630e4d30dd51ff096808c445472a3590056
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Thu Feb 10 10:53:27 2022 +0000
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:05 2022 +0100

    limit style export to words max style count
    
    and
    
    use std::vector
    
    LIBREOFFICE-U78X8I5G
    
    Change-Id: I436b4c13a4ce07f5e9e5d374163bc4de55cd2cde
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129804
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/source/filter/ww8/wrtw8sty.cxx 
b/sw/source/filter/ww8/wrtw8sty.cxx
index 72c171bacdff..9f103627d576 100644
--- a/sw/source/filter/ww8/wrtw8sty.cxx
+++ b/sw/source/filter/ww8/wrtw8sty.cxx
@@ -151,13 +151,13 @@ MSWordStyles::MSWordStyles( MSWordExportBase& rExport, 
bool bListStyles )
         m_rExport.m_rDoc.GetFootnoteInfo().GetAnchorCharFormat( 
m_rExport.m_rDoc );
         m_rExport.m_rDoc.GetFootnoteInfo().GetCharFormat( m_rExport.m_rDoc );
     }
-    sal_uInt16 nAlloc = WW8_RESERVED_SLOTS + 
m_rExport.m_rDoc.GetCharFormats()->size() - 1 +
+    sal_uInt32 nAlloc = WW8_RESERVED_SLOTS + 
m_rExport.m_rDoc.GetCharFormats()->size() - 1 +
                                          
m_rExport.m_rDoc.GetTextFormatColls()->size() - 1 +
                                          (bListStyles ? 
m_rExport.m_rDoc.GetNumRuleTable().size() - 1 : 0);
+    nAlloc = std::min<sal_uInt32>(nAlloc, MSWORD_MAX_STYLES_LIMIT);
 
     // somewhat generous ( free for up to 15 )
-    m_pFormatA.reset( new SwFormat*[ nAlloc ] );
-    memset( m_pFormatA.get(), 0, nAlloc * sizeof( SwFormat* ) );
+    m_aFormatA.resize(nAlloc, nullptr);
     memset( m_aHeadingParagraphStyles, -1 , MAXLEVEL * sizeof( sal_uInt16));
 
     BuildStylesTable();
@@ -173,7 +173,7 @@ sal_uInt16 MSWordStyles::GetSlot( const SwFormat* pFormat ) 
const
 {
     sal_uInt16 n;
     for ( n = 0; n < m_nUsedSlots; n++ )
-        if ( m_pFormatA[n] == pFormat )
+        if ( m_aFormatA[n] == pFormat )
             return n;
     return 0xfff;                   // 0xfff: WW: zero
 }
@@ -283,19 +283,19 @@ void MSWordStyles::BuildStylesTable()
 
     const SwCharFormats& rArr = *m_rExport.m_rDoc.GetCharFormats();       // 
first CharFormat
     // the default character style ( 0 ) will not be outputted !
-    for( size_t n = 1; n < rArr.size(); n++ )
+    for( size_t n = 1; n < rArr.size() && m_nUsedSlots < 
MSWORD_MAX_STYLES_LIMIT; n++ )
     {
         SwCharFormat* pFormat = rArr[n];
-        m_pFormatA[ BuildGetSlot( *pFormat ) ] = pFormat;
+        m_aFormatA[ BuildGetSlot( *pFormat ) ] = pFormat;
     }
 
     const SwTextFormatColls& rArr2 = *m_rExport.m_rDoc.GetTextFormatColls();   
// then TextFormatColls
     // the default character style ( 0 ) will not be outputted !
-    for( size_t n = 1; n < rArr2.size(); n++ )
+    for( size_t n = 1; n < rArr2.size() && m_nUsedSlots < 
MSWORD_MAX_STYLES_LIMIT; n++ )
     {
         SwTextFormatColl* pFormat = rArr2[n];
         sal_uInt16 nId = BuildGetSlot( *pFormat ) ;
-        m_pFormatA[ nId ] = pFormat;
+        m_aFormatA[ nId ] = pFormat;
         if ( pFormat->IsAssignedToListLevelOfOutlineStyle() )
         {
             int nLvl = pFormat->GetAssignedOutlineStyleLevel() ;
@@ -308,7 +308,7 @@ void MSWordStyles::BuildStylesTable()
         return;
 
     const SwNumRuleTable& rNumRuleTable = m_rExport.m_rDoc.GetNumRuleTable();
-    for (size_t i = 0; i < rNumRuleTable.size(); ++i)
+    for (size_t i = 0; i < rNumRuleTable.size() && m_nUsedSlots < 
MSWORD_MAX_STYLES_LIMIT; ++i)
     {
         const SwNumRule* pNumRule = rNumRuleTable[i];
         if (pNumRule->IsAutoRule() || pNumRule->GetName().startsWith("WWNum"))
@@ -348,8 +348,8 @@ void MSWordStyles::BuildStyleIds()
     for (sal_uInt16 n = 1; n < m_nUsedSlots; ++n)
     {
         OUString aName;
-        if(m_pFormatA[n])
-            aName = m_pFormatA[n]->GetName();
+        if (m_aFormatA[n])
+            aName = m_aFormatA[n]->GetName();
         else if (m_aNumRules.find(n) != m_aNumRules.end())
             aName = m_aNumRules[n]->GetName();
 
@@ -628,8 +628,8 @@ void MSWordStyles::OutputStyle( SwFormat* pFormat, 
sal_uInt16 nPos )
             for ( int nSuffix = 0; ; ++nSuffix ) {
                 bool clash=false;
                 for ( sal_uInt16 n = 1; n < m_nUsedSlots; ++n )
-                    if ( m_pFormatA[n] &&
-                         m_pFormatA[n]->GetName().equalsIgnoreAsciiCase(aName) 
)
+                    if ( m_aFormatA[n] &&
+                         m_aFormatA[n]->GetName().equalsIgnoreAsciiCase(aName) 
)
                     {
                         clash = true;
                         break;
@@ -718,7 +718,7 @@ void MSWordStyles::OutputStylesTable()
         if (m_aNumRules.find(n) != m_aNumRules.end())
             OutputStyle(m_aNumRules[n], n);
         else
-            OutputStyle( m_pFormatA[n], n );
+            OutputStyle(m_aFormatA[n], n);
     }
 
     m_rExport.AttrOutput().EndStyles( m_nUsedSlots );
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 72e5a8d65e1e..ef10e2a9a384 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -1571,7 +1571,7 @@ class MSWordStyles
 {
     MSWordExportBase& m_rExport;
     sal_uInt16 m_aHeadingParagraphStyles[MAXLEVEL];
-    std::unique_ptr<SwFormat*[]> m_pFormatA; ///< Slot <-> Character and 
paragraph style array (0 for list styles).
+    std::vector<SwFormat*> m_aFormatA; ///< Slot <-> Character and paragraph 
style array (0 for list styles).
     sal_uInt16 m_nUsedSlots;
     bool m_bListStyles; ///< If list styles are requested to be exported as 
well.
     std::map<sal_uInt16, const SwNumRule*> m_aNumRules; ///< Slot <-> List 
style map.
@@ -1622,7 +1622,7 @@ public:
     /// Get styleId of the nId-th style (nId is its position in pFormatA).
     OString const & GetStyleId(sal_uInt16 nId) const;
 
-    const SwFormat* GetSwFormat(sal_uInt16 nId) const { return 
m_pFormatA[nId]; }
+    const SwFormat* GetSwFormat(sal_uInt16 nId) const { return 
m_aFormatA[nId]; }
     /// Get numbering rule of the nId-th style
     const SwNumRule* GetSwNumRule(sal_uInt16 nId) const;
     sal_uInt16 GetHeadingParagraphStyleId(sal_uInt16 nLevel) const { return 
m_aHeadingParagraphStyles[ nLevel ]; }
commit 40ec65a2a5b192ccb0f680e0c83fb6400de3e43c
Author:     Vasily Melenchuk <vasily.melenc...@cib.de>
AuthorDate: Wed Feb 9 09:41:51 2022 +0300
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:05 2022 +0100

    tdf#146917: docx import: better support for style with num reset
    
    When paragraph style is disabling numbering defined in parent
    style we should apply margin properties (like we already do
    in other numbering cases), but we should include only properties
    from styles not affected by numbering. In other words, only
    styles without w:numId are used.
    
    Unittest was extended to cover different combinations of this
    situation.
    
    Change-Id: Ic19e00fcfe16b2357cdfe763b4f969cc63122e89
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129701
    Tested-by: Jenkins
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>
    (cherry picked from commit 96e1be11540bada172fbdbfbbe3f9b7dc3e58462)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129827
    Reviewed-by: Vasily Melenchuk <vasily.melenc...@cib.de>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf132752.docx 
b/sw/qa/extras/ooxmlexport/data/tdf132752.docx
index 57eddc455fca..a94fc498a101 100644
Binary files a/sw/qa/extras/ooxmlexport/data/tdf132752.docx and 
b/sw/qa/extras/ooxmlexport/data/tdf132752.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
index 1e6938bcecc4..e3eb50c29ea4 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
@@ -384,9 +384,35 @@ 
DECLARE_OOXMLEXPORT_TEST(testTdf143692_outlineLevelTortureTest, "tdf143692_outli
 
 DECLARE_OOXMLEXPORT_TEST(testTdf132752, "tdf132752.docx")
 {
-    CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), 
getProperty<sal_Int32>(getParagraph(1), "ParaLeftMargin"));
-    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), 
getProperty<sal_Int32>(getParagraph(1), "ParaRightMargin"));
-    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(1), 
"ParaFirstLineIndent"));
+    uno::Reference<beans::XPropertySet> xPara1(getParagraph(1), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty<sal_Int32>(xPara1, 
"ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty<sal_Int32>(xPara1, 
"ParaRightMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara1, 
"ParaFirstLineIndent"));
+
+    uno::Reference<beans::XPropertySet> xPara2(getParagraph(2), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty<sal_Int32>(xPara2, 
"ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty<sal_Int32>(xPara2, 
"ParaRightMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-630), getProperty<sal_Int32>(xPara2, 
"ParaFirstLineIndent"));
+
+    uno::Reference<beans::XPropertySet> xPara3(getParagraph(3), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara3, 
"ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(5891), getProperty<sal_Int32>(xPara3, 
"ParaRightMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara3, 
"ParaFirstLineIndent"));
+
+    uno::Reference<beans::XPropertySet> xPara4(getParagraph(4), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty<sal_Int32>(xPara4, 
"ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty<sal_Int32>(xPara4, 
"ParaRightMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4157), getProperty<sal_Int32>(xPara4, 
"ParaFirstLineIndent"));
+
+    uno::Reference<beans::XPropertySet> xPara5(getParagraph(5), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1801), getProperty<sal_Int32>(xPara5, 
"ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), getProperty<sal_Int32>(xPara5, 
"ParaRightMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-630), getProperty<sal_Int32>(xPara5, 
"ParaFirstLineIndent"));
+
+    uno::Reference<beans::XPropertySet> xPara6(getParagraph(6), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3565), getProperty<sal_Int32>(xPara6, 
"ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2764), getProperty<sal_Int32>(xPara6, 
"ParaRightMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-2394), getProperty<sal_Int32>(xPara6, 
"ParaFirstLineIndent"));
 }
 
 DECLARE_OOXMLEXPORT_TEST(testGutterLeft, "gutter-left.docx")
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx 
b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 4b0f3f6c4e75..13f1fb9056b9 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -183,6 +183,45 @@ static void lcl_handleTextField( const uno::Reference< 
beans::XPropertySet >& rx
     }
 }
 
+/**
+ Very similar to DomainMapper_Impl::GetPropertyFromStyleSheet
+ It is focused on paragraph properties search in current & parent stylesheet 
entries.
+ But it will not take into account propeties with listid: these are "list 
paragraph styles" and
+ not used in some cases.
+*/
+static uno::Any lcl_GetPropertyFromParaStyleSheetNoNum(PropertyIds eId, 
StyleSheetEntryPtr pEntry, const StyleSheetTablePtr& rStyleSheet)
+{
+    while (pEntry)
+    {
+        if (pEntry->pProperties)
+        {
+            std::optional<PropertyMap::Property> aProperty =
+                pEntry->pProperties->getProperty(eId);
+            if (aProperty)
+            {
+                if (pEntry->pProperties->GetListId())
+                    // It is a paragraph style with list. Paragraph list 
styles are not taken into account
+                    return uno::Any();
+                else
+                    return aProperty->second;
+            }
+        }
+        //search until the property is set or no parent is available
+        StyleSheetEntryPtr pNewEntry;
+        if (!pEntry->sBaseStyleIdentifier.isEmpty())
+            pNewEntry = 
rStyleSheet->FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier);
+
+        SAL_WARN_IF(pEntry == pNewEntry, "writerfilter.dmapper", "circular 
loop in style hierarchy?");
+
+        if (pEntry == pNewEntry) //fdo#49587
+            break;
+
+        pEntry = pNewEntry;
+    }
+    return uno::Any();
+}
+
+
 namespace {
 
 struct FieldConversion
@@ -1771,11 +1810,21 @@ void DomainMapper_Impl::finishParagraph( const 
PropertyMapPtr& pPropertyMap, con
 
         if (nListId == 0 && !pList)
         {
-            // Seems situation with listid=0 and missing list definition is 
used by DOCX
-            // to remove numbering defined previously. But some default 
numbering attributes
-            // are still applied. This is first line indent, probably 
something more?
-            if (!pParaContext->isSet(PROP_PARA_FIRST_LINE_INDENT))
-                pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, 
uno::makeAny(sal_Int16(0)), false);
+            // listid = 0 and no list definition is used in DOCX to stop 
numbering
+            // defined somewhere in parent styles
+            // And here we should explicitly set left margin and first-line 
margin.
+            // They can be taken from referred style, but not from styles with 
listid!
+            uno::Any aProp = 
lcl_GetPropertyFromParaStyleSheetNoNum(PROP_PARA_FIRST_LINE_INDENT, pEntry, 
m_pStyleSheetTable);
+            if (aProp.hasValue())
+                pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, aProp, 
false);
+            else
+                pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, 
uno::makeAny(sal_uInt32(0)), false);
+
+            aProp = 
lcl_GetPropertyFromParaStyleSheetNoNum(PROP_PARA_LEFT_MARGIN, pEntry, 
m_pStyleSheetTable);
+            if (aProp.hasValue())
+                pParaContext->Insert(PROP_PARA_LEFT_MARGIN, aProp, false);
+            else
+                pParaContext->Insert(PROP_PARA_LEFT_MARGIN, 
uno::makeAny(sal_uInt32(0)), false);
         }
     }
 
commit acc2c423ccc4934958c04e0abae54cdb8547f8ac
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Feb 1 15:17:40 2022 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:04 2022 +0100

    sw: fix swapped inner vs outer border for Word-style right/bottom page 
borders
    
    This is similar to commit cf2690ae76b4250af32be7c8980b8d83b3611591 (sw:
    fix swapped inner vs outer border for Word-style bottom table borders,
    2022-01-13), but that was for outer table borders, this one is for page
    borders.
    
    The explicit mirroring is needed because Writer will automatically
    mirror, but Word mirrors in its document model, so we need to "mirror
    back" to get the matching rendering.
    
    (cherry picked from commit 60a1f07049a817d4d3d7beb6c9b9da2571e2463b)
    
    Change-Id: I38fbf8adbc87ecd217a11b177840b0fede4cdf8c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129770
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/core/layout/data/double-page-border.docx 
b/sw/qa/core/layout/data/double-page-border.docx
new file mode 100644
index 000000000000..a706b327cd05
Binary files /dev/null and b/sw/qa/core/layout/data/double-page-border.docx 
differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index a02e17fb8bde..abd77b3e217d 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -694,6 +694,54 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, 
testParaBorderInCellClip)
     assertXPath(pXmlDoc, "//clipregion/polygon", 2);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testDoublePageBorder)
+{
+    // Given a page with a top and bottom double border, outer is thick, inner 
is thin:
+    SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "double-page-border.docx");
+    SwDocShell* pShell = pDoc->GetDocShell();
+
+    // When rendering that document:
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+
+    // Then make sure the top border is thick+thing and the bottom border is 
thin+thick (from top to
+    // bottom):
+    MetafileXmlDump dumper;
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+    // Collect widths of horizontal lines.
+    xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, 
"//polyline[@style='solid']/point");
+    xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+    // Vertical position -> width.
+    std::map<sal_Int32, sal_Int32> aBorderWidths;
+    for (int i = 0; i < xmlXPathNodeSetGetLength(pXmlNodes); i += 2)
+    {
+        xmlNodePtr pStart = pXmlNodes->nodeTab[i];
+        xmlNodePtr pEnd = pXmlNodes->nodeTab[i + 1];
+        xmlChar* pStartY = xmlGetProp(pStart, BAD_CAST("y"));
+        xmlChar* pEndY = xmlGetProp(pEnd, BAD_CAST("y"));
+        sal_Int32 nStartY = OString(reinterpret_cast<char 
const*>(pStartY)).toInt32();
+        sal_Int32 nEndY = OString(reinterpret_cast<char 
const*>(pEndY)).toInt32();
+        if (nStartY != nEndY)
+        {
+            // Vertical border.
+            continue;
+        }
+        xmlChar* pWidth = xmlGetProp(pStart->parent, BAD_CAST("width"));
+        sal_Int32 nWidth = OString(reinterpret_cast<char 
const*>(pWidth)).toInt32();
+        aBorderWidths[nStartY] = nWidth;
+    }
+    xmlXPathFreeObject(pXmlObj);
+    std::vector<sal_Int32> aBorderWidthVec;
+    std::transform(aBorderWidths.begin(), aBorderWidths.end(), 
std::back_inserter(aBorderWidthVec),
+                   [](const std::pair<sal_Int32, sal_Int32>& rPair) { return 
rPair.second; });
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), aBorderWidthVec.size());
+    CPPUNIT_ASSERT_GREATER(aBorderWidthVec[1], aBorderWidthVec[0]);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected greater than: 60
+    // - Actual  : 15
+    // i.e. the bottom border was thick+thin, not thin+thick.
+    CPPUNIT_ASSERT_GREATER(aBorderWidthVec[2], aBorderWidthVec[3]);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index 1b2a7379b17f..b1b3bef8e42f 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -5358,14 +5358,14 @@ void SwFrame::PaintSwFrameShadowAndBorder(
             pBottomBorder = aAccess.Get()->GetBox().GetBottom();
         }
 
-        bool bWordTableCell = false;
+        bool bWordBorder = false;
         SwViewShell* pShell = getRootFrame()->GetCurrShell();
         if (pShell)
         {
             const IDocumentSettingAccess& rIDSA = 
pShell->GetDoc()->getIDocumentSettingAccess();
-            bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP);
+            bWordBorder = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP);
         }
-        bool bInWordTableCell = IsContentFrame() && GetUpper()->IsCellFrame() 
&& bWordTableCell;
+        bool bInWordTableCell = IsContentFrame() && GetUpper()->IsCellFrame() 
&& bWordBorder;
         if (bInWordTableCell)
         {
             // Compat mode: don't paint bottom border if we know the bottom of 
the content was cut
@@ -5385,8 +5385,21 @@ void SwFrame::PaintSwFrameShadowAndBorder(
                     aRect.Width(), aRect.Height(),
                     aRect.Left(), aRect.Top()));
             const svx::frame::Style aStyleTop(pTopBorder, 1.0);
-            const svx::frame::Style aStyleRight(pRightBorder, 1.0);
-            const svx::frame::Style aStyleBottom(pBottomBorder, 1.0);
+            svx::frame::Style aStyleRight(pRightBorder, 1.0);
+
+            // Right/bottom page borders are always mirrored in Word.
+            if (IsPageFrame() && bWordBorder)
+            {
+                aStyleRight.MirrorSelf();
+            }
+
+            svx::frame::Style aStyleBottom(pBottomBorder, 1.0);
+
+            if (IsPageFrame() && bWordBorder)
+            {
+                aStyleBottom.MirrorSelf();
+            }
+
             const svx::frame::Style aStyleLeft(pLeftBorder, 1.0);
             drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget;
 
commit 523d1c99fb561bc42bdf806671016ea901d2b394
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jan 18 17:04:14 2022 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:04 2022 +0100

    sw: fix unexpected paragraph border inside table cells
    
    The bug document has a table cell, which contains a paragraph with
    borders. Its left/right/bottom borders are rendered in Writer, but not
    in Word.
    
    The reason for the left/right border is that it's outside the
    paragraph's frame area, which is not rendered in Word. Fix this by
    clipping the rendered borders so they don't go outside the paragraph's
    frame area. (Normally the frame area is the larger rectangle, and then
    margins may cause a smaller "print area", but in this case we have a
    negative right margin, so clipping the print area to fit into the frame
    area actually does something.)
    
    This is quite similar to what commit
    1e21902106cbe57658bed03ed24d4d0863685cfd (tdf#117884: intersect border
    with paint area of upper frame., 2018-05-26) did for table borders.
    
    The bottom border is a different problem: the cell has a fixed height
    and enough content so the paragraph is cut off vertically. This means
    that technically the bottom border would be inside the frame area, but
    Word cuts it off, because they apply clipping on the not-yet-cut-off
    rectangle. Fix this by dropping the bottom margin when the frame is cut
    off.
    
    (cherry picked from commit 4a7281fa206c0a82cfc2ba23f25c31ae775d8777)
    
    Change-Id: I7f65b68997330b247db65839db8a484e74f78c64
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129769
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/core/layout/data/para-border-in-cell-clip.docx 
b/sw/qa/core/layout/data/para-border-in-cell-clip.docx
new file mode 100644
index 000000000000..7c516853648c
Binary files /dev/null and 
b/sw/qa/core/layout/data/para-border-in-cell-clip.docx differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index 4ed97597ffcc..a02e17fb8bde 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -674,6 +674,26 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, 
testDoubleBorderHorizontal)
     CPPUNIT_ASSERT_GREATER(aBorderWidthVec[3], aBorderWidthVec[2]);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testParaBorderInCellClip)
+{
+    // Given a document which has outside-cell borders defined, which should 
not be visible:
+    SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "para-border-in-cell-clip.docx");
+    SwDocShell* pShell = pDoc->GetDocShell();
+
+    // When rendering those borders:
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+
+    // Then make sure that we have clipping setup for both paragraphs inside 
the table cell:
+    MetafileXmlDump dumper;
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 2
+    // - Actual  : 0
+    // - XPath '//clipregion/polygon' number of nodes is incorrect
+    // i.e. there was no clipping applied, leading to unexpected left/right 
borders.
+    assertXPath(pXmlDoc, "//clipregion/polygon", 2);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index 656646420dc5..1b2a7379b17f 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -118,6 +118,7 @@
 #include <comphelper/lok.hxx>
 #include <svtools/optionsdrawinglayer.hxx>
 #include <vcl/GraphicLoader.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
 
 using namespace ::editeng;
 using namespace ::com::sun::star;
@@ -5357,6 +5358,25 @@ void SwFrame::PaintSwFrameShadowAndBorder(
             pBottomBorder = aAccess.Get()->GetBox().GetBottom();
         }
 
+        bool bWordTableCell = false;
+        SwViewShell* pShell = getRootFrame()->GetCurrShell();
+        if (pShell)
+        {
+            const IDocumentSettingAccess& rIDSA = 
pShell->GetDoc()->getIDocumentSettingAccess();
+            bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP);
+        }
+        bool bInWordTableCell = IsContentFrame() && GetUpper()->IsCellFrame() 
&& bWordTableCell;
+        if (bInWordTableCell)
+        {
+            // Compat mode: don't paint bottom border if we know the bottom of 
the content was cut
+            // off.
+            auto pContentFrame = static_cast<const SwContentFrame*>(this);
+            if (pContentFrame->IsUndersized())
+            {
+                pBottomBorder = nullptr;
+            }
+        }
+
         if(nullptr != pLeftBorder || nullptr != pRightBorder || nullptr != 
pTopBorder || nullptr != pBottomBorder)
         {
             // now we have all SvxBorderLine(s) sorted out, create geometry
@@ -5370,14 +5390,28 @@ void SwFrame::PaintSwFrameShadowAndBorder(
             const svx::frame::Style aStyleLeft(pLeftBorder, 1.0);
             drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget;
 
-            aBorderLineTarget.append(
-                drawinglayer::primitive2d::Primitive2DReference(
+            drawinglayer::primitive2d::Primitive2DReference aRetval(
                     new 
drawinglayer::primitive2d::SwBorderRectanglePrimitive2D(
                         aBorderTransform,
                         aStyleTop,
                         aStyleRight,
                         aStyleBottom,
-                        aStyleLeft)));
+                        aStyleLeft));
+
+            if (bInWordTableCell)
+            {
+                // Compat mode: cut off the borders which are outside of our 
own area.
+                const SwRect& rClip = getFrameArea();
+                basegfx::B2DRectangle aClip(rClip.Left(), rClip.Top(), 
rClip.Right(),
+                                            rClip.Bottom());
+                const basegfx::B2DPolyPolygon aPolyPolygon(
+                    basegfx::utils::createPolygonFromRect(aClip));
+                const drawinglayer::primitive2d::Primitive2DReference xClipped(
+                    new 
drawinglayer::primitive2d::MaskPrimitive2D(aPolyPolygon, { aRetval }));
+                aRetval = xClipped;
+            }
+
+            aBorderLineTarget.append(aRetval);
             gProp.pBLines->AddBorderLines(std::move(aBorderLineTarget));
         }
     }
commit 6fc89e5b3c12a23a32047209bb14e73f6b3d1b5e
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Jan 13 15:57:05 2022 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:04 2022 +0100

    sw: fix swapped inner vs outer border for Word-style bottom table borders
    
    This is similar to commit fc04a84f297b78a1049182b6d8cf745f863ffe61 (sw:
    fix swapped inner vs outer border for Word-style left table borders,
    2022-01-11), but that was for vertical borders, this is for horizontal
    ones.
    
    The other difference is that Word mirrors vertical lines, but not
    horizontal ones. This means that our horizontal line need less
    mirroring, while our vertical lines needed more mirroring.
    
    (cherry picked from commit cf2690ae76b4250af32be7c8980b8d83b3611591)
    
    Change-Id: Iff07adac5c53420673139d5c93ce52f6148fb977
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129768
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/core/layout/data/double-border-horizontal.docx 
b/sw/qa/core/layout/data/double-border-horizontal.docx
new file mode 100644
index 000000000000..624c7aa1aa74
Binary files /dev/null and 
b/sw/qa/core/layout/data/double-border-horizontal.docx differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index 0358b2f0f359..4ed97597ffcc 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -626,6 +626,54 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, 
testDoubleBorderVertical)
     CPPUNIT_ASSERT_GREATER(aBorderWidthVec[2], aBorderWidthVec[3]);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testDoubleBorderHorizontal)
+{
+    // Given a table with a top and bottom double border, outer is thin, inner 
is thick:
+    SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "double-border-horizontal.docx");
+    SwDocShell* pShell = pDoc->GetDocShell();
+
+    // When rendering table borders:
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+
+    // Then make sure the top border is thin+thick and the bottom border is 
thick+thin (from top to
+    // bottom):
+    MetafileXmlDump dumper;
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+    // Collect widths of horizontal lines.
+    xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, 
"//polyline[@style='solid']/point");
+    xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+    // Vertical position -> width.
+    std::map<sal_Int32, sal_Int32> aBorderWidths;
+    for (int i = 0; i < xmlXPathNodeSetGetLength(pXmlNodes); i += 2)
+    {
+        xmlNodePtr pStart = pXmlNodes->nodeTab[i];
+        xmlNodePtr pEnd = pXmlNodes->nodeTab[i + 1];
+        xmlChar* pStartY = xmlGetProp(pStart, BAD_CAST("y"));
+        xmlChar* pEndY = xmlGetProp(pEnd, BAD_CAST("y"));
+        sal_Int32 nStartY = OString(reinterpret_cast<char 
const*>(pStartY)).toInt32();
+        sal_Int32 nEndY = OString(reinterpret_cast<char 
const*>(pEndY)).toInt32();
+        if (nStartY != nEndY)
+        {
+            // Vertical border.
+            continue;
+        }
+        xmlChar* pWidth = xmlGetProp(pStart->parent, BAD_CAST("width"));
+        sal_Int32 nWidth = OString(reinterpret_cast<char 
const*>(pWidth)).toInt32();
+        aBorderWidths[nStartY] = nWidth;
+    }
+    xmlXPathFreeObject(pXmlObj);
+    std::vector<sal_Int32> aBorderWidthVec;
+    std::transform(aBorderWidths.begin(), aBorderWidths.end(), 
std::back_inserter(aBorderWidthVec),
+                   [](const std::pair<sal_Int32, sal_Int32>& rPair) { return 
rPair.second; });
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), aBorderWidthVec.size());
+    CPPUNIT_ASSERT_GREATER(aBorderWidthVec[0], aBorderWidthVec[1]);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected greater than: 120
+    // - Actual  : 60
+    // i.e. the bottom border was thin+thick, not thick+thin.
+    CPPUNIT_ASSERT_GREATER(aBorderWidthVec[3], aBorderWidthVec[2]);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index 00d0000c8b81..656646420dc5 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2846,8 +2846,21 @@ void SwTabFramePainter::Insert(const SwFrame& rFrame, 
const SvxBoxItem& rBoxItem
     svx::frame::Style aB(rBoxItem.GetBottom(), 1.0);
     aB.SetWordTableCell(bWordTableCell);
 
+    // First cell in a row.
+    bool bLeftIsOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetLower() 
== &rFrame;
+    // Last cell in a row.
+    bool bRightIsOuter = rFrame.IsCellFrame() && rFrame.GetNext() == nullptr;
+    // First row in a table.
+    bool bTopIsOuter = rFrame.IsCellFrame() && 
rFrame.GetUpper()->GetUpper()->GetLower() == rFrame.GetUpper();
+    // Last row in a table.
+    bool bBottomIsOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetNext() 
== nullptr;
+
     aR.MirrorSelf();
-    aB.MirrorSelf();
+    if (!bWordTableCell || !bBottomIsOuter)
+    {
+        // Outer horizontal lines are never mirrored in Word.
+        aB.MirrorSelf();
+    }
 
     const SwTwips nLeft   = aBorderRect.Left_();
     const SwTwips nRight  = aBorderRect.Right_();
@@ -2859,39 +2872,30 @@ void SwTabFramePainter::Insert(const SwFrame& rFrame, 
const SvxBoxItem& rBoxItem
     aT.SetRefMode( !bVert ? svx::frame::RefMode::Begin : 
svx::frame::RefMode::End );
     aB.SetRefMode( !bVert ? svx::frame::RefMode::Begin : 
svx::frame::RefMode::End );
 
-    // First cell in a row.
-    bool bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetLower() == 
&rFrame;
-
-    if (bWordTableCell && bOuter)
+    if (bWordTableCell && bLeftIsOuter)
     {
-        // First vs secondary and inner vs outer is the other way around in 
Word.
+        // Outer vertical lines are always mirrored in Word.
         aL.MirrorSelf();
     }
 
-    SwLineEntry aLeft  (nLeft,   nTop,  nBottom, bOuter,
+    SwLineEntry aLeft  (nLeft,   nTop,  nBottom, bLeftIsOuter,
             bVert ? aB                         : (bR2L ? aR : aL));
     if (bWordTableCell && rBoxItem.GetLeft())
     {
         aLeft.LimitVerticalEndPos(rFrame, SwLineEntry::VerticalType::LEFT);
     }
 
-    // Last cell in a row.
-    bOuter = rFrame.IsCellFrame() && rFrame.GetNext() == nullptr;
-    SwLineEntry aRight (nRight,  nTop,  nBottom, bOuter,
+    SwLineEntry aRight (nRight,  nTop,  nBottom, bRightIsOuter,
             bVert ? (bBottomAsTop ? aB : aT) : (bR2L ? aL : aR));
     if (bWordTableCell && rBoxItem.GetRight())
     {
         aRight.LimitVerticalEndPos(rFrame, SwLineEntry::VerticalType::RIGHT);
     }
 
-    // First row in a table.
-    bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetUpper()->GetLower() 
== rFrame.GetUpper();
-    SwLineEntry aTop   (nTop,    nLeft, nRight, bOuter,
+    SwLineEntry aTop   (nTop,    nLeft, nRight, bTopIsOuter,
             bVert ? aL                         : (bBottomAsTop ? aB : aT));
 
-    // Last row in a table.
-    bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetNext() == nullptr;
-    SwLineEntry aBottom(nBottom, nLeft, nRight, bOuter,
+    SwLineEntry aBottom(nBottom, nLeft, nRight, bBottomIsOuter,
             bVert ? aR                         : aB);
 
     Insert( aLeft, false );
commit b4e76d9815bdba19684c686bd1e3ab5a285e9dcf
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jan 11 17:18:11 2022 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:04 2022 +0100

    sw: fix swapped inner vs outer border for Word-style left table borders
    
    The minimal DOCX bugdoc has a single cell, the left border style is
    thinThickMediumGap, the right border style is thickThinMediumGap, which
    means the doc model already has the left/right mirroring, don't have to
    do it at layout time.
    
    The normal Writer way is to have a single border style and mirror the
    right/bottom border line.
    
    But then looking at the Writer vs Word output, inner vs outer is
    swapped, so at the end we have to mirror the left border line for
    Word-style table borders to get compatible output.
    
    (cherry picked from commit fc04a84f297b78a1049182b6d8cf745f863ffe61)
    
    Change-Id: I10fb95dfac67e466188cfc9ecf35efde806c14b0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129767
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/core/layout/data/double-border-vertical.docx 
b/sw/qa/core/layout/data/double-border-vertical.docx
new file mode 100644
index 000000000000..a4731ebec612
Binary files /dev/null and b/sw/qa/core/layout/data/double-border-vertical.docx 
differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index 2b1dc8be0b3f..0358b2f0f359 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -578,6 +578,54 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, 
testInnerCellBorderIntersect)
     CPPUNIT_ASSERT_LESS(aBorderStartEnds[0].second, 
aBorderStartEnds[1].second);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testDoubleBorderVertical)
+{
+    // Given a table with a left and right double border, outer is thick, 
inner is thin:
+    SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "double-border-vertical.docx");
+    SwDocShell* pShell = pDoc->GetDocShell();
+
+    // When rendering that document:
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+
+    // Then make sure the left border is thick+thin and the right border is 
thin+thick (from left to
+    // right):
+    MetafileXmlDump dumper;
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+    // Collect widths of vertical lines.
+    xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, 
"//polyline[@style='solid']/point");
+    xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+    // Horizontal position -> width.
+    std::map<sal_Int32, sal_Int32> aBorderWidths;
+    for (int i = 0; i < xmlXPathNodeSetGetLength(pXmlNodes); i += 2)
+    {
+        xmlNodePtr pStart = pXmlNodes->nodeTab[i];
+        xmlNodePtr pEnd = pXmlNodes->nodeTab[i + 1];
+        xmlChar* pStartX = xmlGetProp(pStart, BAD_CAST("x"));
+        xmlChar* pEndX = xmlGetProp(pEnd, BAD_CAST("x"));
+        sal_Int32 nStartX = OString(reinterpret_cast<char 
const*>(pStartX)).toInt32();
+        sal_Int32 nEndX = OString(reinterpret_cast<char 
const*>(pEndX)).toInt32();
+        if (nStartX != nEndX)
+        {
+            // Horizontal border.
+            continue;
+        }
+        xmlChar* pWidth = xmlGetProp(pStart->parent, BAD_CAST("width"));
+        sal_Int32 nWidth = OString(reinterpret_cast<char 
const*>(pWidth)).toInt32();
+        aBorderWidths[nStartX] = nWidth;
+    }
+    xmlXPathFreeObject(pXmlObj);
+    std::vector<sal_Int32> aBorderWidthVec;
+    std::transform(aBorderWidths.begin(), aBorderWidths.end(), 
std::back_inserter(aBorderWidthVec),
+                   [](const std::pair<sal_Int32, sal_Int32>& rPair) { return 
rPair.second; });
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), aBorderWidthVec.size());
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected greater than: 120
+    // - Actual  : 60
+    // i.e. the left border was thin+thick, not thick+thin.
+    CPPUNIT_ASSERT_GREATER(aBorderWidthVec[1], aBorderWidthVec[0]);
+    CPPUNIT_ASSERT_GREATER(aBorderWidthVec[2], aBorderWidthVec[3]);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index 41cbb9c47e71..00d0000c8b81 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2861,6 +2861,13 @@ void SwTabFramePainter::Insert(const SwFrame& rFrame, 
const SvxBoxItem& rBoxItem
 
     // First cell in a row.
     bool bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetLower() == 
&rFrame;
+
+    if (bWordTableCell && bOuter)
+    {
+        // First vs secondary and inner vs outer is the other way around in 
Word.
+        aL.MirrorSelf();
+    }
+
     SwLineEntry aLeft  (nLeft,   nTop,  nBottom, bOuter,
             bVert ? aB                         : (bR2L ? aR : aL));
     if (bWordTableCell && rBoxItem.GetLeft())
commit 384bb0abef12b860bb67ffef8c3577aa77a8b402
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Jan 6 15:45:02 2022 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:04 2022 +0100

    sw: fix too long inner borders intersecting with outer borders for Word 
cells
    
    This is similar to commit 66ac8e60896f6306bed8fbb34606fd14474f19ce (sw:
    fix unwanted long vertical border around vertically merged Word cell,
    2021-03-04), but this one is about how we handle table border painting
    when an inner border intersects with an outer border.
    
    Previously we used to paint the full outer border and the full inner
    border, which looks silly in case you have e.g. double border outside
    and a single border inside -- the inner line stops at the edge of the
    thick outer border in Word.
    
    Do the same by limiting the start of a horizontal line if its start
    would match the X coordinate of a vertical line (and the remaining 3
    combinations of hori/vert line start/end). We always limit the inner
    line, so this needs extending SwLineEntry if the line is an outer one or
    not.
    
    (cherry picked from commit 526c8bdb54eff942d5213030d1455f97720a1ba7)
    
    Change-Id: I669a271ce3a4c3c69916779d4f3167208e999f05
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129746
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/core/layout/data/inner-border.docx 
b/sw/qa/core/layout/data/inner-border.docx
new file mode 100644
index 000000000000..1d8adc9fe818
Binary files /dev/null and b/sw/qa/core/layout/data/inner-border.docx differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index b1cb3136b963..2b1dc8be0b3f 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -525,6 +525,59 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testLinkedBullet)
     assertXPath(pXmlDoc, "//bmpexscale", 1);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testInnerCellBorderIntersect)
+{
+    // Given a table with both outer and inner borders:
+    SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "inner-border.docx");
+    SwDocShell* pShell = pDoc->GetDocShell();
+
+    // When rendering table borders:
+    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+
+    // Then make sure that that inner and outer borders don't overlap in Word 
compatibility mode,
+    // and inner borders are reduced to prevent an overlap:
+    MetafileXmlDump dumper;
+    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+    // Collect start/end (vertical) positions of horizontal borders.
+    xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, 
"//polyline[@style='solid']/point");
+    xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+    std::vector<std::pair<sal_Int32, sal_Int32>> aBorderStartEnds;
+    for (int i = 0; i < xmlXPathNodeSetGetLength(pXmlNodes); i += 2)
+    {
+        xmlNodePtr pStart = pXmlNodes->nodeTab[i];
+        xmlNodePtr pEnd = pXmlNodes->nodeTab[i + 1];
+        xmlChar* pStartY = xmlGetProp(pStart, BAD_CAST("y"));
+        xmlChar* pEndY = xmlGetProp(pEnd, BAD_CAST("y"));
+        sal_Int32 nStartY = OString(reinterpret_cast<char 
const*>(pStartY)).toInt32();
+        sal_Int32 nEndY = OString(reinterpret_cast<char 
const*>(pEndY)).toInt32();
+        if (nStartY != nEndY)
+        {
+            // Vertical border.
+            continue;
+        }
+        xmlChar* pStartX = xmlGetProp(pStart, BAD_CAST("x"));
+        xmlChar* pEndX = xmlGetProp(pEnd, BAD_CAST("x"));
+        sal_Int32 nStartX = OString(reinterpret_cast<char 
const*>(pStartX)).toInt32();
+        sal_Int32 nEndX = OString(reinterpret_cast<char 
const*>(pEndX)).toInt32();
+        aBorderStartEnds.emplace_back(nStartX, nEndX);
+    }
+    xmlXPathFreeObject(pXmlObj);
+    // We have 3 lines: top, middle and bottom. The top and the bottom one is 
a full line, since
+    // it's an outer border. The middle one has increased start and decreased 
end to avoid an
+    // overlap.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aBorderStartEnds.size());
+    CPPUNIT_ASSERT_EQUAL(aBorderStartEnds[0].first, aBorderStartEnds[2].first);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected greater than: 1724
+    // - Actual  : 1724
+    // i.e. the middle line's start was the same as the top line start, while 
what we want is a
+    // larger X position, so the start of the middle line doesn't overlap with 
the thick vertical
+    // outer border on the left of the table.
+    CPPUNIT_ASSERT_GREATER(aBorderStartEnds[0].first, 
aBorderStartEnds[1].first);
+    CPPUNIT_ASSERT_EQUAL(aBorderStartEnds[0].second, 
aBorderStartEnds[2].second);
+    CPPUNIT_ASSERT_LESS(aBorderStartEnds[0].second, 
aBorderStartEnds[1].second);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/paintfrm.cxx 
b/sw/source/core/layout/paintfrm.cxx
index e356266b8795..41cbb9c47e71 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2242,6 +2242,7 @@ struct SwLineEntry
     SwTwips mnStartPos;
     SwTwips mnEndPos;
     SwTwips mnLimitedEndPos;
+    bool mbOuter;
 
     svx::frame::Style maAttribute;
 
@@ -2253,6 +2254,7 @@ public:
     SwLineEntry( SwTwips nKey,
                  SwTwips nStartPos,
                  SwTwips nEndPos,
+                 bool bOuter,
                  const svx::frame::Style& rAttribute );
 
     OverlapType Overlaps( const SwLineEntry& rComp ) const;
@@ -2269,11 +2271,13 @@ public:
 SwLineEntry::SwLineEntry( SwTwips nKey,
                           SwTwips nStartPos,
                           SwTwips nEndPos,
+                          bool bOuter,
                           const svx::frame::Style& rAttribute )
     :   mnKey( nKey ),
         mnStartPos( nStartPos ),
         mnEndPos( nEndPos ),
         mnLimitedEndPos(0),
+        mbOuter(bOuter),
         maAttribute( rAttribute )
 {
 }
@@ -2384,10 +2388,11 @@ class SwTabFramePainter
     void Insert( SwLineEntry&, bool bHori );
     void Insert(const SwFrame& rFrame, const SvxBoxItem& rBoxItem, const 
SwRect &rPaintArea);
     void HandleFrame(const SwLayoutFrame& rFrame, const SwRect& rPaintArea);
-    void FindStylesForLine( const Point&,
-                            const Point&,
+    void FindStylesForLine( Point&,
+                            Point&,
                             svx::frame::Style*,
-                            bool bHori ) const;
+                            bool bHori,
+                            bool bOuter ) const;
 
 public:
     explicit SwTabFramePainter( const SwTabFrame& rTabFrame );
@@ -2501,7 +2506,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, 
const SwRect& rRect) cons
 
             svx::frame::Style aStyles[ 7 ];
             aStyles[ 0 ] = rEntryStyle;
-            FindStylesForLine( aStart, aEnd, aStyles, bHori );
+            FindStylesForLine(aStart, aEnd, aStyles, bHori, rEntry.mbOuter);
 
             if (!bHori && rEntry.mnLimitedEndPos)
             {
@@ -2675,10 +2680,10 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, 
const SwRect& rRect) cons
  * StartPoint or Endpoint. The styles of these lines are required for DR's 
magic
  * line painting functions
  */
-void SwTabFramePainter::FindStylesForLine( const Point& rStartPoint,
-                                         const Point& rEndPoint,
+void SwTabFramePainter::FindStylesForLine( Point& rStartPoint,
+                                         Point& rEndPoint,
                                          svx::frame::Style* pStyles,
-                                         bool bHori ) const
+                                         bool bHori, bool bOuter ) const
 {
     // For example, aLFromB means: this vertical line intersects my horizontal 
line at its left end,
     // from bottom.
@@ -2689,6 +2694,14 @@ void SwTabFramePainter::FindStylesForLine( const Point& 
rStartPoint,
     // pStyles[ 5 ] = bHori ? aRFromR : BFromB,
     // pStyles[ 6 ] = bHori ? aRFromB : BFromR,
 
+    bool bWordTableCell = false;
+    SwViewShell* pShell = mrTabFrame.getRootFrame()->GetCurrShell();
+    if (pShell)
+    {
+        const IDocumentSettingAccess& rIDSA = 
pShell->GetDoc()->getIDocumentSettingAccess();
+        bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP);
+    }
+
     SwLineEntryMap::const_iterator aMapIter = maVertLines.find( 
rStartPoint.X() );
     OSL_ENSURE( aMapIter != maVertLines.end(), "FindStylesForLine: Error" );
     const SwLineEntrySet& rVertSet = (*aMapIter).second;
@@ -2701,6 +2714,11 @@ void SwTabFramePainter::FindStylesForLine( const Point& 
rStartPoint,
                 pStyles[ 3 ] = rEntry.maAttribute;
             else if ( rStartPoint.Y() == rEntry.mnEndPos )
                 pStyles[ 1 ] = rEntry.maAttribute;
+
+            if (bWordTableCell && rStartPoint.X() == rEntry.mnKey && !bOuter 
&& rEntry.mbOuter)
+            {
+                rStartPoint.AdjustX(rEntry.maAttribute.GetWidth());
+            }
         }
         else
         {
@@ -2730,6 +2748,11 @@ void SwTabFramePainter::FindStylesForLine( const Point& 
rStartPoint,
                 pStyles[ 1 ] = rEntry.maAttribute;
             else if ( rStartPoint.X() == rEntry.mnStartPos )
                 pStyles[ 3 ] = rEntry.maAttribute;
+
+            if (bWordTableCell && rStartPoint.Y() == rEntry.mnKey && !bOuter 
&& rEntry.mbOuter)
+            {
+                rStartPoint.AdjustY(rEntry.maAttribute.GetWidth());
+            }
         }
     }
 
@@ -2745,6 +2768,11 @@ void SwTabFramePainter::FindStylesForLine( const Point& 
rStartPoint,
                 pStyles[ 6 ] = rEntry.maAttribute;
             else if ( rEndPoint.Y() == rEntry.mnEndPos )
                 pStyles[ 4 ] = rEntry.maAttribute;
+
+            if (bWordTableCell && rEndPoint.X() == rEntry.mnKey && !bOuter && 
rEntry.mbOuter)
+            {
+                rEndPoint.AdjustX(-rEntry.maAttribute.GetWidth());
+            }
         }
     }
     else
@@ -2759,6 +2787,11 @@ void SwTabFramePainter::FindStylesForLine( const Point& 
rStartPoint,
                 pStyles[ 4 ] = rEntry.maAttribute;
             else if ( rEndPoint.X() == rEntry.mnStartPos )
                 pStyles[ 6 ] = rEntry.maAttribute;
+
+            if (bWordTableCell && rEndPoint.Y() == rEntry.mnKey && !bOuter && 
rEntry.mbOuter)
+            {
+                rEndPoint.AdjustY(-rEntry.maAttribute.GetWidth());
+            }
         }
     }
 }
@@ -2826,22 +2859,32 @@ void SwTabFramePainter::Insert(const SwFrame& rFrame, 
const SvxBoxItem& rBoxItem
     aT.SetRefMode( !bVert ? svx::frame::RefMode::Begin : 
svx::frame::RefMode::End );
     aB.SetRefMode( !bVert ? svx::frame::RefMode::Begin : 
svx::frame::RefMode::End );
 
-    SwLineEntry aLeft  (nLeft,   nTop,  nBottom,
+    // First cell in a row.
+    bool bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetLower() == 
&rFrame;
+    SwLineEntry aLeft  (nLeft,   nTop,  nBottom, bOuter,
             bVert ? aB                         : (bR2L ? aR : aL));
     if (bWordTableCell && rBoxItem.GetLeft())
     {
         aLeft.LimitVerticalEndPos(rFrame, SwLineEntry::VerticalType::LEFT);
     }
 
-    SwLineEntry aRight (nRight,  nTop,  nBottom,
+    // Last cell in a row.
+    bOuter = rFrame.IsCellFrame() && rFrame.GetNext() == nullptr;
+    SwLineEntry aRight (nRight,  nTop,  nBottom, bOuter,
             bVert ? (bBottomAsTop ? aB : aT) : (bR2L ? aL : aR));
     if (bWordTableCell && rBoxItem.GetRight())
     {
         aRight.LimitVerticalEndPos(rFrame, SwLineEntry::VerticalType::RIGHT);
     }
-    SwLineEntry aTop   (nTop,    nLeft, nRight,
+
+    // First row in a table.
+    bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetUpper()->GetLower() 
== rFrame.GetUpper();
+    SwLineEntry aTop   (nTop,    nLeft, nRight, bOuter,
             bVert ? aL                         : (bBottomAsTop ? aB : aT));
-    SwLineEntry aBottom(nBottom, nLeft, nRight,
+
+    // Last row in a table.
+    bOuter = rFrame.IsCellFrame() && rFrame.GetUpper()->GetNext() == nullptr;
+    SwLineEntry aBottom(nBottom, nLeft, nRight, bOuter,
             bVert ? aR                         : aB);
 
     Insert( aLeft, false );
@@ -2870,7 +2913,7 @@ void SwTabFramePainter::Insert( SwLineEntry& rNew, bool 
bHori )
     {
         const SwLineEntry& rOld = *aIter;
 
-        if (rOld.mnLimitedEndPos)
+        if (rOld.mnLimitedEndPos || rOld.mbOuter != rNew.mbOuter)
         {
             // Don't merge with this line entry as it ends sooner than 
mnEndPos.
             ++aIter;
@@ -2888,10 +2931,10 @@ void SwTabFramePainter::Insert( SwLineEntry& rNew, bool 
bHori )
             OSL_ENSURE( rNew.mnStartPos >= rOld.mnStartPos, "Overlap type 3? 
How this?" );
 
             // new left segment
-            const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, 
rOldAttr );
+            const SwLineEntry aLeft(nKey, rOld.mnStartPos, rNew.mnStartPos, 
rOld.mbOuter, rOldAttr);
 
             // new middle segment
-            const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rOld.mnEndPos, 
rCmpAttr );
+            const SwLineEntry aMiddle(nKey, rNew.mnStartPos, rOld.mnEndPos, 
rOld.mbOuter, rCmpAttr);
 
             // new right segment
             rNew.mnStartPos = rOld.mnEndPos;
@@ -2908,13 +2951,13 @@ void SwTabFramePainter::Insert( SwLineEntry& rNew, bool 
bHori )
         else if ( SwLineEntry::OVERLAP2 == nOverlapType )
         {
             // new left segment
-            const SwLineEntry aLeft( nKey, rOld.mnStartPos, rNew.mnStartPos, 
rOldAttr );
+            const SwLineEntry aLeft(nKey, rOld.mnStartPos, rNew.mnStartPos, 
rOld.mbOuter, rOldAttr);
 
             // new middle segment
-            const SwLineEntry aMiddle( nKey, rNew.mnStartPos, rNew.mnEndPos, 
rCmpAttr );
+            const SwLineEntry aMiddle(nKey, rNew.mnStartPos, rNew.mnEndPos, 
rOld.mbOuter, rCmpAttr);
 
             // new right segment
-            const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, 
rOldAttr );
+            const SwLineEntry aRight(nKey, rNew.mnEndPos, rOld.mnEndPos, 
rOld.mbOuter, rOldAttr);
 
             // update current lines set
             pLineSet->erase( aIter );
@@ -2929,13 +2972,13 @@ void SwTabFramePainter::Insert( SwLineEntry& rNew, bool 
bHori )
         else if ( SwLineEntry::OVERLAP3 == nOverlapType )
         {
             // new left segment
-            const SwLineEntry aLeft( nKey, rNew.mnStartPos, rOld.mnStartPos, 
rNewAttr );
+            const SwLineEntry aLeft(nKey, rNew.mnStartPos, rOld.mnStartPos, 
rOld.mbOuter, rNewAttr);
 
             // new middle segment
-            const SwLineEntry aMiddle( nKey, rOld.mnStartPos, rNew.mnEndPos, 
rCmpAttr );
+            const SwLineEntry aMiddle(nKey, rOld.mnStartPos, rNew.mnEndPos, 
rOld.mbOuter, rCmpAttr);
 
             // new right segment
-            const SwLineEntry aRight( nKey, rNew.mnEndPos, rOld.mnEndPos, 
rOldAttr );
+            const SwLineEntry aRight(nKey, rNew.mnEndPos, rOld.mnEndPos, 
rOld.mbOuter, rOldAttr);
 
             // update current lines set
             pLineSet->erase( aIter );
commit 8b11be830eda11508b9662582bc8056181384615
Author:     Luboš Luňák <l.lu...@centrum.cz>
AuthorDate: Wed Jan 26 13:34:08 2022 +0100
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Feb 13 19:46:03 2022 +0100

    MSVC -arch is independent from the ability to use CPU intrinsics
    
    It's possible to write AVX512 intrinsics in code compile only with
    -arch:AVX . So do not require -arch for being able to do so,
    especially since there is no -arch option for only AVX512F without
    other AVX512 subsets (the option enables also CD, BW, DQ and VL
    https://docs.microsoft.com/en-us/cpp/build/reference/arch-x64).
    
    
https://crashreport.libreoffice.org/stats/crash_details/55ef825d-c323-4df9-95e2-76672c674e60
    is presumably caused by this, I can see use of registers XMM0-15
    in arraysumAVX512.cxx built with -arch:AVX2 but when built
    with -arch:AVX512 registers XMM16-31 are used too (I'm not sure
    if that's AVX512DQ or something else, I can't find info on it).
    
    Change-Id: I74473333a17e618327d43b920b8929d1b0e733b8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129724
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 807a15bd64c1f2a57371d12e7684541293cd9791)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129765
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/configure.ac b/configure.ac
index e9cac7e398e6..eaab62102bdc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7709,22 +7709,27 @@ if test "$GCC" = "yes" -o "$COM_IS_CLANG" = TRUE; then
     flag_f16c=-mf16c
     flag_fma=-mfma
 else
-    # https://docs.microsoft.com/en-us/cpp/build/reference/arch-x86
-    # MSVC seems to differentiate only between SSE and SSE2, where in fact
-    # SSE2 seems to be SSE2+.
-    # Even if -arch:SSE2 is the default, set it explicitly, so that the 
variable
-    # is not empty (and can be tested in gbuild).
-    flag_sse2=-arch:SSE2
-    flag_ssse3=-arch:SSE2
-    flag_sse41=-arch:SSE2
-    flag_sse42=-arch:SSE2
+    # With MSVC using -arch is in fact not necessary for being able
+    # to use CPU intrinsics, code using AVX512F intrinsics will compile
+    # even if compiled with -arch:AVX, the -arch option really only affects
+    # instructions generated for C/C++ code.
+    # So use the matching same (or lower) -arch options, but only in order
+    # to generate the best matching instructions for the C++ code surrounding
+    # the intrinsics.
+    # SSE2 is the default for x86/x64, so no need to specify the option.
+    flag_sse2=
+    # No specific options for these, use the next lower.
+    flag_ssse3="$flag_sse2"
+    flag_sse41="$flag_sse2"
+    flag_sse42="$flag_sse2"
     flag_avx=-arch:AVX
     flag_avx2=-arch:AVX2
     flag_avx512=-arch:AVX512
-    flag_avx512f=-arch:AVX512
-    # These are part of -arch:AVX2
-    flag_f16c=-arch:AVX2
-    flag_fma=-arch:AVX2
+    # Using -arch:AVX512 would enable more than just AVX512F, so use only AVX2.
+    flag_avx512f=-arch:AVX2
+    # No MSVC options for these.
+    flag_f16c="$flag_sse2"
+    flag_fma="$flag_sse2"
 fi
 
 AC_MSG_CHECKING([whether $CXX can compile SSE2 intrinsics])
diff --git a/include/tools/simdsupport.hxx b/include/tools/simdsupport.hxx
index 738b34e072db..fa8923bb095f 100644
--- a/include/tools/simdsupport.hxx
+++ b/include/tools/simdsupport.hxx
@@ -34,34 +34,21 @@
 
 #if defined(_MSC_VER) // VISUAL STUDIO COMPILER
 
-// SSE2 is required for X64
-#if (defined(_M_X64) || defined(_M_IX86_FP) && _M_IX86_FP >= 2)
+// With MSVC using -arch is in fact not necessary for being able

... etc. - the rest is truncated

Reply via email to