external/liborcus/UnpackedTarball_liborcus.mk                        |    5 
 external/liborcus/forcepoint-83.patch.1                              |   38 
 hwpfilter/source/hbox.cxx                                            |   12 
 include/oox/export/drawingml.hxx                                     |   13 
 include/svx/svdedtv.hxx                                              |    2 
 instsetoo_native/inc_openoffice/unix/find-requires-x11.sh            |    2 
 oox/qa/unit/data/tdf147978_endsubpath.odp                            |binary
 oox/qa/unit/data/tdf147978_enhancedPath_commandA.odp                 |binary
 oox/qa/unit/data/tdf147978_enhancedPath_commandHIJK.odp              |binary
 oox/qa/unit/data/tdf147978_enhancedPath_commandT.odp                 |binary
 oox/qa/unit/data/tdf147978_enhancedPath_commandXY.odp                |binary
 oox/qa/unit/data/tdf147978_enhancedPath_subpath.pptx                 |binary
 oox/qa/unit/export.cxx                                               |  155 +
 oox/source/export/drawingml.cxx                                      |  919 
++++++----
 oox/source/export/shapes.cxx                                         |   31 
 sc/qa/unit/data/xlsx/tdf147014.xlsx                                  |binary
 sc/qa/unit/subsequent_filters_test2.cxx                              |   18 
 sc/qa/unit/tiledrendering/tiledrendering.cxx                         |   31 
 sc/source/filter/oox/worksheethelper.cxx                             |   25 
 sc/source/ui/view/cellsh2.cxx                                        |   49 
 sc/source/ui/view/gridwin4.cxx                                       |    4 
 sc/source/ui/view/tabvwsh2.cxx                                       |   11 
 sd/qa/unit/data/odp/tdf147978_enhancedPath_viewBox.odp               |binary
 sd/qa/unit/data/xml/tdf92001_0.xml                                   |   42 
 sd/qa/unit/export-tests-ooxml2.cxx                                   |   32 
 sd/qa/unit/export-tests-ooxml3.cxx                                   |   16 
 svx/sdi/svx.sdi                                                      |    2 
 svx/source/svdraw/svdedtv.cxx                                        |    7 
 sw/inc/deletelistener.hxx                                            |   92 +
 sw/qa/extras/layout/data/forcepoint92.doc                            |binary
 sw/qa/extras/layout/layout.cxx                                       |    6 
 sw/qa/extras/ooxmlexport/data/tdf147978_enhancedPath_commandABVW.odt |binary
 sw/qa/extras/ooxmlexport/data/tdf148111.docx                         |binary
 sw/qa/extras/ooxmlexport/ooxmlexport17.cxx                           |   44 
 sw/qa/extras/ooxmlexport/ooxmlexport7.cxx                            |   24 
 sw/qa/extras/uiwriter/uiwriter3.cxx                                  |   16 
 sw/source/core/frmedt/tblsel.cxx                                     |   11 
 sw/source/core/layout/layact.cxx                                     |    3 
 sw/source/core/layout/tabfrm.cxx                                     |    8 
 sw/source/core/text/itratr.cxx                                       |    2 
 sw/source/core/undo/untbl.cxx                                        |   29 
 sw/source/filter/ww8/docxsdrexport.cxx                               |   20 
 sw/source/filter/ww8/rtfattributeoutput.cxx                          |    4 
 sw/source/filter/ww8/ww8par2.cxx                                     |   71 
 sw/uiconfig/swxform/toolbar/formdesign.xml                           |    2 
 vcl/source/helper/strhelper.cxx                                      |    3 
 writerfilter/source/dmapper/SdtHelper.cxx                            |    3 
 47 files changed, 1245 insertions(+), 507 deletions(-)

New commits:
commit a39eed087762afe703561782aeebdd8aa28118be
Merge: 00e7d7588b8a 6b1071b6096f
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Wed Mar 30 06:50:04 2022 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Wed Mar 30 06:50:04 2022 +0200

    Merge branch 'libreoffice-7-3'
    
    into distro/lhm/libreoffice-7-3+backports
    
    Change-Id: I0a6e4a1a1dd38bdad0a146aec1f839786fd78fa5

commit 6b1071b6096f65de1244f8f3994366bb9cd0ff09
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Wed Mar 23 16:49:03 2022 +0000
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Mar 29 11:53:22 2022 +0200

    forcepoint#83 Invalid read of size 1
    
    Change-Id: I1576dfd8c9731d943107764aeb66bb1c2294ad5f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131996
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/external/liborcus/UnpackedTarball_liborcus.mk 
b/external/liborcus/UnpackedTarball_liborcus.mk
index 87e462e33d91..a87da7edb88d 100644
--- a/external/liborcus/UnpackedTarball_liborcus.mk
+++ b/external/liborcus/UnpackedTarball_liborcus.mk
@@ -15,8 +15,8 @@ $(eval $(call gb_UnpackedTarball_set_patchlevel,liborcus,1))
 
 $(eval $(call gb_UnpackedTarball_update_autoconf_configs,liborcus))
 
-# crashtesting-crash-on-passing-null-to-std-string_vie.patch.1 submitted as
-# https://gitlab.com/orcus/orcus/-/merge_requests/113
+# forcepoint-83.patch.1 submitted as
+# https://gitlab.com/orcus/orcus/-/merge_requests/117
 
 $(eval $(call gb_UnpackedTarball_add_patches,liborcus,\
        external/liborcus/rpath.patch.0 \
@@ -25,6 +25,7 @@ $(eval $(call gb_UnpackedTarball_add_patches,liborcus,\
        external/liborcus/fix-pch.patch.0 \
        external/liborcus/liborcus_newline.patch.1 \
        external/liborcus/std-get-busted.patch.1 \
+       external/liborcus/forcepoint-83.patch.1 \
 ))
 
 ifeq ($(OS),WNT)
diff --git a/external/liborcus/forcepoint-83.patch.1 
b/external/liborcus/forcepoint-83.patch.1
new file mode 100644
index 000000000000..bfd3bb86fcf9
--- /dev/null
+++ b/external/liborcus/forcepoint-83.patch.1
@@ -0,0 +1,38 @@
+From 283b45ba3bcb22dc28303a09a96c9b94f86d1ba2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caol...@redhat.com>
+Date: Wed, 23 Mar 2022 16:44:00 +0000
+Subject: [PATCH] forcepoint#83 Invalid read of size 1
+
+==343916== Invalid read of size 1
+==343916==    at 0x11A7B2F0: orcus::parser_base::cur_char() const 
(parser_base.hpp:79)
+==343916==    by 0x11B7B112: 
orcus::sax_parser<orcus::sax_ns_parser<orcus::sax_token_parser<orcus::xml_stream_handler>::handler_wrapper>::handler_wrapper,
 orcus::sax_parser_default_config>::element_open(long) (sax_parser.hpp:258)
+==343916==    by 0x11B7A2C7: 
orcus::sax_parser<orcus::sax_ns_parser<orcus::sax_token_parser<orcus::xml_stream_handler>::handler_wrapper>::handler_wrapper,
 orcus::sax_parser_default_config>::element() (sax_parser.hpp:246)
+==343916==    by 0x11B7A197: 
orcus::sax_parser<orcus::sax_ns_parser<orcus::sax_token_parser<orcus::xml_stream_handler>::handler_wrapper>::handler_wrapper,
 orcus::sax_parser_default_config>::body() (sax_parser.hpp:214)
+==343916==    by 0x11B79FD9: 
orcus::sax_parser<orcus::sax_ns_parser<orcus::sax_token_parser<orcus::xml_stream_handler>::handler_wrapper>::handler_wrapper,
 orcus::sax_parser_default_config>::parse() (sax_parser.hpp:182)
+==343916==    by 0x11B79F8B: 
orcus::sax_ns_parser<orcus::sax_token_parser<orcus::xml_stream_handler>::handler_wrapper>::parse()
 (sax_ns_parser.hpp:277)
+==343916==    by 0x11B79768: 
orcus::sax_token_parser<orcus::xml_stream_handler>::parse() 
(sax_token_parser.hpp:215)
+==343916==    by 0x11B79406: orcus::xml_stream_parser::parse() 
(xml_stream_parser.cpp:68)
+==343916==    by 0x11BE3805: orcus::orcus_xlsx::detect(unsigned char const*, 
unsigned long) (orcus_xlsx.cpp:188)
+==343916==    by 0x11AB2482: orcus::detect(unsigned char const*, unsigned 
long) (format_detection.cpp:60)
+==343916==    by 0x30E60945: (anonymous 
namespace)::OrcusFormatDetect::detect(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>&)
 (filterdetect.cxx:83)
+==343916==    by 0x30E60ABE: non-virtual thunk to (anonymous 
namespace)::OrcusFormatDetect::detect(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>&)
 (filterdetect.cxx:0)
+---
+ include/orcus/sax_parser.hpp | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/include/orcus/sax_parser.hpp b/include/orcus/sax_parser.hpp
+index 15e8d917..d0fc45b5 100644
+--- a/include/orcus/sax_parser.hpp
++++ b/include/orcus/sax_parser.hpp
+@@ -255,6 +255,8 @@ void 
sax_parser<_Handler,_Config>::element_open(std::ptrdiff_t begin_pos)
+     while (true)
+     {
+         skip_space_and_control();
++        if (!has_char())
++            return;
+         char c = cur_char();
+         if (c == '/')
+         {
+-- 
+2.35.1
+
commit e672a8351df5e9fcbdafa34857a16f2bd547ebd6
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Fri Mar 25 12:10:32 2022 +0000
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Mar 29 11:38:54 2022 +0200

    forcepoint#89 don't remove page with footnote continuation frame
    
    in browse/html/web mode
    
    Change-Id: Ic821dd7f2cc1f47305b5fe2ced16d5168aedc0b9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132045
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index 33a990a15a5a..da6e7c938f6b 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -295,7 +295,8 @@ bool SwLayAction::RemoveEmptyBrowserPages()
         do
         {
             if ( (pPage->GetSortedObjs() && pPage->GetSortedObjs()->size()) ||
-                 pPage->ContainsContent() )
+                 pPage->ContainsContent() ||
+                 pPage->FindFootnoteCont() )
                 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
             else
             {
commit 0d0cee5e48ca523f11540e9ae0ff022692fd9dca
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Sun Mar 27 12:03:06 2022 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Mar 29 11:38:00 2022 +0200

    forcepoint#92 fix crash on layout of specific doc
    
    Change-Id: Id40d25d05d10d641d071cddd2e1c84594ac777a6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132142
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132148
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/qa/extras/layout/data/forcepoint92.doc 
b/sw/qa/extras/layout/data/forcepoint92.doc
new file mode 100644
index 000000000000..49c4a7f11dfe
Binary files /dev/null and b/sw/qa/extras/layout/data/forcepoint92.doc differ
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index 94edf650a359..bde69da4dde3 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -2496,6 +2496,12 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter, 
testForcepointFootnoteFrame)
 //FIXME: disabled after failing again with fixed layout
 //CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint76) { 
createSwDoc(DATA_DIRECTORY, "forcepoint76-1.rtf"); }
 
+//just care it doesn't crash/assert
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint92)
+{
+    createSwDoc(DATA_DIRECTORY, "forcepoint92.doc");
+}
+
 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf118058)
 {
     SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf118058.fodt");
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 7786f3aec4fc..b405a2124254 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -24,6 +24,7 @@
 #include <viewimp.hxx>
 #include <fesh.hxx>
 #include <swtable.hxx>
+#include <deletelistener.hxx>
 #include <dflyobj.hxx>
 #include <anchoreddrawobject.hxx>
 #include <fmtanchr.hxx>
@@ -2114,13 +2115,18 @@ void SwTabFrame::MakeAll(vcl::RenderContext* 
pRenderContext)
             }
             SwFootnoteBossFrame *pOldBoss = bFootnotesInDoc ? 
FindFootnoteBossFrame( true ) : nullptr;
             bool bReformat;
+            std::optional<SfxDeleteListener> oDeleteListener;
+            if (pOldBoss)
+                oDeleteListener.emplace(*pOldBoss);
             SwFrameDeleteGuard g(this);
             if ( MoveBwd( bReformat ) )
             {
+                SAL_WARN_IF(oDeleteListener && oDeleteListener->WasDeleted(), 
"sw.layout", "SwFootnoteBossFrame unexpectedly deleted");
+
                 aRectFnSet.Refresh(this);
                 bMovedBwd = true;
                 aNotify.SetLowersComplete( false );
-                if ( bFootnotesInDoc )
+                if (bFootnotesInDoc && !oDeleteListener->WasDeleted())
                     MoveLowerFootnotes( nullptr, pOldBoss, nullptr, true );
                 if ( bReformat || bKeep )
                 {
commit 26872d9b408660056fedfa18ba2be25a14b771c1
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Sat Mar 26 21:50:49 2022 +0000
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Mar 29 11:30:20 2022 +0200

    move DeleteListener contraptions to toplevel writer includes
    
    Change-Id: Ifa1e75b62da4174f27fca52eb86559cd6a381513
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132141
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132147
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/inc/deletelistener.hxx b/sw/inc/deletelistener.hxx
new file mode 100644
index 000000000000..2b212e418fef
--- /dev/null
+++ b/sw/inc/deletelistener.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <svl/listener.hxx>
+#include <svl/lstner.hxx>
+#include "calbck.hxx"
+
+class SwDeleteListener final : public SwClient
+{
+private:
+    SwModify* m_pModify;
+
+    virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) override
+    {
+        if (rHint.GetId() != SfxHintId::SwLegacyModify)
+            return;
+        auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
+        if (pLegacy->GetWhich() == RES_OBJECTDYING)
+        {
+            m_pModify->Remove(this);
+            m_pModify = nullptr;
+        }
+    }
+
+public:
+    SwDeleteListener(SwModify& rModify)
+        : m_pModify(&rModify)
+    {
+        m_pModify->Add(this);
+    }
+
+    bool WasDeleted() const { return !m_pModify; }
+
+    virtual ~SwDeleteListener() override
+    {
+        if (!m_pModify)
+            return;
+        m_pModify->Remove(this);
+    }
+};
+
+class SvtDeleteListener final : public SvtListener
+{
+private:
+    bool bObjectDeleted;
+
+public:
+    explicit SvtDeleteListener(SvtBroadcaster& rNotifier)
+        : bObjectDeleted(false)
+    {
+        StartListening(rNotifier);
+    }
+
+    virtual void Notify(const SfxHint& rHint) override
+    {
+        if (rHint.GetId() == SfxHintId::Dying)
+            bObjectDeleted = true;
+    }
+
+    bool WasDeleted() const { return bObjectDeleted; }
+};
+
+class SfxDeleteListener final : public SfxListener
+{
+private:
+    bool bObjectDeleted;
+
+public:
+    explicit SfxDeleteListener(SfxBroadcaster& rNotifier)
+        : bObjectDeleted(false)
+    {
+        StartListening(rNotifier);
+    }
+
+    virtual void Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint) override
+    {
+        if (rHint.GetId() == SfxHintId::Dying)
+            bObjectDeleted = true;
+    }
+
+    bool WasDeleted() const { return bObjectDeleted; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sw/source/filter/ww8/ww8par2.cxx b/sw/source/filter/ww8/ww8par2.cxx
index 3f3c3adfb74f..540b25018743 100644
--- a/sw/source/filter/ww8/ww8par2.cxx
+++ b/sw/source/filter/ww8/ww8par2.cxx
@@ -39,6 +39,7 @@
 #include <editeng/pgrditem.hxx>
 #include <msfilter.hxx>
 #include <pam.hxx>
+#include <deletelistener.hxx>
 #include <doc.hxx>
 #include <IDocumentStylePoolAccess.hxx>
 #include <docary.hxx>
@@ -167,32 +168,6 @@ sal_uInt32 wwSectionManager::GetWWPageTopMargin() const
     return !maSegments.empty() ? maSegments.back().maSep.dyaTop : 0;
 }
 
-namespace
-{
-    class DeleteListener final : public SvtListener
-    {
-    private:
-        bool bObjectDeleted;
-    public:
-        explicit DeleteListener(SvtBroadcaster& rNotifier)
-            : bObjectDeleted(false)
-        {
-            StartListening(rNotifier);
-        }
-
-        virtual void Notify(const SfxHint& rHint) override
-        {
-            if (rHint.GetId() == SfxHintId::Dying)
-                bObjectDeleted = true;
-        }
-
-        bool WasDeleted() const
-        {
-            return bObjectDeleted;
-        }
-    };
-}
-
 sal_uInt16 SwWW8ImplReader::End_Footnote()
 {
     /*
@@ -252,7 +227,7 @@ sal_uInt16 SwWW8ImplReader::End_Footnote()
 
         SwFormatFootnote& rFormatFootnote = 
static_cast<SwFormatFootnote&>(pFN->GetAttr());
 
-        DeleteListener aDeleteListener(rFormatFootnote.GetNotifier());
+        SvtDeleteListener aDeleteListener(rFormatFootnote.GetNotifier());
 
         // read content of Ft-/End-Note
         Read_HdFtFootnoteText( pSttIdx, rDesc.mnStartCp, rDesc.mnLen, 
rDesc.meType);
@@ -2783,46 +2758,6 @@ void WW8TabDesc::MoveOutsideTable()
         *m_pIo->m_pPaM->GetPoint() = *m_xTmpPos->GetPoint();
 }
 
-namespace
-{
-    class SwTableNodeListener final : public SwClient
-    {
-    private:
-        SwModify* m_pModify;
-
-        virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) 
override
-        {
-            if (rHint.GetId() != SfxHintId::SwLegacyModify)
-                return;
-            auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
-            if (pLegacy->GetWhich() == RES_OBJECTDYING)
-            {
-                m_pModify->Remove(this);
-                m_pModify = nullptr;
-            }
-        }
-
-    public:
-        SwTableNodeListener(SwModify* pModify)
-            : m_pModify(pModify)
-        {
-            m_pModify->Add(this);
-        }
-
-        bool WasDeleted() const
-        {
-            return !m_pModify;
-        }
-
-        virtual ~SwTableNodeListener() override
-        {
-            if (!m_pModify)
-                return;
-            m_pModify->Remove(this);
-        }
-    };
-}
-
 void WW8TabDesc::FinishSwTable()
 {
     m_pIo->m_xRedlineStack->closeall(*m_pIo->m_pPaM->GetPoint());
@@ -2833,7 +2768,7 @@ void WW8TabDesc::FinishSwTable()
     m_pIo->m_pLastAnchorPos.reset();
 
     SwTableNode* pTableNode = m_pTable->GetTableNode();
-    SwTableNodeListener aListener(pTableNode);
+    SwDeleteListener aListener(*pTableNode);
     m_pIo->m_xRedlineStack = std::move(mxOldRedlineStack);
 
     if (xLastAnchorCursor)
commit 2bbd6998aefe4a83c93a1810430f1a0da5364284
Author:     Aron Budea <aron.bu...@collabora.com>
AuthorDate: Thu Mar 24 22:02:17 2022 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Tue Mar 29 10:32:34 2022 +0200

    sc: fix crash in SdrPageView::GetPageWindow()
    
    From online crashreport:
    
    SIG   Fatal signal received: SIGSEGV
    
    SdrPageView::GetPageWindow(unsigned int) const
                    svx/source/svdraw/svdpagv.cxx:84
    (anonymous 
namespace)::ScLOKProxyObjectContact::calculateGridOffsetForViewOjectContact(basegfx::B2DVector&,
 sdr::contact::ViewObjectContact const&) const
                    sc/source/ui/view/gridwin4.cxx:1397
    sdr::contact::ViewObjectContact::getGridOffset() const
                    svx/source/sdr/contact/viewobjectcontact.cxx:463
    
sdr::contact::ViewObjectContact::getPrimitive2DSequence(sdr::contact::DisplayInfo
 const&) const
                    include/basegfx/tuple/b2dtuple.hxx:81
    sdr::contact::ViewObjectContact::getObjectRange() const
                    svx/source/sdr/contact/viewobjectcontact.cxx:198
    
    ScLOKProxyObjectContact::calculateGridOffsetForViewOjectContact()
    didn't check if PageWindowCount() was non-zero.
    
    Change-Id: I4a00b5b13a277d0805af3076150a952306908e53
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132251
    Tested-by: Jenkins
    Reviewed-by: Aron Budea <aron.bu...@collabora.com>
    (cherry picked from commit 5d0965f3f12fedb2228ba28f261a90245e343c09)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132181
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index 5da4a54508d2..d1aa33f4c847 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -1355,7 +1355,9 @@ namespace
             if (!pPageView)
                 return;
 
-            SdrPageWindow* pSdrPageWindow = pPageView->GetPageWindow(0);
+            SdrPageWindow* pSdrPageWindow = nullptr;
+            if (pPageView->PageWindowCount() > 0)
+                pSdrPageWindow = pPageView->GetPageWindow(0);
             if (!pSdrPageWindow)
                 return;
 
commit e42219cb3664b3727a6b399153d7891108c01f0c
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Mon Mar 28 11:05:34 2022 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Tue Mar 29 06:16:16 2022 +0200

    tdf#148235 Restore toolbar item to switch XForm to design mode
    
        commit 45b6f096e7ae86d0692ecdfd5b7069622d8a6efa
        Date:   Sun Oct 28 17:02:34 2018 +0100
    
            sw toolbars sync context toolbars between different apps
    
    had replaced the "Form Design" toolbar item to switch
    a complete XForm to design mode with an entry that
    switches the form controls to design mode instead.
    (The former one is labelled "Design Mode On/Off",
    the latter one just "Design Mode" in the English UI.)
    
    This meant that the XForm could no longer be switched
    to design mode from there, unless the toolbar was
    manually customized to add the entry back.
    
    This brings the previous toolbar item back.
    It also removes the one to switch the form controls
    to design mode again, since that one is already contained
    in the "Form Controls" toolbar, where it fits better.
    (And having two different toolbar items with almost
    identical labels but different functionality would
    probably be rather confusing.)
    
    Change-Id: Ia4c98dfa6ad8372eba08a9f08920153133a7f88d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132207
    Reviewed-by: Andreas Kainz <kain...@gmail.com>
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins
    (cherry picked from commit 4f9bf4201bb706cd19142f0805cfc4c859186cd4)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132177
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>

diff --git a/sw/uiconfig/swxform/toolbar/formdesign.xml 
b/sw/uiconfig/swxform/toolbar/formdesign.xml
index 067ddff0675f..f748bcf68e2e 100644
--- a/sw/uiconfig/swxform/toolbar/formdesign.xml
+++ b/sw/uiconfig/swxform/toolbar/formdesign.xml
@@ -44,7 +44,7 @@
  <toolbar:toolbaritem xlink:href=".uno:LeaveGroup" toolbar:visible="false"/>
  <toolbar:toolbarseparator/>
  <toolbar:toolbaritem xlink:href=".uno:SelectObject"/>
- <toolbar:toolbaritem xlink:href=".uno:SwitchControlDesignMode"/>
+ <toolbar:toolbaritem xlink:href=".uno:SwitchXFormsDesignMode"/>
  <toolbar:toolbarseparator/>
  <toolbar:toolbaritem xlink:href=".uno:ControlProperties"/>
  <toolbar:toolbaritem xlink:href=".uno:FormProperties"/>
commit 0c1894acda828c02c76c97c25149187cb04ae91f
Author:     Mark Hung <mark...@gmail.com>
AuthorDate: Sat Mar 19 21:18:54 2022 +0800
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Mar 28 20:53:46 2022 +0200

    tdf#141671 fix destroyed pargraph style in exported RTF in MSO.
    
    Do not call MoveCharacterProperties() in RtfAttributeOutput
    ::EndParagraphProperties(). RtfAttributeOutput::ParagraphStyle() has
    emited run associated properties defined in paragraph style.
    Calling MoveCharacterProperties() again overwrites them.
    
    As this bug is only visible in MS Word, no unit test case is
    added.
    
    Change-Id: I6e5bfd12e8afa7dc286ca54448c1ff022aade31d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131848
    Tested-by: Jenkins
    Reviewed-by: Mark Hung <mark...@gmail.com>
    (cherry picked from commit 882045b934a3416cc48da2c4e30648892a419577)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132175
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index cc7d61c80d75..ca43274da2c7 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -384,7 +384,9 @@ void RtfAttributeOutput::EndParagraphProperties(
     const SwRedlineData* /*pRedlineParagraphMarkerDeleted*/,
     const SwRedlineData* /*pRedlineParagraphMarkerInserted*/)
 {
-    const OString aProperties = MoveCharacterProperties(true);
+    // Do not call MoveCharacterProperties(),
+    // Otherwise associate properties in the paragraph style are ruined.
+    const OString aProperties = m_aStyles.makeStringAndClear();
     m_rExport.Strm().WriteOString(aProperties);
 }
 
commit 8baae1fe3de398f1e6a01d1941f78e4088c0a697
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Mon Mar 28 11:35:35 2022 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Mar 28 20:53:15 2022 +0200

    tdf#148228 sw: fix Undo of tracked table deletion in Hide Changes mode
    
    In Hide Changes mode, tables didn't reappear during
    Undo of their tracked deletion, only by saving and
    reloading the document.
    
    Follow-up to commit 0c6221e1545e7b96d9df23cdc24302c28ae935b8
    "tdf#148227 sw: fix Undo of tracked row deletion in Hide Changes mode".
    
    Change-Id: Ifdc25ab4ae0be25a0c7559ee05b6af2e4f1aa8cf
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132169
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>
    (cherry picked from commit eda1a7aeff42c08e02295e5a8353a6d86a61a118)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132178
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/qa/extras/uiwriter/uiwriter3.cxx 
b/sw/qa/extras/uiwriter/uiwriter3.cxx
index 57f5e6649b70..559d47641a99 100644
--- a/sw/qa/extras/uiwriter/uiwriter3.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter3.cxx
@@ -1988,7 +1988,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf146962)
     // only a single row is visible again
     assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 1);
 
-    // check Undo
+    // tdf#148227 check Undo of tracked table row deletion
 
     dispatchCommand(mxComponent, ".uno:Undo", {});
     discardDumpedLayout();
@@ -2040,6 +2040,14 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf147347)
     pXmlDoc = parseLayoutDump();
     // no visible row again
     assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 0);
+
+    // tdf#148228 check Undo of tracked table deletion
+
+    dispatchCommand(mxComponent, ".uno:Undo", {});
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    // This was 0
+    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);
 }
 
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf135014)
diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx
index d5536b01e624..d5c15a0fbc4a 100644
--- a/sw/source/core/undo/untbl.cxx
+++ b/sw/source/core/undo/untbl.cxx
@@ -952,14 +952,20 @@ void SaveTable::RestoreAttr( SwTable& rTable, bool 
bMdfyBox )
 
     pFormat->InvalidateInSwCache(RES_ATTRSET_CHG);
 
+    // table without table frame
+    bool bHiddenTable = true;
+
     // for safety, invalidate all TableFrames
     SwIterator<SwTabFrame,SwFormat> aIter( *pFormat );
     for( SwTabFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
+    {
         if( pLast->GetTable() == &rTable )
         {
             pLast->InvalidateAll();
             pLast->SetCompletePaint();
+            bHiddenTable = false;
         }
+    }
 
     // fill FrameFormats with defaults (0)
     pFormat = nullptr;
@@ -986,7 +992,19 @@ void SaveTable::RestoreAttr( SwTable& rTable, bool 
bMdfyBox )
     m_bModifyBox = false;
 
     if ( bHideChanges )
-        aTmpBox.MakeFrames( rTable );
+    {
+        if ( bHiddenTable )
+        {
+            SwTableNode* pTableNode = rTable.GetTableNode();
+            pTableNode->DelFrames();
+            SwNodeIndex aTableIdx( *pTableNode->EndOfSectionNode(), 1 );
+            pTableNode->MakeOwnFrames(&aTableIdx);
+        }
+        else
+        {
+            aTmpBox.MakeFrames( rTable );
+        }
+    }
 }
 
 void SaveTable::SaveContentAttrs( SwDoc* pDoc )
commit e07ea7a6f5f7059663e99daa97cbda5e63b141dd
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Fri Mar 25 15:27:21 2022 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Mar 28 20:52:58 2022 +0200

    tdf#148227 sw: fix Undo of tracked row deletion in Hide Changes mode
    
    In Hide Changes mode, table rows didn't reappear during
    Undo of tracked deletion of table rows, only by saving
    and reloading the document.
    
    Follow-up to commit a74c51025fa4519caaf461492e4ed8e68bd34885
    "tdf#146962 sw: hide deleted row at deletion in Hide Changes"
    and commit 794fd10af7361d5a64a0f8bfbe5c8b5f308617a5
    "tdf#147347 sw: hide deleted table at deletion in Hide Changes".
    
    Change-Id: I7ffe8a3687d1d385a549f7d438f7058d829ffd8c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132123
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>
    (cherry picked from commit 0c6221e1545e7b96d9df23cdc24302c28ae935b8)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132049
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sw/qa/extras/uiwriter/uiwriter3.cxx 
b/sw/qa/extras/uiwriter/uiwriter3.cxx
index b8cb857043b2..57f5e6649b70 100644
--- a/sw/qa/extras/uiwriter/uiwriter3.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter3.cxx
@@ -1987,6 +1987,14 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf146962)
     pXmlDoc = parseLayoutDump();
     // only a single row is visible again
     assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 1);
+
+    // check Undo
+
+    dispatchCommand(mxComponent, ".uno:Undo", {});
+    discardDumpedLayout();
+    pXmlDoc = parseLayoutDump();
+    // This was 1
+    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row", 2);
 }
 
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf147347)
diff --git a/sw/source/core/frmedt/tblsel.cxx b/sw/source/core/frmedt/tblsel.cxx
index 80b797384859..b203281506cd 100644
--- a/sw/source/core/frmedt/tblsel.cxx
+++ b/sw/source/core/frmedt/tblsel.cxx
@@ -2336,6 +2336,10 @@ void FndBox_::MakeFrames( SwTable &rTable )
     // And this for all instances of a table (for example in header/footer).
     sal_uInt16 nStPos = 0;
     sal_uInt16 nEndPos= rTable.GetTabLines().size() - 1;
+    SwRootFrame* pLayout =
+        
rTable.GetFrameFormat()->GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout();
+    bool bHideChanges = pLayout && pLayout->IsHideRedlines();
+
     if ( m_pLineBefore )
     {
         nStPos = rTable.GetTabLines().GetPos(
@@ -2389,9 +2393,14 @@ void FndBox_::MakeFrames( SwTable &rTable )
 // ???? or is this the last Follow of the table ????
                 pUpperFrame = pTable;
 
+            SwRedlineTable::size_type nRedlinePos = 0;
             for ( sal_uInt16 j = nStPos; j <= nEndPos; ++j )
-                ::lcl_InsertRow( *rTable.GetTabLines()[j],
+            {
+                SwTableLine * pLine = rTable.GetTabLines()[j];
+                if ( !bHideChanges || !pLine->IsDeleted(nRedlinePos) )
+                    ::lcl_InsertRow( *pLine,
                                 static_cast<SwLayoutFrame*>(pUpperFrame), 
pSibling );
+            }
             if ( pUpperFrame->IsTabFrame() )
                 static_cast<SwTabFrame*>(pUpperFrame)->SetCalcLowers();
         }
diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx
index d3294b5446a3..d5536b01e624 100644
--- a/sw/source/core/undo/untbl.cxx
+++ b/sw/source/core/undo/untbl.cxx
@@ -34,6 +34,8 @@
 #include <IDocumentRedlineAccess.hxx>
 #include <IDocumentFieldsAccess.hxx>
 #include <IDocumentStylePoolAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <rootfrm.hxx>
 #include <editsh.hxx>
 #include <docary.hxx>
 #include <ndtxt.hxx>
@@ -936,6 +938,12 @@ void SaveTable::RestoreAttr( SwTable& rTable, bool 
bMdfyBox )
 {
     m_bModifyBox = bMdfyBox;
 
+    FndBox_ aTmpBox( nullptr, nullptr );
+    bool bHideChanges = 
rTable.GetFrameFormat()->GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout()->IsHideRedlines();
+    // TODO delete/make frames only at changing line attribute TextChangesOnly 
(RES_PRINT) to true again
+    if ( bHideChanges )
+        aTmpBox.DelFrames( rTable );
+
     // first, get back attributes of TableFrameFormat
     SwFrameFormat* pFormat = rTable.GetFrameFormat();
     SfxItemSet& rFormatSet  = const_cast<SfxItemSet&>(static_cast<SfxItemSet 
const &>(pFormat->GetAttrSet()));
@@ -976,6 +984,9 @@ void SaveTable::RestoreAttr( SwTable& rTable, bool bMdfyBox 
)
 
     m_aFrameFormats.clear();
     m_bModifyBox = false;
+
+    if ( bHideChanges )
+        aTmpBox.MakeFrames( rTable );
 }
 
 void SaveTable::SaveContentAttrs( SwDoc* pDoc )
commit 4a614ad8c32ad09f4085980e49dce251358a0a46
Author:     Aron Budea <aron.bu...@collabora.com>
AuthorDate: Sun Feb 13 06:57:16 2022 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Mar 28 14:04:11 2022 +0200

    tdf#147014 Image missing due to integer overflow
    
    32-bit awt::Point/Size/Rectangle cannot fit size of 1M rows with
    larger (eg. 5x the usual) height, and could overflow.
    
    This causes problems in 64-bit Linux builds and, since the
    following commit, in 64-bit Windows builds:
    3d90997fb6f232d8008df4d166d7b97b869c200f
    
    For now, clamp possibly overflowing values to 32-bit.
    
    Change-Id: Ifda7265703388abdfb47f523da4f0c5822358404
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129876
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>
    Reviewed-by: Aron Budea <aron.bu...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132168

diff --git a/sc/qa/unit/data/xlsx/tdf147014.xlsx 
b/sc/qa/unit/data/xlsx/tdf147014.xlsx
new file mode 100644
index 000000000000..df4428795d9d
Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf147014.xlsx differ
diff --git a/sc/qa/unit/subsequent_filters_test2.cxx 
b/sc/qa/unit/subsequent_filters_test2.cxx
index c40f26dfc78d..ac0b8d8d82e9 100644
--- a/sc/qa/unit/subsequent_filters_test2.cxx
+++ b/sc/qa/unit/subsequent_filters_test2.cxx
@@ -204,6 +204,7 @@ public:
     void testTdf129940();
     void testTdf139612();
     void testTdf144740();
+    void testTdf147014();
     void testTdf139763ShapeAnchor();
     void testAutofilterNamedRangesXLSX();
     void testInvalidBareBiff5();
@@ -312,6 +313,7 @@ public:
     CPPUNIT_TEST(testTdf129940);
     CPPUNIT_TEST(testTdf139612);
     CPPUNIT_TEST(testTdf144740);
+    CPPUNIT_TEST(testTdf147014);
     CPPUNIT_TEST(testTdf139763ShapeAnchor);
     CPPUNIT_TEST(testAutofilterNamedRangesXLSX);
     CPPUNIT_TEST(testInvalidBareBiff5);
@@ -2873,6 +2875,22 @@ void ScFiltersTest2::testTdf144740()
     xDocSh->DoClose();
 }
 
+void ScFiltersTest2::testTdf147014()
+{
+    ScDocShellRef xDocSh = loadDoc(u"tdf147014.", FORMAT_XLSX);
+    CPPUNIT_ASSERT_MESSAGE("Failed to load tdf147014.xlsx", xDocSh.is());
+    uno::Reference<frame::XModel> xModel = xDocSh->GetModel();
+    uno::Reference<sheet::XSpreadsheetDocument> xDoc(xModel, 
uno::UNO_QUERY_THROW);
+    uno::Reference<container::XIndexAccess> xIA(xDoc->getSheets(), 
uno::UNO_QUERY_THROW);
+    uno::Reference<drawing::XDrawPageSupplier> 
xDrawPageSupplier(xIA->getByIndex(0),
+                                                                 
uno::UNO_QUERY_THROW);
+    xIA.set(xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW);
+    // The sheet has a single shape, without the fix it was not imported, 
except in 32-bit builds
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Shape not imported", 
static_cast<sal_Int32>(1), xIA->getCount());
+
+    xDocSh->DoClose();
+}
+
 void ScFiltersTest2::testTdf139763ShapeAnchor()
 {
     ScDocShellRef xDocSh = loadDoc(u"tdf139763ShapeAnchor.", FORMAT_XLSX);
diff --git a/sc/source/filter/oox/worksheethelper.cxx 
b/sc/source/filter/oox/worksheethelper.cxx
index 40a99cdb444b..95625751d4a0 100644
--- a/sc/source/filter/oox/worksheethelper.cxx
+++ b/sc/source/filter/oox/worksheethelper.cxx
@@ -75,7 +75,7 @@
 #include <editeng/eeitem.hxx>
 #include <editeng/editobj.hxx>
 #include <editeng/flditem.hxx>
-#include <tools/UnitConversion.hxx>
+#include <tools/gen.hxx>
 
 namespace oox::xls {
 
@@ -96,6 +96,18 @@ void lclUpdateProgressBar( const ISegmentProgressBarRef& 
rxProgressBar, double f
         rxProgressBar->setPosition( fPosition );
 }
 
+// TODO Needed because input might be >32-bit (in 64-bit builds),
+//  or a negative, already overflown value (in 32-bit builds)
+sal_Int32 lclClampToNonNegativeInt32( tools::Long aVal )
+{
+    if ( aVal > SAL_MAX_INT32 || aVal < 0 )
+    {
+        SAL_WARN( "sc.filter", "Overflow detected, " << aVal << " does not fit 
into sal_Int32, or is negative." );
+        return SAL_MAX_INT32;
+    }
+    return static_cast<sal_Int32>( aVal );
+}
+
 } // namespace
 
 ColumnModel::ColumnModel() :
@@ -538,9 +550,9 @@ const awt::Size& WorksheetGlobals::getDrawPageSize() const
 
 awt::Point WorksheetGlobals::getCellPosition( sal_Int32 nCol, sal_Int32 nRow ) 
const
 {
-    awt::Point aPoint;
-    PropertySet aCellProp( getCell( ScAddress( nCol, nRow, getSheetIndex() ) ) 
);
-    aCellProp.getProperty( aPoint, PROP_Position );
+    const tools::Rectangle aMMRect( getScDocument().GetMMRect( nCol, nRow, 
nCol, nRow, getSheetIndex() ) );
+    awt::Point aPoint( lclClampToNonNegativeInt32( aMMRect.Left() ),
+                       lclClampToNonNegativeInt32( aMMRect.Top() ) );
     return aPoint;
 }
 
@@ -1360,8 +1372,9 @@ void WorksheetGlobals::groupColumnsOrRows( sal_Int32 
nFirstColRow, sal_Int32 nLa
 void WorksheetGlobals::finalizeDrawings()
 {
     // calculate the current drawing page size (after rows/columns are 
imported)
-    PropertySet aRangeProp( getCellRange( ScRange( 0, 0, getSheetIndex(), 
mrMaxApiPos.Col(), mrMaxApiPos.Row(), getSheetIndex() ) ) );
-    aRangeProp.getProperty( maDrawPageSize, PROP_Size );
+    const Size aPageSize( getScDocument().GetMMRect( 0, 0, mrMaxApiPos.Col(), 
mrMaxApiPos.Row(), getSheetIndex() ).GetSize() );
+    maDrawPageSize.Width = lclClampToNonNegativeInt32( aPageSize.Width() );
+    maDrawPageSize.Height = lclClampToNonNegativeInt32( aPageSize.Height() );
 
     // import DML and VML
     if( !maDrawingPath.isEmpty() )
commit a743d338c24407b4dec62f12dfff49621102eeac
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Wed Mar 9 16:41:36 2022 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Mar 28 13:07:01 2022 +0200

    svx: don't remove object right after insertion
    
    This is regression from:
    commit 2d95b3846eac367d2baadc194ab258dc31e7bd33
    Author: Tomaz Vajngerl <tomaz.vajng...@collabora.co.uk>
    Date:   Thu Oct 7 16:48:46 2021 +0200
    
        svx: Don't end text edit mode for all views
    
    It was visible with "direct insertion" where user doesn't
    need to draw anything but textbox is inserted in the center
    of a screen (eg. used in LOK case)
    
    Object was inserted into a view and right after that was removed when
    EndTextEditCurrentView was called
    
    Change-Id: I9943d46746aabadf96d76d6e74770b56d648b79d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131263
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Mert Tumer <mert.tu...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131537
    Tested-by: Jenkins
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131596
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/include/svx/svdedtv.hxx b/include/svx/svdedtv.hxx
index 6f80c3aca0fa..d2c9b3816f6a 100644
--- a/include/svx/svdedtv.hxx
+++ b/include/svx/svdedtv.hxx
@@ -188,7 +188,7 @@ public:
      * Checks if this or other views have an active text edit, if true, end 
them.
      */
     void EndTextEditAllViews() const;
-    void EndTextEditCurrentView();
+    void EndTextEditCurrentView(bool bDontDeleteReally = false);
 
     std::vector< std::unique_ptr<SdrUndoAction> > CreateConnectorUndo( const 
SdrObject& rO );
     void AddUndoActions( std::vector< std::unique_ptr<SdrUndoAction> > );
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx 
b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index c4e0da7b9f87..6c6cd5990c3c 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -121,6 +121,7 @@ public:
     void testEditCursorBounds();
     void testTextSelectionBounds();
     void testSheetViewDataCrash();
+    void testTextBoxInsert();
 
     CPPUNIT_TEST_SUITE(ScTiledRenderingTest);
     CPPUNIT_TEST(testRowColumnHeaders);
@@ -175,6 +176,7 @@ public:
     CPPUNIT_TEST(testEditCursorBounds);
     CPPUNIT_TEST(testTextSelectionBounds);
     CPPUNIT_TEST(testSheetViewDataCrash);
+    CPPUNIT_TEST(testTextBoxInsert);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -458,7 +460,12 @@ struct EditCursorMessage final {
         std::stringstream aStream(pMessage);
         boost::property_tree::ptree aTree;
         boost::property_tree::read_json(aStream, aTree);
-        std::string aVal = 
aTree.get_child("refpoint").get_value<std::string>();
+        std::string aVal;
+        boost::property_tree::ptree::const_assoc_iterator it = 
aTree.find("refpoint");
+        if (it != aTree.not_found())
+            aVal = aTree.get_child("refpoint").get_value<std::string>();
+        else
+            return; // happens in testTextBoxInsert test
 
         uno::Sequence<OUString> aSeq = 
comphelper::string::convertCommaSeparated(OUString::createFromAscii(aVal.c_str()));
         CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aSeq.getLength());
@@ -2868,6 +2875,28 @@ void ScTiledRenderingTest::testSheetViewDataCrash()
     Scheduler::ProcessEventsToIdle();
 }
 
+void ScTiledRenderingTest::testTextBoxInsert()
+{
+    comphelper::LibreOfficeKit::setActive();
+
+    createDoc("empty.ods");
+    ViewCallback aView1;
+
+    // insert textbox
+    uno::Sequence<beans::PropertyValue> aArgs(
+        comphelper::InitPropertySequence({
+            { "CreateDirectly",  uno::Any(true) }
+        }));
+    comphelper::dispatchCommand(".uno:DrawText", aArgs);
+    Scheduler::ProcessEventsToIdle();
+
+    // check if we have textbox selected
+    CPPUNIT_ASSERT(!aView1.m_ShapeSelection.isEmpty());
+    CPPUNIT_ASSERT(aView1.m_ShapeSelection != "EMPTY");
+
+    Scheduler::ProcessEventsToIdle();
+}
+
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(ScTiledRenderingTest);
diff --git a/svx/source/svdraw/svdedtv.cxx b/svx/source/svdraw/svdedtv.cxx
index 47f5c971e543..420f024f2064 100644
--- a/svx/source/svdraw/svdedtv.cxx
+++ b/svx/source/svdraw/svdedtv.cxx
@@ -1000,7 +1000,8 @@ bool SdrEditView::InsertObjectAtView(SdrObject* pObj, 
SdrPageView& rPV, SdrInser
     }
     if( IsUndoEnabled())
     {
-        EndTextEditCurrentView();
+        bool bDontDeleteReally = true;
+        EndTextEditCurrentView(bDontDeleteReally);
         AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pObj));
     }
 
@@ -1080,13 +1081,13 @@ void SdrEditView::EndTextEditAllViews() const
     }
 }
 
-void SdrEditView::EndTextEditCurrentView()
+void SdrEditView::EndTextEditCurrentView(bool bDontDeleteReally)
 {
     if (IsTextEdit())
     {
         SdrView* pSdrView = dynamic_cast<SdrView*>(this);
         if (pSdrView)
-            pSdrView->SdrEndTextEdit();
+            pSdrView->SdrEndTextEdit(bDontDeleteReally);
     }
 }
 
commit 10ee1f9d52f28db0aff61fb6f4e08b3fedfd9d19
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Wed Mar 9 21:32:35 2022 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Mar 28 13:06:47 2022 +0200

    lok: insert textbox directly in Calc
    
    Change-Id: I3ae00b255dfbaa34ab8d973356d12dfd0f71d345
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131267
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Mert Tumer <mert.tu...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131536
    Tested-by: Jenkins
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132101

diff --git a/sc/source/ui/view/tabvwsh2.cxx b/sc/source/ui/view/tabvwsh2.cxx
index a096a766ea7d..9060fa98e65c 100644
--- a/sc/source/ui/view/tabvwsh2.cxx
+++ b/sc/source/ui/view/tabvwsh2.cxx
@@ -265,6 +265,7 @@ void ScTabViewShell::ExecDraw(SfxRequest& rReq)
         case SID_DRAW_TEXT_MARQUEE:
         case SID_DRAW_NOTEEDIT:
             pTabView->SetDrawFuncPtr(new FuText(*this, pWin, pView, pDoc, 
aNewReq));
+            bCreateDirectly = comphelper::LibreOfficeKit::isActive();
             break;
 
         case SID_FM_CREATE_CONTROL:
@@ -335,7 +336,6 @@ void ScTabViewShell::ExecDraw(SfxRequest& rReq)
     }
     else
     {
-        GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, 
SfxCallMode::ASYNCHRON);
         ScViewData& rViewData = GetViewData();
         aInsertPos = rViewData.getLOKVisibleArea().Center();
         if (comphelper::LibreOfficeKit::isCompatFlagSet(
@@ -370,13 +370,20 @@ void ScTabViewShell::ExecDraw(SfxRequest& rReq)
     // insert into page
     pView->InsertObjectAtView(pObj.release(), *pPageView);
 
-    if ( nNewId == SID_DRAW_CAPTION || nNewId == SID_DRAW_CAPTION_VERTICAL )
+    switch ( nNewId )
     {
+    case SID_DRAW_CAPTION:
+    case SID_DRAW_CAPTION_VERTICAL:
+    case SID_DRAW_TEXT:
+    case SID_DRAW_TEXT_VERTICAL:
         //  use KeyInput to start edit mode (FuText is created).
         //  For FuText objects, edit mode is handled within 
CreateDefaultObject.
         //  KEY_F2 is handled in FuDraw::KeyInput.
 
         pFuActual->KeyInput( KeyEvent( 0, vcl::KeyCode( KEY_F2 ) ) );
+        break;
+    default:
+        break;
     }
 }
 
diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi
index 1e08145d3644..135efb8a845a 100644
--- a/svx/sdi/svx.sdi
+++ b/svx/sdi/svx.sdi
@@ -8520,7 +8520,7 @@ SfxBoolItem Text SID_ATTR_CHAR
 
 
 SfxBoolItem DrawText SID_DRAW_TEXT
-
+(SfxBoolItem CreateDirectly FN_PARAM_1)
 [
     AutoUpdate = TRUE,
     FastCall = FALSE,
commit db61167cdfdde69d115338be7d50447e81b43616
Author:     Szymon Kłos <szymon.k...@collabora.com>
AuthorDate: Mon Mar 14 21:55:59 2022 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Mar 28 12:00:06 2022 +0200

    tdf#147761 record sort command in macros
    
    fixes regression introduced in:
    
    commit  70b81e74d2a14308e1897d840c681404225d328a
    author  Szymon Kłos <szymon.k...@collabora.com> Tue Jul 21 11:40:22 2020 
+0200
    
    SfxRequest's Done method records the action. It has to be called.
    
    Change-Id: I32529fa11febca3d3829b4afd2cd4e6dd359bf74
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131484
    Tested-by: Jenkins
    Reviewed-by: Szymon Kłos <szymon.k...@collabora.com>
    (cherry picked from commit eca978841816f833616b4c2334e65aa976a9fb61)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131587
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/sc/source/ui/view/cellsh2.cxx b/sc/source/ui/view/cellsh2.cxx
index 0bed3b16141f..8ff829326597 100644
--- a/sc/source/ui/view/cellsh2.cxx
+++ b/sc/source/ui/view/cellsh2.cxx
@@ -526,6 +526,55 @@ void ScCellShell::ExecuteDB( SfxRequest& rReq )
                                     // subtotal when needed new
 
                                     pTabViewShell->UISort( rOutParam );
+
+                                    SfxViewFrame* pViewFrm = 
pTabViewShell->GetViewFrame();
+                                    if (pViewFrm)
+                                    {
+                                        SfxRequest aRequest(pViewFrm, 
SID_SORT);
+
+                                        if ( rOutParam.bInplace )
+                                        {
+                                            aRequest.AppendItem( SfxBoolItem( 
SID_SORT_BYROW,
+                                                rOutParam.bByRow ) );
+                                            aRequest.AppendItem( SfxBoolItem( 
SID_SORT_HASHEADER,
+                                                rOutParam.bHasHeader ) );
+                                            aRequest.AppendItem( SfxBoolItem( 
SID_SORT_CASESENS,
+                                                rOutParam.bCaseSens ) );
+                                            aRequest.AppendItem( SfxBoolItem( 
SID_SORT_NATURALSORT,
+                                                        rOutParam.bNaturalSort 
) );
+                                            aRequest.AppendItem( SfxBoolItem( 
SID_SORT_INCCOMMENTS,
+                                                        
rOutParam.aDataAreaExtras.mbCellNotes ) );
+                                            aRequest.AppendItem( SfxBoolItem( 
SID_SORT_INCIMAGES,
+                                                        
rOutParam.aDataAreaExtras.mbCellDrawObjects ) );
+                                            aRequest.AppendItem( SfxBoolItem( 
SID_SORT_ATTRIBS,
+                                                        
rOutParam.aDataAreaExtras.mbCellFormats ) );
+                                            sal_uInt16 nUser = 
rOutParam.bUserDef ? ( rOutParam.nUserIndex + 1 ) : 0;
+                                            aRequest.AppendItem( 
SfxUInt16Item( SID_SORT_USERDEF, nUser ) );
+                                            if ( 
rOutParam.maKeyState[0].bDoSort )
+                                            {
+                                                aRequest.AppendItem( 
SfxInt32Item( FN_PARAM_1,
+                                                    
rOutParam.maKeyState[0].nField + 1 ) );
+                                                aRequest.AppendItem( 
SfxBoolItem( FN_PARAM_2,
+                                                    
rOutParam.maKeyState[0].bAscending ) );
+                                            }
+                                            if ( 
rOutParam.maKeyState[1].bDoSort )
+                                            {
+                                                aRequest.AppendItem( 
SfxInt32Item( FN_PARAM_3,
+                                                    
rOutParam.maKeyState[1].nField + 1 ) );
+                                                aRequest.AppendItem( 
SfxBoolItem( FN_PARAM_4,
+                                                    
rOutParam.maKeyState[1].bAscending ) );
+                                            }
+                                            if ( 
rOutParam.maKeyState[2].bDoSort )
+                                            {
+                                                aRequest.AppendItem( 
SfxInt32Item( FN_PARAM_5,
+                                                    
rOutParam.maKeyState[2].nField + 1 ) );
+                                                aRequest.AppendItem( 
SfxBoolItem( FN_PARAM_6,
+                                                    
rOutParam.maKeyState[2].bAscending ) );
+                                            }
+                                        }
+
+                                        aRequest.Done();
+                                    }
                                 }
                                 else
                                 {
commit dc2e0b96be481b888d172f41cd2e94b7e1509685
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Thu Mar 24 09:33:44 2022 +0000
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Mar 28 11:58:18 2022 +0200

    forcepoint#85 Conditional jump or move depends on uninitialised value
    
    ==398461==    by 0xCDC7960: (anonymous namespace)::CopyUntil(char16_t*&, 
char16_t const*&, char16_t, bool) (strhelper.cxx:88)
    ==398461==    by 0xCDC839F: psp::WhitespaceToSpace(rtl::OUString const&, 
bool) (strhelper.cxx:294)
    ==398461==    by 0xCB54980: vcl::PDFWriterImpl::setOutlineItemText(int, 
rtl::OUString const&) (pdfwriter_impl.cxx:9875)
    ==398461==    by 0xCB547FF: vcl::PDFWriterImpl::createOutlineItem(int, 
rtl::OUString const&, int) (pdfwriter_impl.cxx:9851)
    ==398461==    by 0xCAF39B0: vcl::PDFWriter::CreateOutlineItem(int, 
rtl::OUString const&, int) (pdfwriter.cxx:383)
    ==398461==    by 0xCABD7C8: 
vcl::GlobalSyncData::PlayGlobalActions(vcl::PDFWriter&) 
(pdfextoutdevdata.cxx:250)
    ==398461==    by 0xCAC0628: 
vcl::PDFExtOutDevData::PlayGlobalActions(vcl::PDFWriter&) 
(pdfextoutdevdata.cxx:616)
    ==398461==    by 0x3D06EA0F: PDFExport::Export(rtl::OUString const&, 
com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) 
(pdfexport.cxx:1004)
    
    Change-Id: I6bc086997851ee06531a4a9ae263e2b26edfba84
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132035
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/vcl/source/helper/strhelper.cxx b/vcl/source/helper/strhelper.cxx
index 96e10b4865e8..782c9ce123e1 100644
--- a/vcl/source/helper/strhelper.cxx
+++ b/vcl/source/helper/strhelper.cxx
@@ -83,7 +83,8 @@ void CopyUntil( sal_Unicode*& pTo, const sal_Unicode*& pFrom, 
sal_Unicode cUntil
             *pTo = *pFrom;
             pTo++;
         }
-        pFrom++;
+        if( *pFrom )
+            pFrom++;
     } while( *pFrom && *pFrom != cUntil );
     // copy the terminating character unless zero or protector
     if( ! isProtect( *pFrom ) || bIncludeUntil )
commit 6bd85136efe3d3668b59a596d692f65bf0a4982c
Author:     Regina Henschel <rb.hensc...@t-online.de>
AuthorDate: Fri Mar 18 18:31:05 2022 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Mar 28 11:38:26 2022 +0200

    tdf#147978 export subpaths individually in custGeom
    
    ...and implement export of all missing commands,
       use existing viewBox if suitable,
       use one EnhancedCustomShape2d
       move WriteCustomGeometryPoint to protected,
       make GetCustomGeometryPointValue local
    
    The fix solves tdf#100390 too.
    
    Without the fix the entire enhanced-path was exported as one element
    <a:path>. The command F was applied to the whole drawing but should
    affect only the subpath. The implementation is changed so that each
    subpath gets its own element <a:path> and command F acts only on its
    subpath.
    
    Support for export of handles and equations is still a long way off.
    Thus there is no reason to tread shapes with and without handles
    different. Shapes with handles had used method WritePolyPolygon, but
    that is not able to handle subpaths. So have desided to use method
    WriteCustomGeometry for all cases.
    
    To get shapes exported regardless of path commands I have added the
    export for the missing commands.
    
    I have removed the no longer used method WritePolyPolygon.
    
    The special treatment of shapes "moon" and "mso-spt89" (right up arrow)
    in export is no longer needed. Related code parts are removed. The
    unit test testFlipAndRotateCustomShape is adapted.
    
    In case the method WriteCustomGeometry fails, the enhanced-path is
    invalid. In that case an minimal custGeom is written in case of docx.
    
    Shapes whose drawing does not touch all edges of the snap rectangle
    were exported with wrong position and size of the drawing inside the
    snap rectangle. That is fixed by using an existing ViewBox for the
    OOXML path size. The old way of creating a path size from point
    coordinates is only used if the shape has no suitable ViewBox.
    
    The point values in unit test SdOOXMLExportTest2::testTdf111798 are
    adapted to path size 21600 x 21600 and traverse direction of the points
    is corrected. The resulting shape outline is still the same as before.
    
    The expected xml is updated for file tdf92001.odp in
    SdImportTest::testDocumentLayout. The resulting shape outline is the
    same, because the shape touches the edges of the snap rectangle.
    
    The case, that the shape outline does not touch a edge of the snap
    rectangle is tested in SdOOXMLExportTest3::testEnhancedPathViewBox.
    
    Still missing is the case, that ViewBox has other left,top than 0,0.
    In that case all coordinates would have to be shifted because the path
    size in OOXML has only width and height but not left,top. That will
    not be included in this patch.
    
    Change-Id: Ib1736d6a08371f4d98411d2769275f0580cd0030
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131837
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit 2029b2f6dd0109c5892e5ac5640022b31fe42fd2)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132048
    Reviewed-by: Bartosz Kosiorek <gan...@poczta.onet.pl>

diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 63a32225172b..7fbb015b4ce4 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -43,6 +43,7 @@
 #include <vcl/checksum.hxx>
 #include <tools/gen.hxx>
 #include <vcl/mapmod.hxx>
+#include <svx/EnhancedCustomShape2d.hxx>
 
 class Graphic;
 class SdrObjCustomShape;
@@ -198,7 +199,8 @@ protected:
 
     void WriteGlowEffect(const css::uno::Reference<css::beans::XPropertySet>& 
rXPropSet);
     void WriteSoftEdgeEffect(const 
css::uno::Reference<css::beans::XPropertySet>& rXPropSet);
-    bool HasEnhancedCustomShapeSegmentCommand(const 
css::uno::Reference<css::drawing::XShape>& rXShape, const sal_Int16 nCommand);
+    void WriteCustomGeometryPoint(const 
css::drawing::EnhancedCustomShapeParameterPair& rParamPair,
+                                  const EnhancedCustomShape2d& rCustomShape2d);
 
 public:
     DrawingML( ::sax_fastparser::FSHelperPtr pFS, ::oox::core::XmlFilterBase* 
pFB, DocumentType eDocumentType = DOCUMENT_PPTX, DMLTextExport* pTextExport = 
nullptr )
@@ -306,14 +308,7 @@ public:
     bool WriteCustomGeometry(
         const css::uno::Reference<css::drawing::XShape>& rXShape,
         const SdrObjCustomShape& rSdrObjCustomShape);
-    void WriteCustomGeometryPoint(
-        const css::drawing::EnhancedCustomShapeParameterPair& rParamPair,
-        const SdrObjCustomShape& rSdrObjCustomShape);
-    static sal_Int32 GetCustomGeometryPointValue(
-        const css::drawing::EnhancedCustomShapeParameter& rParam,
-        const SdrObjCustomShape& rSdrObjCustomShape);
-    void WritePolyPolygon(const css::uno::Reference<css::drawing::XShape>& 
rXShape,
-                          const tools::PolyPolygon& rPolyPolygon, const bool 
bClosed);
+    void WriteEmptyCustomGeometry();
     void WritePolyPolygon(const css::uno::Reference<css::drawing::XShape>& 
rXShape,
                           const bool bClosed);
     void WriteFill( const css::uno::Reference< css::beans::XPropertySet >& 
xPropSet );
diff --git a/oox/qa/unit/data/tdf147978_endsubpath.odp 
b/oox/qa/unit/data/tdf147978_endsubpath.odp
new file mode 100644
index 000000000000..2dfd55de1be3
Binary files /dev/null and b/oox/qa/unit/data/tdf147978_endsubpath.odp differ
diff --git a/oox/qa/unit/data/tdf147978_enhancedPath_commandA.odp 
b/oox/qa/unit/data/tdf147978_enhancedPath_commandA.odp
new file mode 100644
index 000000000000..99ddda7c132e
Binary files /dev/null and 
b/oox/qa/unit/data/tdf147978_enhancedPath_commandA.odp differ
diff --git a/oox/qa/unit/data/tdf147978_enhancedPath_commandHIJK.odp 
b/oox/qa/unit/data/tdf147978_enhancedPath_commandHIJK.odp
new file mode 100644
index 000000000000..49e01bc0933a
Binary files /dev/null and 
b/oox/qa/unit/data/tdf147978_enhancedPath_commandHIJK.odp differ
diff --git a/oox/qa/unit/data/tdf147978_enhancedPath_commandT.odp 
b/oox/qa/unit/data/tdf147978_enhancedPath_commandT.odp
new file mode 100644
index 000000000000..3dcd0d567545
Binary files /dev/null and 
b/oox/qa/unit/data/tdf147978_enhancedPath_commandT.odp differ
diff --git a/oox/qa/unit/data/tdf147978_enhancedPath_commandXY.odp 
b/oox/qa/unit/data/tdf147978_enhancedPath_commandXY.odp
new file mode 100644
index 000000000000..6112251783e1
Binary files /dev/null and 
b/oox/qa/unit/data/tdf147978_enhancedPath_commandXY.odp differ
diff --git a/oox/qa/unit/data/tdf147978_enhancedPath_subpath.pptx 
b/oox/qa/unit/data/tdf147978_enhancedPath_subpath.pptx
new file mode 100644
index 000000000000..bbedc7ab98f5
Binary files /dev/null and 
b/oox/qa/unit/data/tdf147978_enhancedPath_subpath.pptx differ
diff --git a/oox/qa/unit/export.cxx b/oox/qa/unit/export.cxx
index dd722cd04e79..e104b4effdd7 100644
--- a/oox/qa/unit/export.cxx
+++ b/oox/qa/unit/export.cxx
@@ -374,6 +374,161 @@ CPPUNIT_TEST_FIXTURE(Test, 
testTdf146690_endParagraphRunPropertiesNewLinesTextSi
     assertXPath(pXmlDoc, "//p:sp[1]/p:txBody/a:p[2]/a:endParaRPr", "sz", 
"500");
     assertXPath(pXmlDoc, "//p:sp[1]/p:txBody/a:p[3]/a:endParaRPr", "sz", 
"500");
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf147978_endsubpath)
+{
+    // Given an odp file that contains a non-primitive custom shape with 
command N
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf147978_endsubpath.odp";
+
+    // When saving that document:
+    loadAndSave(aURL, "Impress Office Open XML");
+
+    std::unique_ptr<SvStream> pStream = parseExportStream(getTempFile(), 
"ppt/slides/slide1.xml");
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    // Then make sure the pathLst has two child elements,
+    // Without the accompanying fix in place, only one element a:path was 
exported.
+    assertXPathChildren(pXmlDoc, "//a:pathLst", 2);
+    // and make sure first path with no stroke, second with no fill
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]", "stroke", "0");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]", "fill", "none");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf147978_commandA)
+{
+    // Given an odp file that contains a non-primitive custom shape with 
command N
+    OUString aURL
+        = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf147978_enhancedPath_commandA.odp";
+
+    // When saving that document:
+    loadAndSave(aURL, "Impress Office Open XML");
+
+    std::unique_ptr<SvStream> pStream = parseExportStream(getTempFile(), 
"ppt/slides/slide1.xml");
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    // Then make sure the path has a child element arcTo. Prior to the fix 
that part of the curve was
+    // not exported at all. In odp it is a command A. Such does not exist in 
OOXML and is therefore
+    // exported as a:lnTo followed by a:arcTo
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:lnTo", 2);
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", 1);
+    // And assert its attribute values
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", "wR", "7200");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", "hR", "5400");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", "stAng", "7719588");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", "swAng", "-5799266");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf147978_commandT)
+{
+    // The odp file contains a non-primitive custom shape with commands MTZ
+    OUString aURL
+        = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf147978_enhancedPath_commandT.odp";
+
+    // Export to pptx had only exported the command M and has used a wrong 
path size
+    loadAndSave(aURL, "Impress Office Open XML");
+
+    // Verify the markup:
+    std::unique_ptr<SvStream> pStream = parseExportStream(getTempFile(), 
"ppt/slides/slide1.xml");
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    // File has draw:viewBox="0 0 216 216"
+    assertXPath(pXmlDoc, "//a:pathLst/a:path", "w", "216");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path", "h", "216");
+    // Command T is exported as lnTo followed by arcTo.
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:moveTo", 1);
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:lnTo", 1);
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", 1);
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:close", 1);
+    // And assert its values
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:moveTo/a:pt", "x", "108");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:moveTo/a:pt", "y", "162");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:lnTo/a:pt", "x", "138");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:lnTo/a:pt", "y", "110");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", "wR", "108");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", "hR", "54");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", "stAng", "18000000");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path/a:arcTo", "swAng", "18000000");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf147978_commandXY)
+{
+    // The odp file contains a non-primitive custom shapes with commands XY
+    OUString aURL
+        = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf147978_enhancedPath_commandXY.odp";
+
+    // Export to pptx had dropped commands X and Y.
+    loadAndSave(aURL, "Impress Office Open XML");
+
+    // Verify the markup:
+    std::unique_ptr<SvStream> pStream = parseExportStream(getTempFile(), 
"ppt/slides/slide1.xml");
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    // File has draw:viewBox="0 0 10 10"
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]", "w", "10");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]", "h", "10");
+    // Shape has M 0 5 Y 5 0 10 5 5 10 F Y 0 5 N M 10 10 X 0 0
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:moveTo/a:pt", "x", "0");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:moveTo/a:pt", "y", "5");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[1]", "wR", "5");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[1]", "hR", "5");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[1]", "stAng", 
"10800000");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[1]", "swAng", 
"5400000");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[2]", "stAng", 
"16200000");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[2]", "swAng", 
"5400000");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[3]", "stAng", "0");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[3]", "swAng", 
"5400000");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[4]", "stAng", "0");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]/a:arcTo[4]", "swAng", 
"-5400000");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]/a:moveTo/a:pt", "x", "10");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]/a:moveTo/a:pt", "y", "10");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]/a:arcTo", "wR", "10");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]/a:arcTo", "hR", "10");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]/a:arcTo", "stAng", "5400000");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]/a:arcTo", "swAng", "5400000");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf147978_commandHIJK)
+{
+    // The odp file contains a non-primitive custom shapes with commands 
H,I,J,K
+    OUString aURL
+        = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf147978_enhancedPath_commandHIJK.odp";
+
+    // Export to pptx had dropped commands X and Y.
+    loadAndSave(aURL, "Impress Office Open XML");
+
+    // Verify the markup:
+    std::unique_ptr<SvStream> pStream = parseExportStream(getTempFile(), 
"ppt/slides/slide1.xml");
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    // File has draw:viewBox="0 0 80 80"
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]", "w", "80");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]", "h", "80");
+    // File uses from back to front J (lighten), I (lightenLess), normal fill, 
K (darkenLess),
+    // H (darken). New feature, old versions did not export these at all.
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]", "fill", "lighten");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]", "fill", "lightenLess");
+    assertXPathNoAttribute(pXmlDoc, "//a:pathLst/a:path[3]", "fill");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[4]", "fill", "darkenLess");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[5]", "fill", "darken");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf147978_subpath)
+{
+    // The odp file contains a non-primitive custom shapes with commands 
H,I,J,K
+    OUString aURL
+        = m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"tdf147978_enhancedPath_subpath.pptx";
+
+    // Export to pptx had dropped the subpaths.
+    loadAndSave(aURL, "Impress Office Open XML");
+
+    // Verify the markup:
+    std::unique_ptr<SvStream> pStream = parseExportStream(getTempFile(), 
"ppt/slides/slide1.xml");
+    xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+    // File should have four subpaths with increasing path size
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]", "w", "10");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[1]", "h", "10");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]", "w", "20");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[2]", "h", "20");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[3]", "w", "40");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[3]", "h", "40");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[4]", "w", "80");
+    assertXPath(pXmlDoc, "//a:pathLst/a:path[4]", "h", "80");
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index c457e65ac0c8..708aea6fb29a 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -62,6 +62,7 @@
 #include <com/sun/star/drawing/ColorMode.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
 #include <com/sun/star/drawing/Hatch.hpp>
@@ -137,6 +138,7 @@ using namespace ::css::style;
 using namespace ::css::text;
 using namespace ::css::uno;
 using namespace ::css::container;
+using namespace ::com::sun::star::drawing::EnhancedCustomShapeSegmentCommand;
 
 using ::css::io::XOutputStream;
 using ::sax_fastparser::FSHelperPtr;
@@ -3658,6 +3660,86 @@ void DrawingML::WritePresetShape( const char* pShape, 
MSO_SPT eShapeType, bool b
     mpFS->endElementNS(  XML_a, XML_prstGeom );
 }
 
+namespace // helpers for DrawingML::WriteCustomGeometry
+{
+sal_Int32
+FindNextCommandEndSubpath(const sal_Int32 nStart,
+                          const 
uno::Sequence<drawing::EnhancedCustomShapeSegment>& rSegments)
+{
+    sal_Int32 i = nStart < 0 ? 0 : nStart;
+    while (i < rSegments.getLength() && rSegments[i].Command != ENDSUBPATH)
+        i++;
+    return i;
+}
+
+bool HasCommandInSubPath(const sal_Int16 nCommand, const sal_Int32 nFirst, 
const sal_Int32 nLast,
+                         const 
uno::Sequence<drawing::EnhancedCustomShapeSegment>& rSegments)
+{
+    for (sal_Int32 i = nFirst < 0 ? 0 : nFirst; i <= nLast && i < 
rSegments.getLength(); i++)
+    {
+        if (rSegments[i].Command == nCommand)
+            return true;
+    }
+    return false;
+}
+
+// Ellipse is given by radii fwR and fhR and center (fCx|fCy). The ray from 
center through point RayP
+// intersects the ellipse in point S and this point S has angle fAngleDeg in 
degrees.
+void getEllipsePointAndAngleFromRayPoint(double& rfAngleDeg, double& rfSx, 
double& rfSy,
+                                         const double fWR, const double fHR, 
const double fCx,
+                                         const double fCy, const double 
fRayPx, const double fRayPy)
+{
+    if (basegfx::fTools::equalZero(fWR) || basegfx::fTools::equalZero(fHR))
+    {
+        rfSx = fCx; // needed for getting new 'current point'
+        rfSy = fCy;
+    }
+    else
+    {
+        // center ellipse at origin, stretch in y-direction to circle, flip to 
Math orientation
+        // and get angle
+        double fCircleMathAngle = atan2(-fWR / fHR * (fRayPy - fCy), fRayPx - 
fCx);
+        // use angle for intersection point on circle and stretch back to 
ellipse
+        double fPointMathEllipse_x = fWR * cos(fCircleMathAngle);
+        double fPointMathEllipse_y = fHR * sin(fCircleMathAngle);
+        // get angle of intersection point on ellipse
+        double fEllipseMathAngle = atan2(fPointMathEllipse_y, 
fPointMathEllipse_x);
+        // convert from Math to View orientation and shift ellipse back from 
origin
+        rfAngleDeg = -basegfx::rad2deg(fEllipseMathAngle);
+        rfSx = fPointMathEllipse_x + fCx;
+        rfSy = -fPointMathEllipse_y + fCy;
+    }
+}
+
+void getEllipsePointFromViewAngle(double& rfSx, double& rfSy, const double 
fWR, const double fHR,
+                                  const double fCx, const double fCy, const 
double fViewAngleDeg)
+{
+    if (basegfx::fTools::equalZero(fWR) || basegfx::fTools::equalZero(fHR))
+    {
+        rfSx = fCx; // needed for getting new 'current point'
+        rfSy = fCy;
+    }
+    else
+    {
+        double fX = cos(basegfx::deg2rad(fViewAngleDeg)) / fWR;
+        double fY = sin(basegfx::deg2rad(fViewAngleDeg)) / fHR;
+        double fRadius = 1.0 / std::hypot(fX, fY);
+        rfSx = fCx + fRadius * cos(basegfx::deg2rad(fViewAngleDeg));
+        rfSy = fCy + fRadius * sin(basegfx::deg2rad(fViewAngleDeg));
+    }
+}
+
+sal_Int32 GetCustomGeometryPointValue(const 
css::drawing::EnhancedCustomShapeParameter& rParam,
+                                      const EnhancedCustomShape2d& 
rCustomShape2d)
+{
+    double fValue = 0.0;
+    rCustomShape2d.GetParameter(fValue, rParam, false, false);
+    sal_Int32 nValue(std::lround(fValue));
+
+    return nValue;
+}
+}
+
 bool DrawingML::WriteCustomGeometry(
     const Reference< XShape >& rXShape,
     const SdrObjCustomShape& rSdrObjCustomShape)
@@ -3679,349 +3761,574 @@ bool DrawingML::WriteCustomGeometry(
         return false;
     }
 
-
     auto pGeometrySeq = 
o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(aAny);
+    if (!pGeometrySeq)
+        return false;
+
+    auto pPathProp = std::find_if(std::cbegin(*pGeometrySeq), 
std::cend(*pGeometrySeq),
+                                  [](const PropertyValue& rProp) { return 
rProp.Name == "Path"; });
+    if (pPathProp == std::cend(*pGeometrySeq))
+        return false;
 
-    if ( pGeometrySeq )
+    uno::Sequence<beans::PropertyValue> aPathProp;
+    pPathProp->Value >>= aPathProp;
+
+    uno::Sequence<drawing::EnhancedCustomShapeParameterPair> aPairs;
+    uno::Sequence<drawing::EnhancedCustomShapeSegment> aSegments;
+    uno::Sequence<awt::Size> aPathSize;
+    for (const beans::PropertyValue& rPathProp : std::as_const(aPathProp))
     {
-        for( const beans::PropertyValue& rProp : *pGeometrySeq )
-        {
-            if ( rProp.Name == "Path" )
-            {
-                uno::Sequence<beans::PropertyValue> aPathProp;
-                rProp.Value >>= aPathProp;
+        if (rPathProp.Name == "Coordinates")
+            rPathProp.Value >>= aPairs;
+        else if (rPathProp.Name == "Segments")
+            rPathProp.Value >>= aSegments;
+        else if (rPathProp.Name == "SubViewSize")
+            rPathProp.Value >>= aPathSize;
+    }
 
-                uno::Sequence<drawing::EnhancedCustomShapeParameterPair> 
aPairs;
-                uno::Sequence<drawing::EnhancedCustomShapeSegment> aSegments;
-                uno::Sequence<awt::Size> aPathSize;
-                for (const beans::PropertyValue& rPathProp : 
std::as_const(aPathProp))
-                {
-                    if (rPathProp.Name == "Coordinates")
-                        rPathProp.Value >>= aPairs;
-                    else if (rPathProp.Name == "Segments")
-                        rPathProp.Value >>= aSegments;
-                    else if (rPathProp.Name == "SubViewSize")
-                        rPathProp.Value >>= aPathSize;
-                }
+    if ( !aPairs.hasElements() )
+        return false;
 
-                if ( !aPairs.hasElements() )
-                    return false;
+    if ( !aSegments.hasElements() )
+    {
+        aSegments = uno::Sequence<drawing::EnhancedCustomShapeSegment>
+            {
+                { MOVETO, 1 },
+                { LINETO,
+                  static_cast<sal_Int16>(std::min( aPairs.getLength() - 1, 
sal_Int32(32767) )) },
+                { CLOSESUBPATH, 0 },
+                { ENDSUBPATH, 0 }
+            };
+    };
 
-                if ( !aSegments.hasElements() )
-                {
-                    aSegments = 
uno::Sequence<drawing::EnhancedCustomShapeSegment>
-                    {
-                        { drawing::EnhancedCustomShapeSegmentCommand::MOVETO, 
1 },
-                        { drawing::EnhancedCustomShapeSegmentCommand::LINETO,
-                          static_cast<sal_Int16>(std::min( aPairs.getLength() 
- 1, sal_Int32(32767) )) },
-                        { 
drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH, 0 },
-                        { 
drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH, 0 }
-                    };
-                };
+    int nExpectedPairCount = std::accumulate(std::cbegin(aSegments), 
std::cend(aSegments), 0,
+        [](const int nSum, const drawing::EnhancedCustomShapeSegment& 
rSegment) { return nSum + rSegment.Count; });
 
-                int nExpectedPairCount = 
std::accumulate(std::cbegin(aSegments), std::cend(aSegments), 0,
-                    [](const int nSum, const 
drawing::EnhancedCustomShapeSegment& rSegment) { return nSum + rSegment.Count; 
});
+    if ( nExpectedPairCount > aPairs.getLength() )
+    {
+        SAL_WARN("oox.shape", "Segments need " << nExpectedPairCount << " 
coordinates, but Coordinates have only " << aPairs.getLength() << " pairs.");
+        return false;
+    }
 
-                if ( nExpectedPairCount > aPairs.getLength() )
-                {
-                    SAL_WARN("oox.shape", "Segments need " << 
nExpectedPairCount << " coordinates, but Coordinates have only " << 
aPairs.getLength() << " pairs.");
-                    return false;
-                }
+    // A EnhancedCustomShape2d caches the equation results. Therefor we use 
only one of it for the
+    // entire method.
+    const EnhancedCustomShape2d 
aCustomShape2d(const_cast<SdrObjCustomShape&>(rSdrObjCustomShape));
 
-                mpFS->startElementNS(XML_a, XML_custGeom);
-                mpFS->singleElementNS(XML_a, XML_avLst);
-                mpFS->singleElementNS(XML_a, XML_gdLst);
-                mpFS->singleElementNS(XML_a, XML_ahLst);
-                mpFS->singleElementNS(XML_a, XML_rect, XML_l, "l", XML_t, "t",
-                                      XML_r, "r", XML_b, "b");
-                mpFS->startElementNS(XML_a, XML_pathLst);
+    mpFS->startElementNS(XML_a, XML_custGeom);
+    mpFS->singleElementNS(XML_a, XML_avLst);
+    mpFS->singleElementNS(XML_a, XML_gdLst);
+    mpFS->singleElementNS(XML_a, XML_ahLst);
+    // ToDO: use draw:TextAreas for <a:rect>
+    mpFS->singleElementNS(XML_a, XML_rect, XML_l, "l", XML_t, "t", XML_r, "r", 
XML_b, "b");
+    mpFS->startElementNS(XML_a, XML_pathLst);
 
-                std::optional<OString> sFill;
-                if (HasEnhancedCustomShapeSegmentCommand(rXShape, 
css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL))
-                    sFill = "none"; // for possible values see ST_PathFillMode 
in OOXML standard
+    // Prepare width and height for <a:path>
+    bool bUseGlobalViewBox(false);
+
+    // nViewBoxWidth must be integer otherwise ReplaceGeoWidth in 
aCustomShape2d.GetParameter() is not
+    // triggered; same for height.
+    sal_Int32 nViewBoxWidth(0);
+    sal_Int32 nViewBoxHeight(0);
+    if (!aPathSize.hasElements())
+    {
+        bUseGlobalViewBox = true;
+        // If draw:viewBox is missing in draw:enhancedGeometry, then import 
sets
+        // viewBox="0 0 21600 21600". Missing ViewBox can only occur, if user 
has manipulated
+        // current file via macro. Author of macro has to fix it.
+        auto pProp = std::find_if(
+            std::cbegin(*pGeometrySeq), std::cend(*pGeometrySeq),
+            [](const beans::PropertyValue& rGeomProp) { return rGeomProp.Name 
== "ViewBox"; });
+        if (pProp != std::cend(*pGeometrySeq))
+        {
+            css::awt::Rectangle aViewBox;
+            if (pProp->Value >>= aViewBox)
+            {
+                nViewBoxWidth = aViewBox.Width;
+                nViewBoxHeight = aViewBox.Height;
+                css::drawing::EnhancedCustomShapeParameter aECSP;
+                aECSP.Type = 
css::drawing::EnhancedCustomShapeParameterType::NORMAL;
+                aECSP.Value <<= nViewBoxWidth;
+                double fRetValue;
+                aCustomShape2d.GetParameter(fRetValue, aECSP, true, false);
+                nViewBoxWidth = basegfx::fround(fRetValue);
+                aECSP.Value <<= nViewBoxHeight;
+                aCustomShape2d.GetParameter(fRetValue, aECSP, false, true);
+                nViewBoxHeight = basegfx::fround(fRetValue);
+            }
+        }
+        // Import from oox or documents, which are imported from oox and saved 
to strict ODF, might
+        // have no subViewSize but viewBox="0 0 0 0". We need to generate 
width and height in those
+        // cases. Even if that is fixed, we need the substitute for old 
documents.
+        if ((nViewBoxWidth == 0 && nViewBoxHeight == 0) || pProp == 
std::cend(*pGeometrySeq))
+        {
+            // Generate a substitute based on point coordinates
+            sal_Int32 nXMin(0);
+            aPairs[0].First.Value >>= nXMin;
+            sal_Int32 nXMax = nXMin;
+            sal_Int32 nYMin(0);
+            aPairs[0].Second.Value >>= nYMin;
+            sal_Int32 nYMax = nYMin;
 
-                if ( aPathSize.hasElements() )
-                {
-                    mpFS->startElementNS( XML_a, XML_path,
-                          XML_fill, sFill,
-                          XML_w, OString::number(aPathSize[0].Width),
-                          XML_h, OString::number(aPathSize[0].Height) );
-                }
-                else
+            for (const auto& rPair : std::as_const(aPairs))
+            {
+                sal_Int32 nX = GetCustomGeometryPointValue(rPair.First, 
aCustomShape2d);
+                sal_Int32 nY = GetCustomGeometryPointValue(rPair.Second, 
aCustomShape2d);
+                if (nX < nXMin)
+                    nXMin = nX;
+                if (nY < nYMin)
+                    nYMin = nY;
+                if (nX > nXMax)
+                    nXMax = nX;
+                if (nY > nYMax)
+                    nYMax = nY;
+            }
+            nViewBoxWidth = std::max(nXMax, nXMax - nXMin);
+            nViewBoxHeight = std::max(nYMax, nYMax - nYMin);
+        }
+        // ToDo: Other values of left,top than 0,0 are not considered yet. 
Such would require a
+        // shift of the resulting path coordinates.
+    }
+
+    // Iterate over subpaths
+    sal_Int32 nPairIndex = 0; // index over "Coordinates"
+    sal_Int32 nPathSizeIndex = 0; // index over "SubViewSize"
+    sal_Int32 nSubpathStartIndex(0); // index over "Segments"
+    do
+    {
+        bool bOK(true); // catch faulty paths were commands do not correspond 
to points
+        // get index of next command ENDSUBPATH; if such doesn't exist use 
index behind last segment
+        sal_Int32 nNextNcommandIndex = 
FindNextCommandEndSubpath(nSubpathStartIndex, aSegments);
+
+        // Prepare attributes for a:path start element
+        // NOFILL or one of the LIGHTEN commands
+        std::optional<OString> sFill;
+        if (HasCommandInSubPath(NOFILL, nSubpathStartIndex, nNextNcommandIndex 
- 1, aSegments))
+            sFill = "none";
+        else if (HasCommandInSubPath(DARKEN, nSubpathStartIndex, 
nNextNcommandIndex - 1, aSegments))
+            sFill = "darken";
+        else if (HasCommandInSubPath(DARKENLESS, nSubpathStartIndex, 
nNextNcommandIndex - 1,
+                                     aSegments))
+            sFill = "darkenLess";
+        else if (HasCommandInSubPath(LIGHTEN, nSubpathStartIndex, 
nNextNcommandIndex - 1,
+                                     aSegments))
+            sFill = "lighten";
+        else if (HasCommandInSubPath(LIGHTENLESS, nSubpathStartIndex, 
nNextNcommandIndex - 1,
+                                     aSegments))
+            sFill = "lightenLess";
+        // NOSTROKE
+        std::optional<OString> sStroke;
+        if (HasCommandInSubPath(NOSTROKE, nSubpathStartIndex, 
nNextNcommandIndex - 1, aSegments))
+            sStroke = "0";
+
+        // Write a:path start element
+        mpFS->startElementNS(
+            XML_a, XML_path, XML_fill, sFill, XML_stroke, sStroke, XML_w,
+            OString::number(bUseGlobalViewBox ? nViewBoxWidth : 
aPathSize[nPathSizeIndex].Width),
+            XML_h,
+            OString::number(bUseGlobalViewBox ? nViewBoxHeight : 
aPathSize[nPathSizeIndex].Height));
+
+        // Arcs drawn by commands ELLIPTICALQUADRANTX and ELLIPTICALQUADRANTY 
depend on the position
+        // of the target point in regard to the current point. Therefore we 
need to track the
+        // current point. A current point is not defined in the beginning.
+        double fCurrentX(0.0);
+        double fCurrentY(0.0);
+        bool bCurrentValid(false);
+        // Actually write the subpath
+        for (sal_Int32 nSegmentIndex = nSubpathStartIndex; nSegmentIndex < 
nNextNcommandIndex;
+             ++nSegmentIndex)
+        {
+            const auto& rSegment(aSegments[nSegmentIndex]);
+            if (rSegment.Command == CLOSESUBPATH)
+            {
+                mpFS->singleElementNS(XML_a, XML_close); // command Z has no 
parameter
+                // ODF 1.4 specifies, that the start of the subpath becomes 
the current point.
+                // But that is not implemented yet. Currently LO keeps the 
last current point.
+            }
+            for (sal_Int32 k = 0; k < rSegment.Count && bOK; ++k)
+            {
+                switch (rSegment.Command)
                 {
-                    sal_Int32 nXMin(0);
-                    aPairs[0].First.Value >>= nXMin;
-                    sal_Int32 nXMax = nXMin;
-                    sal_Int32 nYMin(0);
-                    aPairs[0].Second.Value >>= nYMin;
-                    sal_Int32 nYMax = nYMin;
-
-                    for ( const auto& rPair : std::as_const(aPairs) )
+                    case MOVETO:
                     {
-                        sal_Int32 nX = 
GetCustomGeometryPointValue(rPair.First, rSdrObjCustomShape);
-                        sal_Int32 nY = 
GetCustomGeometryPointValue(rPair.Second, rSdrObjCustomShape);
-                        if (nX < nXMin)
-                            nXMin = nX;
-                        if (nY < nYMin)
-                            nYMin = nY;
-                        if (nX > nXMax)
-                            nXMax = nX;
-                        if (nY > nYMax)
-                            nYMax = nY;
+                        if (nPairIndex >= aPairs.getLength())
+                            bOK = false;
+                        else
+                        {
+                            mpFS->startElementNS(XML_a, XML_moveTo);
+                            WriteCustomGeometryPoint(aPairs[nPairIndex], 
aCustomShape2d);
+                            mpFS->endElementNS(XML_a, XML_moveTo);
+                            aCustomShape2d.GetParameter(fCurrentX, 
aPairs[nPairIndex].First, false,
+                                                        false);
+                            aCustomShape2d.GetParameter(fCurrentY, 
aPairs[nPairIndex].Second, false,
+                                                        false);
+                            bCurrentValid = true;
+                            nPairIndex++;
+                        }
+                        break;
                     }
-                    mpFS->startElementNS( XML_a, XML_path,
-                          XML_fill, sFill,
-                          XML_w, OString::number(nXMax - nXMin),
-                          XML_h, OString::number(nYMax - nYMin) );
-                }
-
-
-                int nPairIndex = 0;
-                bool bOK = true;
-                for (const auto& rSegment : std::as_const(aSegments))
-                {
-                    if ( rSegment.Command == 
drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH )
+                    case LINETO:
                     {
-                        mpFS->singleElementNS(XML_a, XML_close);
+                        if (nPairIndex >= aPairs.getLength())
+                            bOK = false;
+                        else
+                        {
+                            mpFS->startElementNS(XML_a, XML_lnTo);
+                            WriteCustomGeometryPoint(aPairs[nPairIndex], 
aCustomShape2d);
+                            mpFS->endElementNS(XML_a, XML_lnTo);
+                            aCustomShape2d.GetParameter(fCurrentX, 
aPairs[nPairIndex].First, false,
+                                                        false);
+                            aCustomShape2d.GetParameter(fCurrentY, 
aPairs[nPairIndex].Second, false,
+                                                        false);
+                            bCurrentValid = true;
+                            nPairIndex++;
+                        }
+                        break;
                     }
-                    for (int k = 0; k < rSegment.Count && bOK; ++k)
+                    case CURVETO:
                     {
-                        switch( rSegment.Command )
+                        if (nPairIndex + 2 >= aPairs.getLength())
+                            bOK = false;
+                        else
                         {
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
+                            mpFS->startElementNS(XML_a, XML_cubicBezTo);
+                            for (sal_uInt8 l = 0; l <= 2; ++l)
                             {
-                                if (nPairIndex >= aPairs.getLength())
-                                    bOK = false;
-                                else
-                                {
-                                    mpFS->startElementNS(XML_a, XML_moveTo);
-                                    
WriteCustomGeometryPoint(aPairs[nPairIndex], rSdrObjCustomShape);
-                                    mpFS->endElementNS( XML_a, XML_moveTo );
-                                    nPairIndex++;
-                                }
-                                break;
+                                WriteCustomGeometryPoint(aPairs[nPairIndex + 
l], aCustomShape2d);
                             }
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::LINETO :
+                            mpFS->endElementNS(XML_a, XML_cubicBezTo);
+                            aCustomShape2d.GetParameter(fCurrentX, 
aPairs[nPairIndex + 2].First,
+                                                        false, false);
+                            aCustomShape2d.GetParameter(fCurrentY, 
aPairs[nPairIndex + 2].Second,
+                                                        false, false);
+                            bCurrentValid = true;
+                            nPairIndex += 3;
+                        }
+                        break;
+                    }
+                    case ANGLEELLIPSETO:
+                    case ANGLEELLIPSE:
+                    {
+                        if (nPairIndex + 2 >= aPairs.getLength())
+                            bOK = false;
+                        else
+                        {
+                            // Read parameters
+                            double fCx = 0.0;
+                            aCustomShape2d.GetParameter(fCx, 
aPairs[nPairIndex].First, false,
+                                                        false);
+                            double fCy = 0.0;
+                            aCustomShape2d.GetParameter(fCy, 
aPairs[nPairIndex].Second, false,
+                                                        false);
+                            double fWR = 0.0;
+                            aCustomShape2d.GetParameter(fWR, aPairs[nPairIndex 
+ 1].First, false,
+                                                        false);
+                            double fHR = 0.0;
+                            aCustomShape2d.GetParameter(fHR, aPairs[nPairIndex 
+ 1].Second, false,
+                                                        false);
+                            double fStartAngle = 0.0;
+                            aCustomShape2d.GetParameter(fStartAngle, 
aPairs[nPairIndex + 2].First,
+                                                        false, false);
+                            double fEndAngle = 0.0;
+                            aCustomShape2d.GetParameter(fEndAngle, 
aPairs[nPairIndex + 2].Second,
+                                                        false, false);
+
+                            // Prepare start and swing angle
+                            sal_Int32 nStartAng(std::lround(fStartAngle * 
60000));
+                            sal_Int32 nSwingAng = 0;
+                            if (basegfx::fTools::equalZero(fStartAngle)
+                                && basegfx::fTools::equalZero(fEndAngle - 
360.0))
+                                nSwingAng = 360 * 60000; // special case full 
circle
+                            else
                             {
-                                if (nPairIndex >= aPairs.getLength())
-                                    bOK = false;
-                                else
-                                {
-                                    mpFS->startElementNS(XML_a, XML_lnTo);
-                                    
WriteCustomGeometryPoint(aPairs[nPairIndex], rSdrObjCustomShape);
-                                    mpFS->endElementNS( XML_a, XML_lnTo );
-                                    nPairIndex++;
-                                }
-                                break;
+                                nSwingAng = std::lround((fEndAngle - 
fStartAngle) * 60000);
+                                if (nSwingAng < 0)
+                                    nSwingAng += 360 * 60000;
                             }
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
+
+                            // calculate start point on ellipse
+                            double fSx = 0.0;
+                            double fSy = 0.0;
+                            getEllipsePointFromViewAngle(fSx, fSy, fWR, fHR, 
fCx, fCy, fStartAngle);
+
+                            // write markup for going to start point
+                            if (rSegment.Command == ANGLEELLIPSETO)
                             {
-                                if (nPairIndex + 2 >= aPairs.getLength())
-                                    bOK = false;
-                                else
-                                {
-                                    mpFS->startElementNS(XML_a, 
XML_cubicBezTo);
-                                    for( sal_uInt8 l = 0; l <= 2; ++l )
-                                    {
-                                        
WriteCustomGeometryPoint(aPairs[nPairIndex+l], rSdrObjCustomShape);
-                                    }
-                                    mpFS->endElementNS( XML_a, XML_cubicBezTo 
);
-                                    nPairIndex += 3;
-                                }
-                                break;
+                                mpFS->startElementNS(XML_a, XML_lnTo);
+                                mpFS->singleElementNS(XML_a, XML_pt, XML_x,
+                                                      
OString::number(std::lround(fSx)), XML_y,
+                                                      
OString::number(std::lround(fSy)));
+                                mpFS->endElementNS(XML_a, XML_lnTo);
                             }
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
+                            else
                             {
-                                nPairIndex += 3;
-                                break;
+                                mpFS->startElementNS(XML_a, XML_moveTo);
+                                mpFS->singleElementNS(XML_a, XML_pt, XML_x,
+                                                      
OString::number(std::lround(fSx)), XML_y,
+                                                      
OString::number(std::lround(fSy)));
+                                mpFS->endElementNS(XML_a, XML_moveTo);
                             }
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::ARC :
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
+                            // write markup for arcTo
+                            if (!basegfx::fTools::equalZero(fWR)
+                                && !basegfx::fTools::equalZero(fHR))
+                                mpFS->singleElement(FSNS(XML_a, XML_arcTo), 
XML_wR,
+                                                    
OString::number(std::lround(fWR)), XML_hR,
+                                                    
OString::number(std::lround(fHR)), XML_stAng,
+                                                    
OString::number(nStartAng), XML_swAng,
+                                                    
OString::number(nSwingAng));
+
+                            getEllipsePointFromViewAngle(fCurrentX, fCurrentY, 
fWR, fHR, fCx, fCy,
+                                                         fEndAngle);
+                            bCurrentValid = true;
+                            nPairIndex += 3;
+                        }
+                        break;
+                    }
+                    case ARCTO:
+                    case ARC:
+                    case CLOCKWISEARCTO:
+                    case CLOCKWISEARC:
+                    {
+                        if (nPairIndex + 3 >= aPairs.getLength())
+                            bOK = false;
+                        else
+                        {
+                            // read parameters
+                            double fX1 = 0.0;
+                            aCustomShape2d.GetParameter(fX1, 
aPairs[nPairIndex].First, false,
+                                                        false);
+                            double fY1 = 0.0;
+                            aCustomShape2d.GetParameter(fY1, 
aPairs[nPairIndex].Second, false,
+                                                        false);
+                            double fX2 = 0.0;
+                            aCustomShape2d.GetParameter(fX2, aPairs[nPairIndex 
+ 1].First, false,
+                                                        false);
+                            double fY2 = 0.0;
+                            aCustomShape2d.GetParameter(fY2, aPairs[nPairIndex 
+ 1].Second, false,
+                                                        false);
+                            double fX3 = 0.0;
+                            aCustomShape2d.GetParameter(fX3, aPairs[nPairIndex 
+ 2].First, false,
+                                                        false);
+                            double fY3 = 0.0;
+                            aCustomShape2d.GetParameter(fY3, aPairs[nPairIndex 
+ 2].Second, false,
+                                                        false);
+                            double fX4 = 0.0;
+                            aCustomShape2d.GetParameter(fX4, aPairs[nPairIndex 
+ 3].First, false,
+                                                        false);
+                            double fY4 = 0.0;
+                            aCustomShape2d.GetParameter(fY4, aPairs[nPairIndex 
+ 3].Second, false,
+                                                        false);
+                            // calculate ellipse parameter
+                            const double fWR = (fX2 - fX1) / 2.0;
+                            const double fHR = (fY2 - fY1) / 2.0;
+                            const double fCx = (fX1 + fX2) / 2.0;
+                            const double fCy = (fY1 + fY2) / 2.0;
+                            // calculate start angle
+                            double fStartAngle = 0.0;
+                            double fPx = 0.0;
+                            double fPy = 0.0;
+                            getEllipsePointAndAngleFromRayPoint(fStartAngle, 
fPx, fPy, fWR, fHR,
+                                                                fCx, fCy, fX3, 
fY3);
+                            // markup for going to start point
+                            if (rSegment.Command == ARCTO || rSegment.Command 
== CLOCKWISEARCTO)
                             {
-                                nPairIndex += 4;
-                                break;
+                                mpFS->startElementNS(XML_a, XML_lnTo);
+                                mpFS->singleElementNS(XML_a, XML_pt, XML_x,
+                                                      
OString::number(std::lround(fPx)), XML_y,
+                                                      
OString::number(std::lround(fPy)));
+                                mpFS->endElementNS(XML_a, XML_lnTo);
                             }
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
-                            case 
drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
+                            else
                             {
-                                nPairIndex++;
-                                break;
+                                mpFS->startElementNS(XML_a, XML_moveTo);
+                                mpFS->singleElementNS(XML_a, XML_pt, XML_x,
+                                                      
OString::number(std::lround(fPx)), XML_y,
+                                                      
OString::number(std::lround(fPy)));
+                                mpFS->endElementNS(XML_a, XML_moveTo);

... etc. - the rest is truncated

Reply via email to