[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.3' - 9 commits - cppcanvas/source cui/source editeng/source hwpfilter/source include/editeng include/svx oox/source scripting/source sd/qa sd/source svx/source sw/qa sw/source vcl/inc vcl/unx vcl/win writerfilter/source xmloff/inc xmloff/source

Caolán McNamara caolanm at redhat.com
Tue Apr 18 18:16:24 UTC 2017


 cppcanvas/source/mtfrenderer/emfplus.cxx          |   88 +++++++-----
 cui/source/tabpages/chardlg.cxx                   |    4 
 editeng/source/editeng/editdoc.cxx                |    3 
 editeng/source/editeng/editdoc.hxx                |    5 
 editeng/source/editeng/editeng.cxx                |   21 ++
 editeng/source/editeng/editobj.cxx                |   40 ++++-
 editeng/source/editeng/editobj2.hxx               |    6 
 editeng/source/editeng/impedit.cxx                |   82 +++++++++--
 editeng/source/editeng/impedit.hxx                |    4 
 editeng/source/editeng/impedit3.cxx               |  161 +++++++++++++++++-----
 editeng/source/editeng/impedit4.cxx               |    4 
 editeng/source/items/svxitems.src                 |    8 +
 editeng/source/items/textitem.cxx                 |  119 ++++++++++++++--
 editeng/source/outliner/outlin2.cxx               |    9 -
 editeng/source/outliner/outliner.cxx              |   29 +++
 editeng/source/outliner/outlobj.cxx               |   12 +
 hwpfilter/source/hpara.cxx                        |    2 
 include/editeng/charrotateitem.hxx                |   57 ++++++-
 include/editeng/editeng.hxx                       |    3 
 include/editeng/editobj.hxx                       |    3 
 include/editeng/editrids.hrc                      |    2 
 include/editeng/outliner.hxx                      |    3 
 include/editeng/outlobj.hxx                       |    3 
 include/svx/svddef.hxx                            |    3 
 oox/source/drawingml/table/tablecell.cxx          |    5 
 scripting/source/pyprov/pythonscript.py           |    7 
 sd/qa/unit/data/pptx/tdf100926.pptx               |binary
 sd/qa/unit/data/pptx/tdf100926_ODP.pptx           |binary
 sd/qa/unit/export-tests.cxx                       |   31 ++++
 sd/qa/unit/import-tests.cxx                       |   28 +++
 sd/source/ui/func/futext.cxx                      |    4 
 svx/source/svdraw/svdattr.cxx                     |    2 
 svx/source/svdraw/svdotext.cxx                    |    2 
 svx/source/svdraw/svdotextdecomposition.cxx       |   24 ++-
 svx/source/table/cell.cxx                         |   67 ++++++++-
 svx/source/table/svdotable.cxx                    |    4 
 svx/source/unodraw/unoshtxt.cxx                   |    2 
 sw/qa/extras/ooxmlexport/data/tdf106970.docx      |binary
 sw/qa/extras/ooxmlexport/ooxmlexport9.cxx         |    9 +
 sw/source/core/crsr/crstrvl.cxx                   |   20 ++
 sw/source/filter/ww8/ww8graf.cxx                  |   10 +
 vcl/inc/win/saldata.hxx                           |    4 
 vcl/unx/gtk/a11y/atkutil.cxx                      |    9 +
 vcl/win/app/salinst.cxx                           |    1 
 vcl/win/gdi/winlayout.cxx                         |   26 ++-
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |   18 ++
 xmloff/inc/xmlsdtypes.hxx                         |    2 
 xmloff/source/draw/sdpropls.cxx                   |   64 ++++++++
 xmloff/source/table/XMLTableExport.cxx            |   14 +
 xmloff/source/table/XMLTableImport.cxx            |    1 
 xmloff/source/table/table.hxx                     |    1 
 51 files changed, 855 insertions(+), 171 deletions(-)

New commits:
commit f2252864812adf7c91681a11ddb817a28376d406
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Tue Apr 18 09:15:23 2017 +0100

    catch exception like text_wrapper_get_caret_offset does
    
    Change-Id: I7d681a5cd58af60005eefa9969ec975d5cfc5580
    (cherry picked from commit 0d2a607a849e3f1b51092c7d96bc5529420cfab2)
    Reviewed-on: https://gerrit.libreoffice.org/36635
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Stahl <mstahl at redhat.com>
    (cherry picked from commit 615942e388c6dfa48d1edbf645fe6b0dd67cfa40)

diff --git a/vcl/unx/gtk/a11y/atkutil.cxx b/vcl/unx/gtk/a11y/atkutil.cxx
index 708417722788..6c3dca52a557 100644
--- a/vcl/unx/gtk/a11y/atkutil.cxx
+++ b/vcl/unx/gtk/a11y/atkutil.cxx
@@ -91,7 +91,14 @@ atk_wrapper_focus_idle_handler (gpointer data)
                     wrapper_obj->mpText.set(wrapper_obj->mpContext, css::uno::UNO_QUERY);
                     if ( wrapper_obj->mpText.is() )
                     {
-                        gint caretPos = wrapper_obj->mpText->getCaretPosition();
+                        gint caretPos = -1;
+
+                        try {
+                            caretPos = wrapper_obj->mpText->getCaretPosition();
+                        }
+                        catch(const uno::Exception&) {
+                            g_warning( "Exception in getCaretPosition()" );
+                        }
 
                         if ( caretPos != -1 )
                         {
commit 3e1304da32ace76b51d869b641676257d3ebd875
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Sun Apr 16 14:25:25 2017 +0100

    coverity#1405158 Wrong sizeof argument
    
    Change-Id: Ie6b7fc3d2b7d1ac709501698e55aabc72215b187
    (cherry picked from commit b17177c63a4eac55dcdaa3006abec05ab71ca1b4)
    Reviewed-on: https://gerrit.libreoffice.org/36578
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit ee85316249902aa19f4426acae546ee79a083b07)

diff --git a/hwpfilter/source/hpara.cxx b/hwpfilter/source/hpara.cxx
index 3149d65acf0a..cce909ead16e 100644
--- a/hwpfilter/source/hpara.cxx
+++ b/hwpfilter/source/hpara.cxx
@@ -78,7 +78,7 @@ HWPPara::HWPPara()
     , cshape(new CharShape)
     , linfo(nullptr)
 {
-    memset(cshape.get(), 0, sizeof(cshape));
+    memset(cshape.get(), 0, sizeof(CharShape));
     memset(&pshape, 0, sizeof(pshape));
 }
 
commit 06af76cf2574112aef759f96c0ab2d5de09e94ad
Author: Michael Stahl <mstahl at redhat.com>
Date:   Thu Apr 13 17:28:46 2017 +0200

    tdf#106933 vcl: delete D2DWriteTextOutRenderer before exit()
    
    As it happens this DirectWrite stuff is using some thread pool
    internally, and that must be shutdown before exit(), as Win32 will
    terminate all other threads at that point, and then the thread pool
    wants to talk to threads that don't exist any more.
    
    https://blogs.msdn.microsoft.com/oldnewthing/20120427-00/?p=7763/
    
    So convert this from a global variable that is deleted from DllMain()
    to a member of SalData, so it is deleted from DeInitVCL().
    
    Change-Id: I51408a07c78758cf0c193ab66b9214d0c9dbd9e3
    (cherry picked from commit df556aa47da22f96b3fcd356c12419d3035cba3c)
    Reviewed-on: https://gerrit.libreoffice.org/36534
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Markus Mohrhard <markus.mohrhard at googlemail.com>
    (cherry picked from commit 1ba5bae490f7e14e475e0b80f03e5f444cdce908)

diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx
index fc82e13b617a..cf11a04ddace 100644
--- a/vcl/inc/win/saldata.hxx
+++ b/vcl/inc/win/saldata.hxx
@@ -39,6 +39,7 @@ class WinSalPrinter;
 namespace vcl { class Font; }
 struct HDCCache;
 struct TempFontItem;
+class TextOutRenderer;
 
 #define MAX_STOCKPEN            4
 #define MAX_STOCKBRUSH          4
@@ -118,6 +119,9 @@ public:
 
     std::set< HMENU >       mhMenuSet;              // keeps track of menu handles created by VCL, used by IsKnownMenuHandle()
     std::map< UINT,sal_uInt16 > maVKMap;      // map some dynamic VK_* entries
+
+    // must be deleted before exit(), so delete it in DeInitSalData()
+    std::unique_ptr<TextOutRenderer> m_pTextOutRenderer;
 };
 
 inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = pData; }
diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx
index 94ae96d53608..da67ca44582f 100644
--- a/vcl/win/app/salinst.cxx
+++ b/vcl/win/app/salinst.cxx
@@ -39,6 +39,7 @@
 #include "win/salobj.h"
 #include "win/saltimer.h"
 #include "win/salbmp.h"
+#include "win/winlayout.hxx"
 
 #include "salimestatus.hxx"
 #include "salsys.hxx"
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index 482cbd7a460c..22a6fb268f55 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -3072,20 +3072,26 @@ void D2DWriteTextOutRenderer::CleanupModules()
 
 TextOutRenderer & TextOutRenderer::get(bool bUseDWrite)
 {
-    if (bUseDWrite)
-    {
-        static std::unique_ptr<TextOutRenderer> _impl(D2DWriteTextOutRenderer::InitModules()
-            ? static_cast<TextOutRenderer*>(new D2DWriteTextOutRenderer())
-            : static_cast<TextOutRenderer*>(new ExTextOutRenderer()));
+    SalData *const pSalData = GetSalData();
 
-        return *_impl;
+    if (!pSalData)
+    {   // don't call this after DeInitVCL()
+        fprintf(stderr, "TextOutRenderer fatal error: no SalData");
+        abort();
     }
-    else
-    {
-        static std::unique_ptr<TextOutRenderer> _impl(new ExTextOutRenderer());
 
-        return *_impl;
+    if (!pSalData->m_pTextOutRenderer)
+    {
+        if (bUseDWrite && D2DWriteTextOutRenderer::InitModules())
+        {
+            pSalData->m_pTextOutRenderer.reset(new D2DWriteTextOutRenderer());
+        }
+        else
+        {
+            pSalData->m_pTextOutRenderer.reset(new ExTextOutRenderer());
+        }
     }
+    return *pSalData->m_pTextOutRenderer;
 }
 
 
commit ff0c559692c263d5eb4243289cdabf79afaff13e
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Apr 13 13:01:35 2017 +0100

    ofz: header has to be at least 1 pair long
    
    Change-Id: I5725048519a2b68265e90d12b1e4bcb506c56fc2
    (cherry picked from commit e72f3ce68e18ac604469ce5e856341a469af27ff)
    Reviewed-on: https://gerrit.libreoffice.org/36519
    Reviewed-by: Michael Stahl <mstahl at redhat.com>
    Tested-by: Michael Stahl <mstahl at redhat.com>
    (cherry picked from commit d180418fedd4592044c33558426e9ea9be6f1ebd)

diff --git a/sw/source/filter/ww8/ww8graf.cxx b/sw/source/filter/ww8/ww8graf.cxx
index 09e6dfd3f893..718faff1c16c 100644
--- a/sw/source/filter/ww8/ww8graf.cxx
+++ b/sw/source/filter/ww8/ww8graf.cxx
@@ -1246,12 +1246,20 @@ SdrObject* SwWW8ImplReader::ReadCaptionBox(WW8_DPHEAD* pHd, SfxAllItemSet &rSet)
         return nullptr;
 
     sal_uInt16 nCount = SVBT16ToShort( aCallB.dpPolyLine.aBits1 ) >> 1 & 0x7fff;
+    if (nCount < 1)
+    {
+        SAL_WARN("sw.ww8", "Short CaptionBox header");
+        return nullptr;
+    }
+
     std::unique_ptr<SVBT16[]> xP(new SVBT16[nCount * 2]);
 
     bool bCouldRead = checkRead(*m_pStrm, xP.get(), nCount * 4);      // Punkte einlesen
-    OSL_ENSURE(bCouldRead, "Short CaptionBox header");
     if (!bCouldRead)
+    {
+        SAL_WARN("sw.ww8", "Short CaptionBox header");
         return nullptr;
+    }
 
     sal_uInt8 nTyp = (sal_uInt8)nCount - 1;
     if( nTyp == 1 && SVBT16ToShort( xP[0] ) == SVBT16ToShort( xP[2] ) )
commit df0fc826e0acf76b95af8221a9da9cae37558074
Author: Bartosz Kosiorek <gang65 at poczta.onet.pl>
Date:   Fri Apr 7 13:24:41 2017 +0200

    Replace EmfPlusRecordType decimal valuse with hex
    
    Change-Id: Ia5f248282e663e86b76a8c90fb5dd55d112f6912
    Reviewed-on: https://gerrit.libreoffice.org/36260
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Bartosz Kosiorek <gang65 at poczta.onet.pl>
    (cherry picked from commit 723ee43cf65f85d7b586ae8c98529a22621054a3)
    Reviewed-on: https://gerrit.libreoffice.org/36522
    (cherry picked from commit 42bf09876a8cb7faef0c2490ff3e7531de4fec8f)

diff --git a/cppcanvas/source/mtfrenderer/emfplus.cxx b/cppcanvas/source/mtfrenderer/emfplus.cxx
index d05dd2f04e67..a03b02d2b8b3 100644
--- a/cppcanvas/source/mtfrenderer/emfplus.cxx
+++ b/cppcanvas/source/mtfrenderer/emfplus.cxx
@@ -50,39 +50,61 @@
 namespace
 {
 
-#define EmfPlusRecordTypeHeader 16385
-#define EmfPlusRecordTypeEndOfFile 16386
-#define EmfPlusRecordTypeGetDC 16388
-#define EmfPlusRecordTypeObject 16392
-#define EmfPlusRecordTypeFillRects 16394
-#define EmfPlusRecordTypeFillPolygon 16396
-#define EmfPlusRecordTypeDrawLines 16397
-#define EmfPlusRecordTypeFillEllipse 16398
-#define EmfPlusRecordTypeDrawEllipse 16399
-#define EmfPlusRecordTypeFillPie 16400
-#define EmfPlusRecordTypeFillPath 16404
-#define EmfPlusRecordTypeDrawPath 16405
-#define EmfPlusRecordTypeDrawImage 16410
-#define EmfPlusRecordTypeDrawImagePoints 16411
-#define EmfPlusRecordTypeDrawString 16412
-#define EmfPlusRecordTypeSetRenderingOrigin 16413
-#define EmfPlusRecordTypeSetAntiAliasMode 16414
-#define EmfPlusRecordTypeSetTextRenderingHint 16415
-#define EmfPlusRecordTypeSetInterpolationMode 16417
-#define EmfPlusRecordTypeSetPixelOffsetMode 16418
-#define EmfPlusRecordTypeSetCompositingQuality 16420
-#define EmfPlusRecordTypeSave 16421
-#define EmfPlusRecordTypeRestore 16422
-#define EmfPlusRecordTypeBeginContainerNoParams 16424
-#define EmfPlusRecordTypeEndContainer 16425
-#define EmfPlusRecordTypeSetWorldTransform 16426
-#define EmfPlusRecordTypeResetWorldTransform 16427
-#define EmfPlusRecordTypeMultiplyWorldTransform 16428
-#define EmfPlusRecordTypeSetPageTransform 16432
-#define EmfPlusRecordTypeSetClipRect 16434
-#define EmfPlusRecordTypeSetClipPath 16435
-#define EmfPlusRecordTypeSetClipRegion 16436
-#define EmfPlusRecordTypeDrawDriverString 16438
+#define EmfPlusRecordTypeHeader 0x4001
+#define EmfPlusRecordTypeEndOfFile 0x4002
+//TODO EmfPlusRecordTypeComment 0x4003
+#define EmfPlusRecordTypeGetDC 0x4004
+//TODO EmfPlusRecordTypeMultiFormatStart 0x4005
+//TODO EmfPlusRecordTypeMultiFormatSection 0x4006
+//TODO EmfPlusRecordTypeMultiFormatEnd 0x4007
+#define EmfPlusRecordTypeObject 0x4008
+//TODO EmfPlusRecordTypeClear 0x4009
+#define EmfPlusRecordTypeFillRects 0x400A
+#define EmfPlusRecordTypeFillPolygon 0x400C
+#define EmfPlusRecordTypeDrawLines 0x400D
+#define EmfPlusRecordTypeFillEllipse 0x400E
+#define EmfPlusRecordTypeDrawEllipse 0x400F
+#define EmfPlusRecordTypeFillPie 0x4010
+//TODO EmfPlusRecordTypeDrawPie 0x4011
+//TODO EmfPlusRecordTypeDrawArc 0x4012
+//TODO EmfPlusRecordTypeFillRegion 0x4013
+#define EmfPlusRecordTypeFillPath 0x4014
+#define EmfPlusRecordTypeDrawPath 0x4015
+//TODO EmfPlusRecordTypeFillClosedCurve 0x4016
+//TODO EmfPlusRecordTypeDrawClosedCurve 0x4017
+//TODO EmfPlusRecordTypeDrawCurve 0x4018
+//TODO EmfPlusRecordTypeDrawBeziers 0x4019
+#define EmfPlusRecordTypeDrawImage 0x401A
+#define EmfPlusRecordTypeDrawImagePoints 0x401B
+#define EmfPlusRecordTypeDrawString 0x401C
+#define EmfPlusRecordTypeSetRenderingOrigin 0x401D
+#define EmfPlusRecordTypeSetAntiAliasMode 0x401E
+#define EmfPlusRecordTypeSetTextRenderingHint 0x401F
+#define EmfPlusRecordTypeSetInterpolationMode 0x4021
+#define EmfPlusRecordTypeSetPixelOffsetMode 0x4022
+//TODO EmfPlusRecordTypeSetCompositingMode 0x4023
+#define EmfPlusRecordTypeSetCompositingQuality 0x4024
+#define EmfPlusRecordTypeSave 0x4025
+#define EmfPlusRecordTypeRestore 0x4026
+//TODO EmfPlusRecordTypeBeginContainer 0x4027
+#define EmfPlusRecordTypeBeginContainerNoParams 0x4028
+#define EmfPlusRecordTypeEndContainer 0x4027
+#define EmfPlusRecordTypeSetWorldTransform 0x402A
+#define EmfPlusRecordTypeResetWorldTransform 0x402B
+#define EmfPlusRecordTypeMultiplyWorldTransform 0x402C
+//TODO EmfPlusRecordTypeScaleWorldTransform 0x402E
+//TODO EmfPlusRecordTypeRotateWorldTransform 0x402F
+#define EmfPlusRecordTypeSetPageTransform 0x4030
+//TODO EmfPlusRecordTypeResetClip 0x4031
+#define EmfPlusRecordTypeSetClipRect 0x4032
+#define EmfPlusRecordTypeSetClipPath 0x4033
+#define EmfPlusRecordTypeSetClipRegion 0x4034
+//TODO EmfPlusRecordTypeOffsetClip 0x4035
+#define EmfPlusRecordTypeDrawDriverString 0x4036
+//TODO EmfPlusRecordTypeStrokeFillPath 0x4037
+//TODO EmfPlusRecordTypeSerializableObject 0x4038
+//TODO EmfPlusRecordTypeSetTSGraphics 0x4039
+//TODO EmfPlusRecordTypeSetTSClip 0x403A
 
 #define EmfPlusObjectTypeBrush 0x100
 #define EmfPlusObjectTypePen 0x200
commit 20765811a89cd37f978674e1188d949be31813ea
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Apr 11 08:54:36 2017 +0200

    tdf#106970 DOCX import: don't collapse para auto space for different nums
    
    Commit 1bf7f6a1a50ee9f24a3687240fe6ae390b905a6b (tdf#106690 DOCX import:
    fix automatic spacing before/after numbered para block, 2017-04-04) made
    sure that autospacing is only collapsed in case the adjacent text nodes
    both have a numbering rule.
    
    It turns out there is an additional condition: even if both text nodes
    have a numbering rule, do the collapsing only in case they have the same
    numbering rule.
    
    (cherry picked from commit e1c83d0514e6123faa50ad0a7aa6a9031b271c9a)
    
    Change-Id: Idb7a2b24d7eaa9094cc36f86b8a483045a33d028
    Reviewed-on: https://gerrit.libreoffice.org/36510
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Stahl <mstahl at redhat.com>
    (cherry picked from commit e57873156d3c04ecc34bb5f38b186ebe29567f0c)

diff --git a/sw/qa/extras/ooxmlexport/data/tdf106970.docx b/sw/qa/extras/ooxmlexport/data/tdf106970.docx
new file mode 100644
index 000000000000..8a534558b641
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf106970.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx
index e48f51824749..99695f570cc7 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx
@@ -58,6 +58,15 @@ DECLARE_OOXMLEXPORT_TEST(testTdf106690, "tdf106690.docx")
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(494), getProperty<sal_Int32>(getParagraph(2), "ParaTopMargin"));
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf106970, "tdf106970.docx")
+{
+    // The second paragraph (first numbered one) had 0 bottom margin:
+    // autospacing was even collapsed between different numbering styles.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(494), getProperty<sal_Int32>(getParagraph(2), "ParaBottomMargin"));
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), getProperty<sal_Int32>(getParagraph(3), "ParaBottomMargin"));
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(494), getProperty<sal_Int32>(getParagraph(4), "ParaBottomMargin"));
+}
+
 DECLARE_OOXMLEXPORT_TEST(testTdf89377, "tdf89377_tableWithBreakBeforeParaStyle.docx")
 {
     // the paragraph style should set table's text-flow break-before-page
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 236436cbd362..a9473ef74c68 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -1178,10 +1178,22 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap )
                     });
                     if (itNumberingRules != aProperties.end())
                     {
-                        // This textnode has numbering.
-                        if (m_xPreviousParagraph.is() && m_xPreviousParagraph->getPropertyValue("NumberingRules").hasValue())
+                        // This textnode has numbering. Look up the numbering style name of the current and previous paragraph.
+                        OUString aCurrentNumberingRuleName;
+                        uno::Reference<container::XNamed> xCurrentNumberingRules(itNumberingRules->Value, uno::UNO_QUERY);
+                        if (xCurrentNumberingRules.is())
+                            aCurrentNumberingRuleName = xCurrentNumberingRules->getName();
+                        OUString aPreviousNumberingRuleName;
+                        if (m_xPreviousParagraph.is())
                         {
-                            // There was a previous textnode and it had numbering.
+                            uno::Reference<container::XNamed> xPreviousNumberingRules(m_xPreviousParagraph->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
+                            if (xPreviousNumberingRules.is())
+                                aPreviousNumberingRuleName = xPreviousNumberingRules->getName();
+                        }
+
+                        if (!aPreviousNumberingRuleName.isEmpty() && aCurrentNumberingRuleName == aPreviousNumberingRuleName)
+                        {
+                            // There was a previous textnode and it had the same numbering.
                             if (m_bParaAutoBefore)
                             {
                                 // This before spacing is set to auto, set before space to 0.
commit d9db45db3f0741f1d7a6584e0b4d34efc236b717
Author: Werner Tietz <karlooforum at arcor.de>
Date:   Tue Apr 11 01:51:11 2017 +0200

    tdf#92007 python scripts with tuple-assignments fails on access from GUI
    
    Change-Id: Ice1d7d92cec56751cb26cbb31a5995ab30895125
    Reviewed-on: https://gerrit.libreoffice.org/36399
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Stahl <mstahl at redhat.com>
    (cherry picked from commit 7ef47336411389ac492729bef52fe62aebe90f5a)
    Reviewed-on: https://gerrit.libreoffice.org/36483
    (cherry picked from commit 9a6d78b722f3a49f71a680e49cf64e7cfb637c43)

diff --git a/scripting/source/pyprov/pythonscript.py b/scripting/source/pyprov/pythonscript.py
index 6089d14edefe..e312c6a52fbf 100644
--- a/scripting/source/pyprov/pythonscript.py
+++ b/scripting/source/pyprov/pythonscript.py
@@ -405,7 +405,12 @@ class ProviderContext:
                 allFuncs.append(node.name)
             elif isinstance(node, ast.Assign):
                 for target in node.targets:
-                    if target.id == "g_exportedScripts":
+                    try:
+                        identifier = target.id
+                    except AttributeError:
+                        identifier = ""
+                        pass
+                    if identifier == "g_exportedScripts":
                         for value in node.value.elts:
                             g_exportedScripts.append(value.id)
                         return g_exportedScripts
commit 7a9c6ef9b282ea1112320c87adcadfb22a422116
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Mon Apr 10 15:14:37 2017 +0100

    Resolves: tdf#106078 get bounding box of commented region for gtk3 tooltips
    
    Change-Id: I4fdc1f471c6c191be9c7c611926bd2b5b2b41308
    (cherry picked from commit eb433f83a5f66dd1ca8ed0c62ef9cc0761b7f0ac)
    Reviewed-on: https://gerrit.libreoffice.org/36383
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Stahl <mstahl at redhat.com>
    (cherry picked from commit 244d2abb6c1bcd89cedf773d8721f62451708c3f)

diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index c024e0eb7d69..9bdc9b932768 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -1440,12 +1440,18 @@ bool SwCursorShell::GetContentAtPos( const Point& rPt,
 
                             if( pFieldRect && nullptr != ( pFrame = pTextNd->getLayoutFrame( GetLayout(), &aPt ) ) )
                             {
+                                //get bounding box of range
                                 SwRect aStart;
                                 SwPosition aStartPos(*pTextNd, nSt);
                                 pFrame->GetCharRect(aStart, aStartPos, &aTmpState);
                                 SwRect aEnd;
                                 SwPosition aEndPos(*pTextNd, nEnd);
                                 pFrame->GetCharRect(aEnd, aEndPos, &aTmpState);
+                                if (aStart.Top() != aEnd.Top() || aStart.Bottom() != aEnd.Bottom())
+                                {
+                                    aStart.Left(pFrame->Frame().Left());
+                                    aEnd.Right(pFrame->Frame().Right());
+                                }
                                 *pFieldRect = aStart.Union(aEnd);
                             }
                         }
@@ -1463,7 +1469,19 @@ bool SwCursorShell::GetContentAtPos( const Point& rPt,
                         bRet = true;
 
                         if( pFieldRect && nullptr != ( pFrame = pTextNd->getLayoutFrame( GetLayout(), &aPt ) ) )
-                            pFrame->GetCharRect( *pFieldRect, aPos, &aTmpState );
+                        {
+                            //get bounding box of range
+                            SwRect aStart;
+                            pFrame->GetCharRect(aStart, *pRedl->Start(), &aTmpState);
+                            SwRect aEnd;
+                            pFrame->GetCharRect(aEnd, *pRedl->End(), &aTmpState);
+                            if (aStart.Top() != aEnd.Top() || aStart.Bottom() != aEnd.Bottom())
+                            {
+                                aStart.Left(pFrame->Frame().Left());
+                                aEnd.Right(pFrame->Frame().Right());
+                            }
+                            *pFieldRect = aStart.Union(aEnd);
+                        }
                     }
                 }
             }
commit 253e2035474b830c07bf327ca7204fa362312a47
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Tue Mar 28 19:24:49 2017 +0200

    tdf#105286: Implement text rotation for Impress tables
    
    Typo: TopToBotton -> TopToBottom
    
    Change-Id: I1b4d3ab9ec1d1383d76a56c9662ffeeb9fe69655
    Reviewed-on: https://gerrit.libreoffice.org/36014
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit 334e6e2f1ad3da319be0849ec426aa64b18cb599)
    
    Add SvxTextRotateItem inherited from SvxCharRotatItem
    
    I will be use it later for text rotation inside a table.
    
    Change-Id: I4cbaf05953b0e71331d2f3fdb45b7c4254a2b8cc
    Reviewed-on: https://gerrit.libreoffice.org/36021
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    Tested-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit 1e30d2aface12a31687e5a27126e2061efd4b0cd)
    
    Introduce text rotation for Impress tables
    
    * Introduce new table property for text rotation
    * Support only two rotation angle (270° and 90°)
    * Implement editing and rendering of 270° rotated
    text (90° rotation was already implemented)
    
    (cherry picked from commit c671094154ecec6f3ba5beea9d26ff0d2d4d86ad)
    
    Change-Id: Ifc2e0f171e9c840e86b365e9af2c30aa97ecd92e
    
    Implement RotateAngle API property for Impress table cells
    
    (cherry picked from commit a0755ab8772d01797f4945016a978a2bbd8fdf20)
    
    Change-Id: I01379c0fc21e8fe294bc882bf824f64502863ff4
    
    tdf#100926: PPTX import of table with rotated text
    
    (cherry picked from commit 2436cf17304f25c7d34da52a321d6da0e9011d19)
    
    Change-Id: I05a8e979ac11b179e15784023032a56edc5b569b
    
    ODF import / export of rotated text in Impress table
    
    (cherry picked from commit bcb371b1a830442610ad7fda476eda5271427a50)
    
    Change-Id: I57136e32ed2db5e405a45e8e4bad1b8d459b7ae8
    
    Fix vertical text and bitmap bullet rendering
    
    Change-Id: I881fce0511c81b164516d68f72c7e750687d4e0e
    (cherry picked from commit 15ac3f9f4dc65fc0c6020284064e3725956f5d0a)

diff --git a/cui/source/tabpages/chardlg.cxx b/cui/source/tabpages/chardlg.cxx
index f9958c81dd1c..5d879817f9a1 100644
--- a/cui/source/tabpages/chardlg.cxx
+++ b/cui/source/tabpages/chardlg.cxx
@@ -2954,7 +2954,7 @@ void SvxCharPositionPage::Reset( const SfxItemSet* rSet )
                     static_cast<const SvxCharRotateItem&>( rSet->Get( nWhich ));
             if (rItem.IsBottomToTop())
                 m_p90degRB->Check();
-            else if (rItem.IsTopToBotton())
+            else if (rItem.IsTopToBottom())
                 m_p270degRB->Check();
             else
             {
@@ -3111,7 +3111,7 @@ bool SvxCharPositionPage::FillItemSet( SfxItemSet* rSet )
         if (m_p90degRB->IsChecked())
             aItem.SetBottomToTop();
         else if (m_p270degRB->IsChecked())
-            aItem.SetTopToBotton();
+            aItem.SetTopToBottom();
         rSet->Put( aItem );
         bModified = true;
     }
diff --git a/editeng/source/editeng/editdoc.cxx b/editeng/source/editeng/editdoc.cxx
index a7a73ceea4f6..8763b0733594 100644
--- a/editeng/source/editeng/editdoc.cxx
+++ b/editeng/source/editeng/editdoc.cxx
@@ -1982,6 +1982,7 @@ EditDoc::EditDoc( SfxItemPool* pPool ) :
     pItemPool(pPool ? pPool : new EditEngineItemPool(false)),
     nDefTab(DEFTAB),
     bIsVertical(false),
+    bIsTopToBottomVert(false),
     bIsFixedCellHeight(false),
     bOwnerOfPool(pPool == nullptr),
     bModified(false)
@@ -2116,7 +2117,7 @@ void EditDoc::CreateDefFont( bool bUseStyles )
     SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END );
     CreateFont( aDefFont, aTmpSet );
     aDefFont.SetVertical( IsVertical() );
-    aDefFont.SetOrientation( IsVertical() ? 2700 : 0 );
+    aDefFont.SetOrientation( IsVertical() ? (IsTopToBottom() ? 2700 : 900) : 0 );
 
     for ( sal_Int32 nNode = 0; nNode < Count(); nNode++ )
     {
diff --git a/editeng/source/editeng/editdoc.hxx b/editeng/source/editeng/editdoc.hxx
index 63d5961165ac..bb647933fab5 100644
--- a/editeng/source/editeng/editdoc.hxx
+++ b/editeng/source/editeng/editdoc.hxx
@@ -739,6 +739,7 @@ private:
     SvxFont         aDefFont;           //faster than ever from the pool!!
     sal_uInt16      nDefTab;
     bool            bIsVertical:1;
+    bool            bIsTopToBottomVert : 1;
     bool            bIsFixedCellHeight:1;
 
     bool            bOwnerOfPool:1;
@@ -765,8 +766,10 @@ public:
     void            SetDefTab( sal_uInt16 nTab )    { nDefTab = nTab ? nTab : DEFTAB; }
     sal_uInt16      GetDefTab() const           { return nDefTab; }
 
-    void            SetVertical( bool bVertical )   { bIsVertical = bVertical; }
+    void            SetVertical( bool bVertical, bool bTopToBottom = true )
+                    { bIsVertical = bVertical; bIsTopToBottomVert = bVertical && bTopToBottom; }
     bool            IsVertical() const              { return bIsVertical; }
+    bool            IsTopToBottom() const           { return bIsTopToBottomVert; }
 
     void            SetFixedCellHeight( bool bUseFixedCellHeight )  { bIsFixedCellHeight = bUseFixedCellHeight; }
     bool            IsFixedCellHeight() const               { return bIsFixedCellHeight; }
diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx
index bde286a10b72..5f88c0e36a10 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -429,9 +429,9 @@ const Size& EditEngine::GetPaperSize() const
     return pImpEditEngine->GetPaperSize();
 }
 
-void EditEngine::SetVertical( bool bVertical )
+void EditEngine::SetVertical( bool bVertical, bool bTopToBottom )
 {
-    pImpEditEngine->SetVertical( bVertical );
+    pImpEditEngine->SetVertical( bVertical, bTopToBottom);
 }
 
 bool EditEngine::IsVertical() const
@@ -439,6 +439,11 @@ bool EditEngine::IsVertical() const
     return pImpEditEngine->IsVertical();
 }
 
+bool EditEngine::IsTopToBottom() const
+{
+    return pImpEditEngine->IsTopToBottom();
+}
+
 void EditEngine::SetFixedCellHeight( bool bUseFixedCellHeight )
 {
     pImpEditEngine->SetFixedCellHeight( bUseFixedCellHeight );
@@ -1767,8 +1772,16 @@ void EditEngine::StripPortions()
     Rectangle aBigRect( Point( 0, 0 ), Size( 0x7FFFFFFF, 0x7FFFFFFF ) );
     if ( IsVertical() )
     {
-        aBigRect.Right() = 0;
-        aBigRect.Left() = -0x7FFFFFFF;
+        if( IsTopToBottom() )
+        {
+            aBigRect.Right() = 0;
+            aBigRect.Left() = -0x7FFFFFFF;
+        }
+        else
+        {
+            aBigRect.Top() = -0x7FFFFFFF;
+            aBigRect.Bottom() = 0;
+        }
     }
     pImpEditEngine->Paint( aTmpDev.get(), aBigRect, Point(), true );
 }
diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx
index 5a370837d350..e64793cddc00 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -355,9 +355,14 @@ bool EditTextObject::IsVertical() const
     return mpImpl->IsVertical();
 }
 
-void EditTextObject::SetVertical( bool bVertical )
+bool EditTextObject::IsTopToBottom() const
 {
-    return mpImpl->SetVertical(bVertical);
+    return mpImpl->IsTopToBottom();
+}
+
+void EditTextObject::SetVertical( bool bVertical, bool bTopToBottom )
+{
+    return mpImpl->SetVertical(bVertical, bTopToBottom);
 }
 
 SvtScriptType EditTextObject::GetScriptType() const
@@ -562,6 +567,7 @@ EditTextObjectImpl::EditTextObjectImpl( EditTextObject* pFront, SfxItemPool* pP
     }
 
     bVertical = false;
+    bIsTopToBottomVert = false;
     bStoreUnicodeStrings = false;
     nScriptType = SvtScriptType::NONE;
 }
@@ -574,6 +580,7 @@ EditTextObjectImpl::EditTextObjectImpl( EditTextObject* pFront, const EditTextOb
     nUserType = r.nUserType;
     nObjSettings = r.nObjSettings;
     bVertical = r.bVertical;
+    bIsTopToBottomVert = r.bIsTopToBottomVert;
     nScriptType = r.nScriptType;
     pPortionInfo = nullptr;    // Do not copy PortionInfo
     bStoreUnicodeStrings = false;
@@ -655,12 +662,22 @@ std::vector<svl::SharedString> EditTextObjectImpl::GetSharedStrings() const
     return aSSs;
 }
 
+bool EditTextObjectImpl::IsVertical() const
+{
+    return bVertical;
+}
+
+bool EditTextObjectImpl::IsTopToBottom() const
+{
+    return bIsTopToBottomVert;
+}
 
-void EditTextObjectImpl::SetVertical( bool b )
+void EditTextObjectImpl::SetVertical( bool bVert, bool bTopToBottom)
 {
-    if ( b != bVertical )
+    if (bVert != bVertical || bTopToBottom != (bVert && bIsTopToBottomVert))
     {
-        bVertical = b;
+        bVertical = bVert;
+        bIsTopToBottomVert = bVert && bTopToBottom;
         ClearPortionInfo();
     }
 }
@@ -1090,7 +1107,7 @@ public:
 
 void EditTextObjectImpl::StoreData( SvStream& rOStream ) const
 {
-    sal_uInt16 nVer = 602;
+    sal_uInt16 nVer = 603;
     rOStream.WriteUInt16( nVer );
 
     rOStream.WriteBool( bOwnerOfPool );
@@ -1229,6 +1246,7 @@ void EditTextObjectImpl::StoreData( SvStream& rOStream ) const
     rOStream.WriteUInt32( nObjSettings );
 
     rOStream.WriteBool( bVertical );
+    rOStream.WriteBool( bIsTopToBottomVert );
     rOStream.WriteUInt16( static_cast<sal_uInt16>(nScriptType) );
 
     rOStream.WriteBool( bStoreUnicodeStrings );
@@ -1481,6 +1499,13 @@ void EditTextObjectImpl::CreateData( SvStream& rIStream )
         bVertical = bTmp;
     }
 
+    if (nVersion >= 603)
+    {
+        bool bTmp(false);
+        rIStream.ReadCharAsBool(bTmp);
+        bIsTopToBottomVert = bTmp;
+    }
+
     if ( nVersion >= 602 )
     {
         sal_uInt16 aTmp16;
@@ -1571,7 +1596,8 @@ bool EditTextObjectImpl::operator==( const EditTextObjectImpl& rCompare ) const
             ( nMetric != rCompare.nMetric ) ||
             ( nUserType!= rCompare.nUserType ) ||
             ( nScriptType != rCompare.nScriptType ) ||
-            ( bVertical != rCompare.bVertical ) )
+            ( bVertical != rCompare.bVertical ) ||
+            ( bIsTopToBottomVert != rCompare.bIsTopToBottomVert ) )
         return false;
 
     for (size_t i = 0, n = aContents.size(); i < n; ++i)
diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx
index 9aaef1d441eb..746635409d8f 100644
--- a/editeng/source/editeng/editobj2.hxx
+++ b/editeng/source/editeng/editobj2.hxx
@@ -182,6 +182,7 @@ private:
 
     bool                    bOwnerOfPool:1;
     bool                    bVertical:1;
+    bool                    bIsTopToBottomVert : 1;
     bool                    bStoreUnicodeStrings:1;
 
     bool ImpChangeStyleSheets( const OUString& rOldName, SfxStyleFamily eOldFamily,
@@ -204,8 +205,9 @@ public:
     void NormalizeString( svl::SharedStringPool& rPool );
     std::vector<svl::SharedString> GetSharedStrings() const;
 
-    bool                    IsVertical() const { return bVertical;}
-    void                    SetVertical( bool b );
+    bool                    IsVertical() const;
+    bool                    IsTopToBottom() const;
+    void                    SetVertical( bool bVert, bool bTopToBottom = true);
 
     SvtScriptType           GetScriptType() const { return nScriptType;}
     void                    SetScriptType( SvtScriptType nType );
diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index e4eb6156b27e..a8af19d86982 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -513,6 +513,11 @@ bool ImpEditView::IsVertical() const
     return pEditEngine->pImpEditEngine->IsVertical();
 }
 
+bool ImpEditView::IsTopToBottom() const
+{
+    return pEditEngine->pImpEditEngine->IsTopToBottom();
+}
+
 Rectangle ImpEditView::GetVisDocArea() const
 {
     return Rectangle( GetVisDocLeft(), GetVisDocTop(), GetVisDocRight(), GetVisDocBottom() );
@@ -530,8 +535,16 @@ Point ImpEditView::GetDocPos( const Point& rWindowPos ) const
     }
     else
     {
-        aPoint.X() = rWindowPos.Y() - aOutArea.Top() + GetVisDocLeft();
-        aPoint.Y() = aOutArea.Right() - rWindowPos.X() + GetVisDocTop();
+        if (pEditEngine->pImpEditEngine->IsTopToBottom())
+        {
+            aPoint.X() = rWindowPos.Y() - aOutArea.Top() + GetVisDocLeft();
+            aPoint.Y() = aOutArea.Right() - rWindowPos.X() + GetVisDocTop();
+        }
+        else
+        {
+            aPoint.X() = aOutArea.Bottom() - rWindowPos.Y() + GetVisDocLeft();
+            aPoint.Y() = rWindowPos.X() - aOutArea.Left() + GetVisDocTop();
+        }
     }
 
     return aPoint;
@@ -549,8 +562,16 @@ Point ImpEditView::GetWindowPos( const Point& rDocPos ) const
     }
     else
     {
-        aPoint.X() = aOutArea.Right() - rDocPos.Y() + GetVisDocTop();
-        aPoint.Y() = rDocPos.X() + aOutArea.Top() - GetVisDocLeft();
+        if (pEditEngine->pImpEditEngine->IsTopToBottom())
+        {
+            aPoint.X() = aOutArea.Right() - rDocPos.Y() + GetVisDocTop();
+            aPoint.Y() = rDocPos.X() + aOutArea.Top() - GetVisDocLeft();
+        }
+        else
+        {
+            aPoint.X() = aOutArea.Left() + rDocPos.Y() - GetVisDocTop();
+            aPoint.Y() = aOutArea.Bottom() - rDocPos.X() + GetVisDocLeft();
+        }
     }
 
     return aPoint;
@@ -916,8 +937,8 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
 
         if ( nDocDiffX | nDocDiffY )
         {
-            long nDiffX = !IsVertical() ? nDocDiffX : -nDocDiffY;
-            long nDiffY = !IsVertical() ? nDocDiffY : nDocDiffX;
+            long nDiffX = !IsVertical() ? nDocDiffX : (IsTopToBottom() ? -nDocDiffY : nDocDiffY);
+            long nDiffY = !IsVertical() ? nDocDiffY : (IsTopToBottom() ? nDocDiffX : -nDocDiffX);
 
             // Negative: Back to the top or left edge
             if ( ( std::abs( nDiffY ) > pEditEngine->GetOnePixelInRef() ) && DoBigScroll() )
@@ -993,7 +1014,7 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
             aCursorSz.Width() = aOldSz.Height();
             aCursorSz.Height() = aOldSz.Width();
             GetCursor()->SetPos( aCursorRect.TopRight() );
-            GetCursor()->SetOrientation( 2700 );
+            GetCursor()->SetOrientation( IsTopToBottom() ? 2700 : 900 );
         }
         else
             // #i32593# Reset correct orientation in horizontal layout
@@ -1087,8 +1108,16 @@ Pair ImpEditView::Scroll( long ndX, long ndY, ScrollRangeCheck nRangeCheck )
     }
     else
     {
-        aNewVisArea.Top() += ndX;
-        aNewVisArea.Bottom() += ndX;
+        if( IsTopToBottom() )
+        {
+            aNewVisArea.Top() += ndX;
+            aNewVisArea.Bottom() += ndX;
+        }
+        else
+        {
+            aNewVisArea.Top() -= ndX;
+            aNewVisArea.Bottom() -= ndX;
+        }
     }
     if ( ( nRangeCheck == ScrollRangeCheck::PaperWidthTextSize ) && ( aNewVisArea.Bottom() > (long)pEditEngine->pImpEditEngine->GetTextHeight() ) )
     {
@@ -1107,8 +1136,16 @@ Pair ImpEditView::Scroll( long ndX, long ndY, ScrollRangeCheck nRangeCheck )
     }
     else
     {
-        aNewVisArea.Left() -= ndY;
-        aNewVisArea.Right() -= ndY;
+        if (IsTopToBottom())
+        {
+            aNewVisArea.Left() -= ndY;
+            aNewVisArea.Right() -= ndY;
+        }
+        else
+        {
+            aNewVisArea.Left() += ndY;
+            aNewVisArea.Right() += ndY;
+        }
     }
     if ( ( nRangeCheck == ScrollRangeCheck::PaperWidthTextSize ) && ( aNewVisArea.Right() > (long)pEditEngine->pImpEditEngine->CalcTextWidth( false ) ) )
     {
@@ -1119,8 +1156,8 @@ Pair ImpEditView::Scroll( long ndX, long ndY, ScrollRangeCheck nRangeCheck )
         aNewVisArea.Move( -aNewVisArea.Left(), 0 );
 
     // The difference must be alignt on pixel (due to scroll!)
-    long nDiffX = !IsVertical() ? ( GetVisDocLeft() - aNewVisArea.Left() ) : -( GetVisDocTop() - aNewVisArea.Top() );
-    long nDiffY = !IsVertical() ? ( GetVisDocTop() - aNewVisArea.Top() ) : ( GetVisDocLeft() - aNewVisArea.Left() );
+    long nDiffX = !IsVertical() ? ( GetVisDocLeft() - aNewVisArea.Left() ) : (IsTopToBottom() ? -( GetVisDocTop() - aNewVisArea.Top() ) : (GetVisDocTop() - aNewVisArea.Top()));
+    long nDiffY = !IsVertical() ? ( GetVisDocTop() - aNewVisArea.Top() ) : (IsTopToBottom() ? (GetVisDocLeft() - aNewVisArea.Left()) : -(GetVisDocTop() - aNewVisArea.Top()));
 
     Size aDiffs( nDiffX, nDiffY );
     aDiffs = pOutWin->LogicToPixel( aDiffs );
@@ -1139,7 +1176,12 @@ Pair ImpEditView::Scroll( long ndX, long ndY, ScrollRangeCheck nRangeCheck )
         if ( !IsVertical() )
             aVisDocStartPos.Move( -nRealDiffX, -nRealDiffY );
         else
-            aVisDocStartPos.Move( -nRealDiffY, nRealDiffX );
+        {
+            if (IsTopToBottom())
+                aVisDocStartPos.Move(-nRealDiffY, nRealDiffX);
+            else
+                aVisDocStartPos.Move(nRealDiffY, -nRealDiffX);
+        }
         // Das Move um den allignten Wert ergibt nicht unbedingt ein
         // alligntes Rechteck...
         // Aligned value of the move does not necessarily result in aligned
@@ -2117,8 +2159,16 @@ void ImpEditView::dragOver(const css::datatransfer::dnd::DropTargetDragEvent& rD
                     }
                     else
                     {
-                        aEditCursor.Left()--;
-                        aEditCursor.Right()++;
+                        if( IsTopToBottom() )
+                        {
+                            aEditCursor.Left()--;
+                            aEditCursor.Right()++;
+                        }
+                        else
+                        {
+                            aEditCursor.Left()++;
+                            aEditCursor.Right()--;
+                        }
                     }
                     aEditCursor = GetWindow()->PixelToLogic( aEditCursor );
                 }
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index 291a95ad572a..0958617c3bba 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -295,6 +295,7 @@ public:
     const Rectangle&    GetOutputArea() const   { return aOutArea; }
 
     bool            IsVertical() const;
+    bool            IsTopToBottom() const;
 
     bool            PostKeyEvent( const KeyEvent& rKeyEvent, vcl::Window* pFrameWin );
 
@@ -720,8 +721,9 @@ public:
     const Size&             GetPaperSize() const                    { return aPaperSize; }
     void                    SetPaperSize( const Size& rSz )         { aPaperSize = rSz; }
 
-    void                    SetVertical( bool bVertical );
+    void                    SetVertical( bool bVertical, bool bTopToBottom = true);
     bool                    IsVertical() const                      { return GetEditDoc().IsVertical(); }
+    bool                    IsTopToBottom() const                   { return GetEditDoc().IsTopToBottom(); }
 
     bool IsPageOverflow( ) const;
 
diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index cf66a4daaafd..0da41d7af407 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -2580,11 +2580,11 @@ void ImpEditEngine::SetTextRanger( TextRanger* pRanger )
     }
 }
 
-void ImpEditEngine::SetVertical( bool bVertical )
+void ImpEditEngine::SetVertical( bool bVertical, bool bTopToBottom)
 {
-    if ( IsVertical() != bVertical )
+    if ( IsVertical() != bVertical || IsTopToBottom() != (bVertical && bTopToBottom))
     {
-        GetEditDoc().SetVertical( bVertical );
+        GetEditDoc().SetVertical( bVertical, bTopToBottom);
         bool bUseCharAttribs = bool(aStatus.GetControlWord() & EEControlBits::USECHARATTRIBS);
         GetEditDoc().CreateDefFont( bUseCharAttribs );
         if ( IsFormatted() )
@@ -2963,7 +2963,8 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
         sal_Int32 nIndex = 0;
         if ( pPortion->IsVisible() && (
                 ( !IsVertical() && ( ( aStartPos.Y() + nParaHeight ) > aClipRect.Top() ) ) ||
-                ( IsVertical() && ( ( aStartPos.X() - nParaHeight ) < aClipRect.Right() ) ) ) )
+                ( IsVertical() && IsTopToBottom() && ( ( aStartPos.X() - nParaHeight ) < aClipRect.Right() ) ) ||
+                ( IsVertical() && !IsTopToBottom() && ( ( aStartPos.X() + nParaHeight ) > aClipRect.Left() ) ) ) )
 
         {
 
@@ -2977,7 +2978,12 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
             if ( !IsVertical() )
                 aStartPos.Y() += pPortion->GetFirstLineOffset();
             else
-                aStartPos.X() -= pPortion->GetFirstLineOffset();
+            {
+                if( IsTopToBottom() )
+                    aStartPos.X() -= pPortion->GetFirstLineOffset();
+                else
+                    aStartPos.X() += pPortion->GetFirstLineOffset();
+            }
 
             Point aParaStart( aStartPos );
 
@@ -3002,15 +3008,27 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                 }
                 else
                 {
-                    aTmpPos.Y() += pLine->GetStartPosX();
-                    aTmpPos.X() -= pLine->GetMaxAscent();
-                    aStartPos.X() -= pLine->GetHeight();
-                    if (nLine != nLastLine)
-                        aStartPos.X() -= nVertLineSpacing;
+                    if ( IsTopToBottom() )
+                    {
+                        aTmpPos.Y() += pLine->GetStartPosX();
+                        aTmpPos.X() -= pLine->GetMaxAscent();
+                        aStartPos.X() -= pLine->GetHeight();
+                        if (nLine != nLastLine)
+                            aStartPos.X() -= nVertLineSpacing;
+                    }
+                    else
+                    {
+                        aTmpPos.Y() -= pLine->GetStartPosX();
+                        aTmpPos.X() += pLine->GetMaxAscent();
+                        aStartPos.X() += pLine->GetHeight();
+                        if (nLine != nLastLine)
+                            aStartPos.X() += nVertLineSpacing;
+                    }
                 }
 
                 if ( ( !IsVertical() && ( aStartPos.Y() > aClipRect.Top() ) )
-                    || ( IsVertical() && aStartPos.X() < aClipRect.Right() ) )
+                    || ( IsVertical() && IsTopToBottom() && aStartPos.X() < aClipRect.Right() )
+                    || ( IsVertical() && !IsTopToBottom() && aStartPos.X() > aClipRect.Left() ) )
                 {
                     bPaintBullet = false;
 
@@ -3048,9 +3066,18 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                         }
                         else
                         {
-                            aTmpPos.Y() = aStartPos.Y() + nPortionXOffset;
-                            if ( aTmpPos.Y() > aClipRect.Bottom() )
-                                break;  // No further output in line necessary
+                            if( IsTopToBottom() )
+                            {
+                                aTmpPos.Y() = aStartPos.Y() + nPortionXOffset;
+                                if ( aTmpPos.Y() > aClipRect.Bottom() )
+                                    break;  // No further output in line necessary
+                            }
+                            else
+                            {
+                                aTmpPos.Y() = aStartPos.Y() - nPortionXOffset;
+                                if (aTmpPos.Y() < aClipRect.Top())
+                                    break;  // No further output in line necessary
+                            }
                         }
 
                         switch ( rTextPortion.GetKind() )
@@ -3141,8 +3168,16 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                                                 }
                                                 else
                                                 {
-                                                    aTopLeftRectPos.Y() += nAdvanceX;
-                                                    aTopLeftRectPos.X() -= nAdvanceY;
+                                                    if( IsTopToBottom() )
+                                                    {
+                                                        aTopLeftRectPos.Y() -= nAdvanceX;
+                                                        aTopLeftRectPos.X() += nAdvanceY;
+                                                    }
+                                                    else
+                                                    {
+                                                        aTopLeftRectPos.Y() += nAdvanceX;
+                                                        aTopLeftRectPos.X() -= nAdvanceY;
+                                                    }
                                                 }
 
                                                 Point aBottomRightRectPos( aTopLeftRectPos );
@@ -3153,8 +3188,16 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                                                 }
                                                 else
                                                 {
-                                                    aBottomRightRectPos.X() -= pLine->GetHeight();
-                                                    aBottomRightRectPos.Y() += 2 * nHalfBlankWidth;
+                                                    if (IsTopToBottom())
+                                                    {
+                                                        aBottomRightRectPos.X() += pLine->GetHeight();
+                                                        aBottomRightRectPos.Y() -= 2 * nHalfBlankWidth;
+                                                    }
+                                                    else
+                                                    {
+                                                        aBottomRightRectPos.X() -= pLine->GetHeight();
+                                                        aBottomRightRectPos.Y() += 2 * nHalfBlankWidth;
+                                                    }
                                                 }
 
                                                 pOutDev->Push( PushFlags::FILLCOLOR );
@@ -3187,7 +3230,10 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                                                     }
                                                     else
                                                     {
-                                                        aSlashPos.Y() = aTopLeftRectPos.Y() + nAddX;
+                                                        if (IsTopToBottom())
+                                                            aSlashPos.Y() = aTopLeftRectPos.Y() + nAddX;
+                                                        else
+                                                            aSlashPos.Y() = aTopLeftRectPos.Y() - nAddX;
                                                     }
 
                                                     aTmpFont.QuickDrawText( pOutDev, aSlashPos, aSlash, 0, 1 );
@@ -3226,8 +3272,16 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                                             }
                                             else
                                             {
-                                                aTmpPos.X() -= pLine->GetMaxAscent();
-                                                aStartPos.X() -= pLine->GetHeight();
+                                                if (IsTopToBottom())
+                                                {
+                                                    aTmpPos.X() -= pLine->GetMaxAscent();
+                                                    aStartPos.X() -= pLine->GetHeight();
+                                                }
+                                                else
+                                                {
+                                                    aTmpPos.X() += pLine->GetMaxAscent();
+                                                    aStartPos.X() += pLine->GetHeight();
+                                                }
                                             }
                                         }
                                         ::std::vector< sal_Int32 >::iterator curIt = itSubLines;
@@ -3404,7 +3458,12 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                                             if ( !IsVertical() )
                                                 aOutPos.Y() -= nDiff;
                                             else
-                                                aOutPos.X() += nDiff;
+                                            {
+                                                if (IsTopToBottom())
+                                                    aOutPos.X() += nDiff;
+                                                else
+                                                    aOutPos.X() -= nDiff;
+                                            }
                                             aRedLineTmpPos = aOutPos;
                                             aTmpFont.SetEscapement( 0 );
                                         }
@@ -3534,7 +3593,10 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                                                 if( !IsVertical() )
                                                     aRedLineTmpPos.Y() -= nShift;
                                                 else
-                                                    aRedLineTmpPos.X() += nShift;
+                                                    if (IsTopToBottom())
+                                                        aRedLineTmpPos.X() += nShift;
+                                                    else
+                                                        aRedLineTmpPos.X() -= nShift;
                                             }
                                         }
                                         Color aOldColor( pOutDev->GetLineColor() );
@@ -3651,13 +3713,20 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                     if ( !IsVertical() )
                         aStartPos.Y() += nSBL;
                     else
-                        aStartPos.X() -= nSBL;
+                    {
+                        if( IsTopToBottom() )
+                            aStartPos.X() -= nSBL;
+                        else
+                            aStartPos.X() += nSBL;
+                    }
                 }
 
                 // no more visible actions?
                 if ( !IsVertical() && ( aStartPos.Y() >= aClipRect.Bottom() ) )
                     break;
-                else if ( IsVertical() && ( aStartPos.X() <= aClipRect.Left() ) )
+                else if ( IsVertical() && IsTopToBottom() && ( aStartPos.X() <= aClipRect.Left() ) )
+                    break;
+                else if (IsVertical() && !IsTopToBottom() && (aStartPos.X() >= aClipRect.Right()))
                     break;
             }
 
@@ -3668,7 +3737,12 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                 if ( !IsVertical() )
                     aStartPos.Y() += nUL;
                 else
-                    aStartPos.X() -= nUL;
+                {
+                    if (IsTopToBottom())
+                        aStartPos.X() -= nUL;
+                    else
+                        aStartPos.X() += nUL;
+                }
             }
 
             // #108052# Safer way for #i108052# and #i118881#: If for the current ParaPortion
@@ -3697,7 +3771,12 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
             if ( !IsVertical() )
                 aStartPos.Y() += nParaHeight;
             else
-                aStartPos.X() -= nParaHeight;
+            {
+                if (IsTopToBottom())
+                    aStartPos.X() -= nParaHeight;
+                else
+                    aStartPos.X() += nParaHeight;
+            }
         }
 
         if ( pPDFExtOutDevData )
@@ -3706,7 +3785,9 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
         // no more visible actions?
         if ( !IsVertical() && ( aStartPos.Y() > aClipRect.Bottom() ) )
             break;
-        if ( IsVertical() && ( aStartPos.X() < aClipRect.Left() ) )
+        if ( IsVertical() && IsTopToBottom() && ( aStartPos.X() < aClipRect.Left() ) )
+            break;
+        if (IsVertical() && !IsTopToBottom() && ( aStartPos.X() > aClipRect.Right() ) )
             break;
     }
     if ( aStatus.DoRestoreFont() )
@@ -3735,9 +3816,18 @@ void ImpEditEngine::Paint( ImpEditView* pView, const Rectangle& rRect, OutputDev
     }
     else
     {
-        aStartPos = pView->GetOutputArea().TopRight();
-        aStartPos.X() += pView->GetVisDocTop();
-        aStartPos.Y() -= pView->GetVisDocLeft();
+        if( IsTopToBottom() )
+        {
+            aStartPos = pView->GetOutputArea().TopRight();
+            aStartPos.X() += pView->GetVisDocTop();
+            aStartPos.Y() -= pView->GetVisDocLeft();
+        }
+        else
+        {
+            aStartPos = pView->GetOutputArea().BottomLeft();
+            aStartPos.X() -= pView->GetVisDocTop();
+            aStartPos.Y() += pView->GetVisDocLeft();
+        }
     }
 
     // If Doc-width < Output Area,Width and not wrapped fields,
@@ -4029,8 +4119,13 @@ long ImpEditEngine::CalcVertLineSpacing(Point& rStartPos) const
         return 0;
 
     if (IsVertical())
-        // Shift the text to the right for the asian layout mode.
-        rStartPos.X() += nTotalSpace;
+    {
+        if( IsTopToBottom() )
+            // Shift the text to the right for the asian layout mode.
+            rStartPos.X() += nTotalSpace;
+        else
+            rStartPos.X() -= nTotalSpace;
+    }
 
     return nTotalSpace / (nTotalLineCount-1);
 }
diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx
index dde54ad48dc4..7cf098b3c279 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -1026,7 +1026,7 @@ EditTextObject* ImpEditEngine::CreateTextObject(const EditSelection& rSel)
 EditTextObject* ImpEditEngine::CreateTextObject( EditSelection aSel, SfxItemPool* pPool, bool bAllowBigObjects, sal_Int32 nBigObjectStart )
 {
     EditTextObject* pTxtObj = new EditTextObject(pPool);
-    pTxtObj->SetVertical( IsVertical() );
+    pTxtObj->SetVertical( IsVertical(), IsTopToBottom());
     MapUnit eMapUnit = aEditDoc.GetItemPool().GetMetric( DEF_METRIC );
     pTxtObj->mpImpl->SetMetric( (sal_uInt16) eMapUnit );
     if ( pTxtObj->mpImpl->IsOwnerOfPool() )
@@ -1184,7 +1184,7 @@ void ImpEditEngine::SetText( const EditTextObject& rTextObject )
     EnableUndo( false );
 
     InsertText( rTextObject, EditSelection( aPaM, aPaM ) );
-    SetVertical( rTextObject.IsVertical() );
+    SetVertical( rTextObject.IsVertical(), rTextObject.IsTopToBottom());
 
     DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "From where comes the Undo in SetText ?!" );
     SetUpdateMode( _bUpdate );
diff --git a/editeng/source/items/svxitems.src b/editeng/source/items/svxitems.src
index e173867c5cf9..c39eb0dc2306 100644
--- a/editeng/source/items/svxitems.src
+++ b/editeng/source/items/svxitems.src
@@ -943,6 +943,14 @@ String RID_SVXITEMS_CHARROTATE_FITLINE
 {
     Text [ en-US ] = "Fit to line";
 };
+String RID_SVXITEMS_TEXTROTATE_OFF
+{
+    Text [ en-US ] = "Text is not rotated";
+};
+String RID_SVXITEMS_TEXTROTATE
+{
+    Text [ en-US ] = "Text is rotated by $(ARG1)°";
+};
 String RID_SVXITEMS_CHARSCALE
 {
     Text [ en-US ] = "Characters scaled $(ARG1)%";
diff --git a/editeng/source/items/textitem.cxx b/editeng/source/items/textitem.cxx
index 1e01793795cf..2bc2b9d82e02 100644
--- a/editeng/source/items/textitem.cxx
+++ b/editeng/source/items/textitem.cxx
@@ -2878,13 +2878,114 @@ sal_uInt16 SvxTwoLinesItem::GetVersion( sal_uInt16 nFFVer ) const
 
 
 /*************************************************************************
+|*    class SvxTextRotateItem
+*************************************************************************/
+
+SvxTextRotateItem::SvxTextRotateItem(sal_uInt16 nValue, const sal_uInt16 nW)
+    : SfxUInt16Item(nW, nValue)
+{
+}
+
+SfxPoolItem* SvxTextRotateItem::Clone(SfxItemPool*) const
+{
+    return new SvxTextRotateItem(GetValue(), Which());
+}
+
+SfxPoolItem* SvxTextRotateItem::Create(SvStream& rStrm, sal_uInt16) const
+{
+    sal_uInt16 nVal;
+    rStrm.ReadUInt16(nVal);
+    return new SvxTextRotateItem(nVal, Which());
+}
+
+SvStream& SvxTextRotateItem::Store(SvStream & rStrm, sal_uInt16) const
+{
+    rStrm.WriteUInt16(GetValue());
+    return rStrm;
+}
+
+sal_uInt16 SvxTextRotateItem::GetVersion(sal_uInt16 nFFVer) const
+{
+    return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0;
+}
+
+bool SvxTextRotateItem::GetPresentation(
+    SfxItemPresentation /*ePres*/,
+    MapUnit /*eCoreMetric*/, MapUnit /*ePresMetric*/,
+    OUString &rText, const IntlWrapper*) const
+{
+    if (!GetValue())
+        rText = EE_RESSTR(RID_SVXITEMS_TEXTROTATE_OFF);
+    else
+    {
+        rText = EE_RESSTR(RID_SVXITEMS_TEXTROTATE);
+        rText = rText.replaceFirst("$(ARG1)",
+            OUString::number(GetValue() / 10));
+    }
+    return true;
+}
+
+bool SvxTextRotateItem::QueryValue(css::uno::Any& rVal,
+    sal_uInt8 nMemberId) const
+{
+    nMemberId &= ~CONVERT_TWIPS;
+    bool bRet = true;
+    switch (nMemberId)
+    {
+    case MID_ROTATE:
+        rVal <<= (sal_Int16)GetValue();
+        break;
+    default:
+        bRet = false;
+        break;
+    }
+    return bRet;
+}
+
+bool SvxTextRotateItem::PutValue(const css::uno::Any& rVal, sal_uInt8 nMemberId)
+{
+    nMemberId &= ~CONVERT_TWIPS;
+    bool bRet = true;
+    switch (nMemberId)
+    {
+    case MID_ROTATE:
+    {
+        sal_Int16 nVal = 0;
+        if ((rVal >>= nVal) && (0 == nVal || 900 == nVal || 2700 == nVal))
+            SetValue((sal_uInt16)nVal);
+        else
+            bRet = false;
+        break;
+    }
+    default:
+        bRet = false;
+    }
+    return bRet;
+}
+
+bool SvxTextRotateItem::operator==(const SfxPoolItem& rItem) const
+{
+    assert(SfxPoolItem::operator==(rItem));
+    return SfxUInt16Item::operator==(rItem);
+}
+
+void SvxTextRotateItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+    xmlTextWriterStartElement(pWriter, BAD_CAST("SvxTextRotateItem"));
+    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), BAD_CAST(OString::number(Which()).getStr()));
+    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"), BAD_CAST(OString::number(GetValue()).getStr()));
+    xmlTextWriterEndElement(pWriter);
+}
+
+
+/*************************************************************************
 |*    class SvxCharRotateItem
 *************************************************************************/
 
 SvxCharRotateItem::SvxCharRotateItem( sal_uInt16 nValue,
                                        bool bFitIntoLine,
                                        const sal_uInt16 nW )
-    : SfxUInt16Item( nW, nValue ), bFitToLine( bFitIntoLine )
+    : SvxTextRotateItem(nValue, nW), bFitToLine( bFitIntoLine )
 {
 }
 
@@ -2934,12 +3035,11 @@ bool SvxCharRotateItem::GetPresentation(
 bool SvxCharRotateItem::QueryValue( css::uno::Any& rVal,
                                 sal_uInt8 nMemberId ) const
 {
-    nMemberId &= ~CONVERT_TWIPS;
     bool bRet = true;
-    switch( nMemberId )
+    switch(nMemberId & ~CONVERT_TWIPS)
     {
     case MID_ROTATE:
-        rVal <<= (sal_Int16)GetValue();
+        SvxTextRotateItem::QueryValue(rVal, nMemberId);
         break;
     case MID_FITTOLINE:
         rVal = css::uno::makeAny<bool>( IsFitToLine() );
@@ -2954,17 +3054,12 @@ bool SvxCharRotateItem::QueryValue( css::uno::Any& rVal,
 bool SvxCharRotateItem::PutValue( const css::uno::Any& rVal,
                                     sal_uInt8 nMemberId )
 {
-    nMemberId &= ~CONVERT_TWIPS;
     bool bRet = true;
-    switch( nMemberId )
+    switch(nMemberId & ~CONVERT_TWIPS)
     {
     case MID_ROTATE:
         {
-            sal_Int16 nVal = 0;
-            if((rVal >>= nVal) && (0 == nVal || 900 == nVal || 2700 == nVal))
-                SetValue( (sal_uInt16)nVal );
-            else
-                bRet = false;
+            bRet = SvxTextRotateItem::PutValue(rVal, nMemberId);
             break;
         }
 
@@ -2980,7 +3075,7 @@ bool SvxCharRotateItem::PutValue( const css::uno::Any& rVal,
 bool SvxCharRotateItem::operator==( const SfxPoolItem& rItem ) const
 {
     assert(SfxPoolItem::operator==(rItem));
-    return SfxUInt16Item::operator==( rItem ) &&
+    return SvxTextRotateItem::operator==( rItem ) &&
            IsFitToLine() == static_cast<const SvxCharRotateItem&>(rItem).IsFitToLine();
 }
 
diff --git a/editeng/source/outliner/outlin2.cxx b/editeng/source/outliner/outlin2.cxx
index 3248ba34f51e..c89a89fdaffb 100644
--- a/editeng/source/outliner/outlin2.cxx
+++ b/editeng/source/outliner/outlin2.cxx
@@ -526,9 +526,9 @@ const EditEngine& Outliner::GetEditEngine() const
     return *pEditEngine;
 }
 
-void Outliner::SetVertical( bool b )
+void Outliner::SetVertical( bool bVertical, bool bTopToBottom)
 {
-    pEditEngine->SetVertical( b );
+    pEditEngine->SetVertical(bVertical, bTopToBottom);
 }
 
 bool Outliner::IsVertical() const
@@ -536,6 +536,11 @@ bool Outliner::IsVertical() const
     return pEditEngine->IsVertical();
 }
 
+bool Outliner::IsTopToBottom() const
+{
+    return pEditEngine->IsTopToBottom();
+}
+
 void Outliner::SetFixedCellHeight( bool bUseFixedCellHeight )
 {
     pEditEngine->SetFixedCellHeight( bUseFixedCellHeight );
diff --git a/editeng/source/outliner/outliner.cxx b/editeng/source/outliner/outliner.cxx
index a77e88199fa4..9943efdb0d26 100644
--- a/editeng/source/outliner/outliner.cxx
+++ b/editeng/source/outliner/outliner.cxx
@@ -861,7 +861,7 @@ vcl::Font Outliner::ImpCalcBulletFont( sal_Int32 nPara ) const
     aBulletFont.SetFontSize( Size( 0, nScaledLineHeight ) );
     bool bVertical = IsVertical();
     aBulletFont.SetVertical( bVertical );
-    aBulletFont.SetOrientation( bVertical ? 2700 : 0 );
+    aBulletFont.SetOrientation( bVertical ? (IsTopToBottom() ? 2700 : 900) : 0 );
 
     Color aColor( COL_AUTO );
     if( !pEditEngine->IsFlatMode() && !( pEditEngine->GetControlWord() & EEControlBits::NOCOLORS ) )
@@ -890,6 +890,7 @@ void Outliner::PaintBullet( sal_Int32 nPara, const Point& rStartPos,
     if (bDrawBullet && ImplHasNumberFormat(nPara))
     {
         bool bVertical = IsVertical();
+        bool bTopToBottom = IsTopToBottom();
 
         bool bRightToLeftPara = pEditEngine->IsRightToLeft( nPara );
 
@@ -927,9 +928,17 @@ void Outliner::PaintBullet( sal_Int32 nPara, const Point& rStartPos,
                 }
                 else
                 {
-//                  aTextPos.X() = rStartPos.X() - aBulletArea.Bottom();
-                    aTextPos.X() = rStartPos.X() - ( bSymbol ? aBulletArea.Bottom() : aParaInfos.nFirstLineMaxAscent );
-                    aTextPos.Y() = rStartPos.Y() + aBulletArea.Left();
+                    if (bTopToBottom)
+                    {
+//                      aTextPos.X() = rStartPos.X() - aBulletArea.Bottom();
+                        aTextPos.X() = rStartPos.X() - (bSymbol ? aBulletArea.Bottom() : aParaInfos.nFirstLineMaxAscent);
+                        aTextPos.Y() = rStartPos.Y() + aBulletArea.Left();
+                    }
+                    else
+                    {
+                        aTextPos.X() = rStartPos.X() + (bSymbol ? aBulletArea.Bottom() : aParaInfos.nFirstLineMaxAscent);
+                        aTextPos.Y() = rStartPos.Y() + aBulletArea.Left();
+                    }
                 }
 
                 if ( nOrientation )
@@ -998,8 +1007,16 @@ void Outliner::PaintBullet( sal_Int32 nPara, const Point& rStartPos,
                     }
                     else
                     {
-                        aBulletPos.X() = rStartPos.X() - aBulletArea.Bottom();
-                        aBulletPos.Y() = rStartPos.Y() + aBulletArea.Left();
+                        if (bTopToBottom)
+                        {
+                            aBulletPos.X() = rStartPos.X() - aBulletArea.Bottom();
+                            aBulletPos.Y() = rStartPos.Y() + aBulletArea.Left();
+                        }
+                        else
+                        {
+                            aBulletPos.X() = rStartPos.X() + aBulletArea.Top();
+                            aBulletPos.Y() = rStartPos.Y() - aBulletArea.Right();
+                        }
                     }
 
                     if(bStrippingPortions)
diff --git a/editeng/source/outliner/outlobj.cxx b/editeng/source/outliner/outlobj.cxx
index 3eba88e27435..a993b8200c3e 100644
--- a/editeng/source/outliner/outlobj.cxx
+++ b/editeng/source/outliner/outlobj.cxx
@@ -131,12 +131,18 @@ bool OutlinerParaObject::IsVertical() const
     return mpImpl->mpEditTextObject->IsVertical();
 }
 
-void OutlinerParaObject::SetVertical(bool bNew)
+bool OutlinerParaObject::IsTopToBottom() const
+{
+    return mpImpl->mpEditTextObject->IsTopToBottom();
+}
+
+void OutlinerParaObject::SetVertical(bool bNew, bool bTopToBottom)
 {
     const ::o3tl::cow_wrapper< OutlinerParaObjData >* pImpl = &mpImpl;
-    if ( ( *pImpl )->mpEditTextObject->IsVertical() != bNew )
+    if ( ( *pImpl )->mpEditTextObject->IsVertical() != bNew ||
+        (*pImpl)->mpEditTextObject->IsTopToBottom() != (bNew && bTopToBottom))
     {
-        mpImpl->mpEditTextObject->SetVertical(bNew);
+        mpImpl->mpEditTextObject->SetVertical(bNew, bTopToBottom);
     }
 }
 
diff --git a/include/editeng/charrotateitem.hxx b/include/editeng/charrotateitem.hxx
index 2ab87f22aaa5..32a84a5613d9 100644
--- a/include/editeng/charrotateitem.hxx
+++ b/include/editeng/charrotateitem.hxx
@@ -22,6 +22,55 @@
 #include <svl/intitem.hxx>
 #include <editeng/editengdllapi.h>
 
+ // class SvxTextRotateItem ----------------------------------------------
+
+ /* [Description]
+
+ This item defines a text rotation value. Currently
+ text can only be rotated 90,0 and 270,0 degrees.
+
+ */
+
+class EDITENG_DLLPUBLIC SvxTextRotateItem : public SfxUInt16Item
+{
+public:
+    static SfxPoolItem* CreateDefault();
+
+    SvxTextRotateItem(sal_uInt16 nValue, const sal_uInt16 nId);
+
+    virtual SfxPoolItem*    Clone(SfxItemPool *pPool = nullptr) const override;
+    virtual SfxPoolItem*    Create(SvStream &, sal_uInt16) const override;
+    virtual SvStream&       Store(SvStream & rStrm, sal_uInt16 nIVer) const override;
+    virtual sal_uInt16      GetVersion(sal_uInt16 nFileVersion) const override;
+
+    virtual bool GetPresentation(SfxItemPresentation ePres,
+        MapUnit eCoreMetric,
+        MapUnit ePresMetric,
+        OUString &rText,
+        const IntlWrapper * = nullptr) const override;
+
+    virtual bool            QueryValue(css::uno::Any& rVal, sal_uInt8 nMemberId = 0) const override;
+    virtual bool            PutValue(const css::uno::Any& rVal, sal_uInt8 nMemberId) override;
+
+    SvxTextRotateItem& operator=(const SvxTextRotateItem& rItem)
+    {
+        SetValue(rItem.GetValue());
+        return *this;
+    }
+
+    virtual bool operator==(const SfxPoolItem&) const override;
+
+    // our currently only degree values
+    void SetTopToBottom() { SetValue(2700); }
+    void SetBottomToTop() { SetValue(900); }
+    bool IsTopToBottom() const { return 2700 == GetValue(); }
+    bool IsBottomToTop() const { return  900 == GetValue(); }
+    bool IsVertical() const     { return IsTopToBottom() || IsBottomToTop(); }
+
+    void dumpAsXml(struct _xmlTextWriter* pWriter) const override;
+};
+
+
 // class SvxCharRotateItem ----------------------------------------------
 
 /* [Description]
@@ -33,7 +82,7 @@
 
 */
 
-class EDITENG_DLLPUBLIC SvxCharRotateItem : public SfxUInt16Item
+class EDITENG_DLLPUBLIC SvxCharRotateItem : public SvxTextRotateItem
 {
     bool bFitToLine;
 public:
@@ -66,12 +115,6 @@ public:
 
     virtual bool             operator==( const SfxPoolItem& ) const override;
 
-    // our currently only degree values
-    void SetTopToBotton()                   { SetValue( 2700 ); }
-    void SetBottomToTop()                   { SetValue(  900 ); }
-    bool IsTopToBotton() const              { return 2700 == GetValue(); }
-    bool IsBottomToTop() const              { return  900 == GetValue(); }
-
     bool IsFitToLine() const                { return bFitToLine; }
     void SetFitToLine( bool b )             { bFitToLine = b; }
 
diff --git a/include/editeng/editeng.hxx b/include/editeng/editeng.hxx
index d8be7c663eed..4d771074214c 100644
--- a/include/editeng/editeng.hxx
+++ b/include/editeng/editeng.hxx
@@ -237,8 +237,9 @@ public:
     void            SetPaperSize( const Size& rSize );
     const Size&     GetPaperSize() const;
 
-    void            SetVertical( bool bVertical );
+    void            SetVertical( bool bVertical, bool bTopToBottom = true );
     bool            IsVertical() const;
+    bool            IsTopToBottom() const;
 
     void            SetFixedCellHeight( bool bUseFixedCellHeight );
 
diff --git a/include/editeng/editobj.hxx b/include/editeng/editobj.hxx
index da35f32d03fe..aba1c86d7b21 100644
--- a/include/editeng/editobj.hxx
+++ b/include/editeng/editobj.hxx
@@ -87,7 +87,8 @@ public:
     void SetUserType( OutlinerMode n );
 
     bool IsVertical() const;
-    void SetVertical( bool bVertical );
+    bool IsTopToBottom() const;
+    void SetVertical( bool bVertical, bool bTopToBottom = true);
 
     SvtScriptType GetScriptType() const;
 
diff --git a/include/editeng/editrids.hrc b/include/editeng/editrids.hrc
index cff44d40c234..522d85807bdd 100644
--- a/include/editeng/editrids.hrc
+++ b/include/editeng/editrids.hrc
@@ -113,6 +113,8 @@
 #define RID_SVXITEMS_CHARROTATE_OFF         (RID_EDIT_START + 81)
 #define RID_SVXITEMS_CHARROTATE             (RID_EDIT_START + 82)
 #define RID_SVXITEMS_CHARROTATE_FITLINE     (RID_EDIT_START + 83)
+#define RID_SVXITEMS_TEXTROTATE_OFF         (RID_EDIT_START + 84)
+#define RID_SVXITEMS_TEXTROTATE             (RID_EDIT_START + 116)
 
 #define RID_SVXITEMS_RELIEF_BEGIN           (RID_EDIT_START + 85)
 #define RID_SVXITEMS_RELIEF_NONE            (RID_EDIT_START + 85)
diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx
index dad3d11ce110..ae04cd0ccb40 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -686,8 +686,9 @@ public:
     void            Init( OutlinerMode nOutlinerMode );
     OutlinerMode    GetMode() const { return nOutlinerMode; }
 
-    void            SetVertical( bool bVertical );
+    void            SetVertical( bool bVertical, bool bTopToBottom = true);
     bool            IsVertical() const;
+    bool            IsTopToBottom() const;
 
     void            SetFixedCellHeight( bool bUseFixedCellHeight );
 
diff --git a/include/editeng/outlobj.hxx b/include/editeng/outlobj.hxx
index 6bde289e7f73..b34cf008dc73 100644
--- a/include/editeng/outlobj.hxx
+++ b/include/editeng/outlobj.hxx
@@ -80,7 +80,8 @@ public:
 
     // vertical access
     bool IsVertical() const;
-    void SetVertical(bool bNew);
+    bool IsTopToBottom() const;
+    void SetVertical(bool bNew, bool bTopToBottom = true);
 
     // data read access
     sal_Int32 Count() const;
diff --git a/include/svx/svddef.hxx b/include/svx/svddef.hxx
index 0f93472cd81f..0d889fe88cf7 100644
--- a/include/svx/svddef.hxx
+++ b/include/svx/svddef.hxx
@@ -296,8 +296,9 @@
 #define SDRATTR_TABLE_BORDER_INNER              (SDRATTR_TABLE_FIRST+1)
 #define SDRATTR_TABLE_BORDER_TLBR               (SDRATTR_TABLE_FIRST+2)
 #define SDRATTR_TABLE_BORDER_BLTR               (SDRATTR_TABLE_FIRST+3)
+#define SDRATTR_TABLE_TEXT_ROTATION             (SDRATTR_TABLE_FIRST+4)
 
-#define SDRATTR_TABLE_LAST                      (SDRATTR_TABLE_BORDER_BLTR)
+#define SDRATTR_TABLE_LAST                      (SDRATTR_TABLE_TEXT_ROTATION)
 
 #define SDRATTR_END                             SDRATTR_TABLE_LAST      /* 1357 */ /* 1333 V4+++*/ /* 1243 V4+++*/  /*1213*/ /*1085*/ /*1040*/ /*Pool V2: 1123,V1: 1065 */
 
diff --git a/oox/source/drawingml/table/tablecell.cxx b/oox/source/drawingml/table/tablecell.cxx
index 1c0d08616599..ebc2ed731d5b 100644
--- a/oox/source/drawingml/table/tablecell.cxx
+++ b/oox/source/drawingml/table/tablecell.cxx
@@ -467,6 +467,11 @@ void TableCell::pushToXCell( const ::oox::core::XmlFilterBase& rFilterBase, cons
     }
 
     getTextBody()->insertAt( rFilterBase, xText, xAt, aTextStyleProps, pMasterTextListStyle );
+
+    if (getVertToken() == XML_vert)
+        xPropSet->setPropertyValue("RotateAngle", Any(short(27000)));
+    else if (getVertToken() == XML_vert270)
+        xPropSet->setPropertyValue("RotateAngle", Any(short(9000)));
 }
 
 } } }
diff --git a/sd/qa/unit/data/pptx/tdf100926.pptx b/sd/qa/unit/data/pptx/tdf100926.pptx
new file mode 100755
index 000000000000..71627394ec84
Binary files /dev/null and b/sd/qa/unit/data/pptx/tdf100926.pptx differ
diff --git a/sd/qa/unit/data/pptx/tdf100926_ODP.pptx b/sd/qa/unit/data/pptx/tdf100926_ODP.pptx
new file mode 100755
index 000000000000..71627394ec84
Binary files /dev/null and b/sd/qa/unit/data/pptx/tdf100926_ODP.pptx differ
diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx
index 797bf36d6192..df0da159aacf 100644
--- a/sd/qa/unit/export-tests.cxx
+++ b/sd/qa/unit/export-tests.cxx
@@ -92,6 +92,7 @@ public:
     void testTdf62176();
     void testTransparentBackground();
     void testEmbeddedPdf();
+    void testTdf100926();
 
     CPPUNIT_TEST_SUITE(SdExportTest);
 
@@ -106,6 +107,7 @@ public:
     CPPUNIT_TEST(testTdf62176);
     CPPUNIT_TEST(testTransparentBackground);
     CPPUNIT_TEST(testEmbeddedPdf);
+    CPPUNIT_TEST(testTdf100926);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -552,6 +554,35 @@ void SdExportTest::testEmbeddedPdf()
 #endif
 }
 
+void SdExportTest::testTdf100926()
+{
+    sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/pptx/tdf100926_ODP.pptx"), PPTX);
+
+    xDocShRef = saveAndReload(xDocShRef.get(), ODP);
+
+    const SdrPage* pPage = GetPage(1, xDocShRef);
+    CPPUNIT_ASSERT(pPage != nullptr);
+
+    sdr::table::SdrTableObj *pTableObj = dynamic_cast<sdr::table::SdrTableObj*>(pPage->GetObj(0));
+    CPPUNIT_ASSERT(pTableObj != nullptr);
+    uno::Reference< table::XCellRange > xTable(pTableObj->getTable(), uno::UNO_QUERY_THROW);
+
+    sal_Int32 nRotation = 0;
+    uno::Reference< beans::XPropertySet > xCell(xTable->getCellByPosition(0, 0), uno::UNO_QUERY_THROW);
+    xCell->getPropertyValue("RotateAngle") >>= nRotation;
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(27000), nRotation);
+
+    xCell.set(xTable->getCellByPosition(1, 0), uno::UNO_QUERY_THROW);
+    xCell->getPropertyValue("RotateAngle") >>= nRotation;
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(9000), nRotation);
+
+    xCell.set(xTable->getCellByPosition(2, 0), uno::UNO_QUERY_THROW);
+    xCell->getPropertyValue("RotateAngle") >>= nRotation;
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nRotation);
+
+    xDocShRef->DoClose();
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SdExportTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index df0e639c7265..27d15c0ec22b 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -142,6 +142,7 @@ public:
     void testTdf104015();
     void testTdf104201();
     void testTdf104445();
+    void testTdf100926();
 
     bool checkPattern(sd::DrawDocShellRef& rDocRef, int nShapeNumber, std::vector<sal_uInt8>& rExpected);
     void testPatternImport();
@@ -205,6 +206,7 @@ public:
     CPPUNIT_TEST(testTdf104201);
     CPPUNIT_TEST(testTdf104445);
     CPPUNIT_TEST(testPatternImport);
+    CPPUNIT_TEST(testTdf100926);
 
     CPPUNIT_TEST_SUITE_END();
 };
@@ -2109,6 +2111,32 @@ void SdImportTest::testPatternImport()
     xDocRef->DoClose();
 }
 
+void SdImportTest::testTdf100926()
+{
+    sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/pptx/tdf100926.pptx"), PPTX);
+    const SdrPage* pPage = GetPage(1, xDocShRef);
+    CPPUNIT_ASSERT(pPage != nullptr);
+
+    sdr::table::SdrTableObj *pTableObj = dynamic_cast<sdr::table::SdrTableObj*>(pPage->GetObj(0));
+    CPPUNIT_ASSERT(pTableObj != nullptr);
+    uno::Reference< table::XCellRange > xTable(pTableObj->getTable(), uno::UNO_QUERY_THROW);
+
+    sal_Int32 nRotation = 0;
+    uno::Reference< beans::XPropertySet > xCell(xTable->getCellByPosition(0, 0), uno::UNO_QUERY_THROW);
+    xCell->getPropertyValue("RotateAngle") >>= nRotation;
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(27000), nRotation);
+
+    xCell.set(xTable->getCellByPosition(1, 0), uno::UNO_QUERY_THROW);
+    xCell->getPropertyValue("RotateAngle") >>= nRotation;
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(9000), nRotation);
+
+    xCell.set(xTable->getCellByPosition(2, 0), uno::UNO_QUERY_THROW);
+    xCell->getPropertyValue("RotateAngle") >>= nRotation;
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nRotation);
+
+    xDocShRef->DoClose();
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/source/ui/func/futext.cxx b/sd/source/ui/func/futext.cxx
index 37fb65c97943..cb9bdc3c8120 100644
--- a/sd/source/ui/func/futext.cxx
+++ b/sd/source/ui/func/futext.cxx
@@ -1055,7 +1055,9 @@ void FuText::SetInEditMode(const MouseEvent& rMEvt, bool bQuickDrag)
                 if( pTextObj )
                 {
                     OutlinerParaObject* pOPO = pTextObj->GetOutlinerParaObject();
-                    if( ( pOPO && pOPO->IsVertical() ) || (nSlotId == SID_ATTR_CHAR_VERTICAL) || (nSlotId == SID_TEXT_FITTOSIZE_VERTICAL) )
+                    if( pOPO && pOPO->IsVertical() )
+                        pOutl->SetVertical( true, pOPO->IsTopToBottom());
+                    else if (nSlotId == SID_ATTR_CHAR_VERTICAL || nSlotId == SID_TEXT_FITTOSIZE_VERTICAL)
                         pOutl->SetVertical( true );
 
                     if( pTextObj->getTextCount() > 1 )
diff --git a/svx/source/svdraw/svdattr.cxx b/svx/source/svdraw/svdattr.cxx
index 196a344b6111..c3519a3fcbe0 100644
--- a/svx/source/svdraw/svdattr.cxx
+++ b/svx/source/svdraw/svdattr.cxx
@@ -38,6 +38,7 @@
 #include <editeng/adjustitem.hxx>
 #include <editeng/editdata.hxx>
 #include <editeng/writingmodeitem.hxx>
+#include <editeng/charrotateitem.hxx>
 #include <i18nutil/unicode.hxx>
 #include <svl/solar.hrc>
 #include <tools/bigint.hxx>
@@ -319,6 +320,7 @@ SdrItemPool::SdrItemPool(
     mppLocalPoolDefaults[ SDRATTR_TABLE_BORDER_INNER - SDRATTR_START ] =  pBoxInfoItem;
     mppLocalPoolDefaults[ SDRATTR_TABLE_BORDER_TLBR - SDRATTR_START ] = new SvxLineItem( SDRATTR_TABLE_BORDER_TLBR );
     mppLocalPoolDefaults[ SDRATTR_TABLE_BORDER_BLTR - SDRATTR_START ] = new SvxLineItem( SDRATTR_TABLE_BORDER_BLTR );
+    mppLocalPoolDefaults[SDRATTR_TABLE_TEXT_ROTATION - SDRATTR_START] = new SvxTextRotateItem(0, SDRATTR_TABLE_TEXT_ROTATION);
 
     // set own ItemInfos
     mpLocalItemInfos[SDRATTR_SHADOW-SDRATTR_START]._nSID=SID_ATTR_FILL_SHADOW;
diff --git a/svx/source/svdraw/svdotext.cxx b/svx/source/svdraw/svdotext.cxx
index f052d6964c1a..6824c46bad95 100644
--- a/svx/source/svdraw/svdotext.cxx
+++ b/svx/source/svdraw/svdotext.cxx
@@ -1384,7 +1384,7 @@ void SdrTextObj::NbcSetOutlinerParaObjectForText( OutlinerParaObject* pTextObjec
 
     if (pText && pText->GetOutlinerParaObject())
     {
-        SvxWritingModeItem aWritingMode(pText->GetOutlinerParaObject()->IsVertical()
+        SvxWritingModeItem aWritingMode(pText->GetOutlinerParaObject()->IsVertical() && pText->GetOutlinerParaObject()->IsTopToBottom()
             ? css::text::WritingMode_TB_RL
             : css::text::WritingMode_LR_TB,
             SDRATTR_TEXTDIRECTION);
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx
index c567477a0f1a..e97b77cf50a0 100644
--- a/svx/source/svdraw/svdotextdecomposition.cxx
+++ b/svx/source/svdraw/svdotextdecomposition.cxx
@@ -759,6 +759,7 @@ void SdrTextObj::impDecomposeAutoFitTextPrimitive(
     const OutlinerParaObject* pOutlinerParaObject = rSdrAutofitTextPrimitive.getSdrText()->GetOutlinerParaObject();
     OSL_ENSURE(pOutlinerParaObject, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
     const bool bVerticalWriting(pOutlinerParaObject->IsVertical());
+    const bool bTopToBottom(pOutlinerParaObject->IsTopToBottom());
     const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
 
     if((rSdrAutofitTextPrimitive.getWordWrap() || IsTextFrame()))
@@ -829,8 +830,9 @@ void SdrTextObj::impDecomposeAutoFitTextPrimitive(
     // translate relative to given primitive to get same rotation and shear
     // as the master shape we are working on. For vertical, use the top-right
     // corner
-    const double fStartInX(bVerticalWriting ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
-    aNewTransformA.translate(fStartInX, aAdjustTranslate.getY());
+    const double fStartInX(bVerticalWriting && bTopToBottom ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
+    const double fStartInY(bVerticalWriting && !bTopToBottom ? aAdjustTranslate.getY() + aOutlinerScale.getY() : aAdjustTranslate.getY());
+    aNewTransformA.translate(fStartInX, fStartInY);
 
     // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
     // move the null point which was top left to bottom right.
@@ -922,6 +924,7 @@ void SdrTextObj::impDecomposeBlockTextPrimitive(
     const sal_uInt32 nAnchorTextWidth(FRound(aAnchorTextRange.getWidth() + 1L));
     const sal_uInt32 nAnchorTextHeight(FRound(aAnchorTextRange.getHeight() + 1L));
     const bool bVerticalWriting(rSdrBlockTextPrimitive.getOutlinerParaObject().IsVertical());
+    const bool bTopToBottom(rSdrBlockTextPrimitive.getOutlinerParaObject().IsTopToBottom());
     const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
 
     if(bIsCell)
@@ -1082,8 +1085,9 @@ void SdrTextObj::impDecomposeBlockTextPrimitive(
     // Translate relative to given primitive to get same rotation and shear
     // as the master shape we are working on. For vertical, use the top-right
     // corner
-    const double fStartInX(bVerticalWriting ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
-    const basegfx::B2DTuple aAdjOffset(fStartInX, aAdjustTranslate.getY());
+    const double fStartInX(bVerticalWriting && bTopToBottom ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
+    const double fStartInY(bVerticalWriting && !bTopToBottom ? aAdjustTranslate.getY() + aOutlinerScale.getY() : aAdjustTranslate.getY());
+    const basegfx::B2DTuple aAdjOffset(fStartInX, fStartInY);
     basegfx::B2DHomMatrix aNewTransformA(basegfx::tools::createTranslateB2DHomMatrix(aAdjOffset.getX(), aAdjOffset.getY()));
 
     // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
@@ -1162,10 +1166,14 @@ void SdrTextObj::impDecomposeStretchTextPrimitive(
     // needs to translate the text initially around object width to orient
     // it relative to the topper right instead of the topper left
     const bool bVertical(rSdrStretchTextPrimitive.getOutlinerParaObject().IsVertical());
+    const bool bTopToBottom(rSdrStretchTextPrimitive.getOutlinerParaObject().IsTopToBottom());
 
     if(bVertical)
     {
-        aNewTransformA.translate(aScale.getX(), 0.0);
+        if(bTopToBottom)
+            aNewTransformA.translate(aScale.getX(), 0.0);
+        else
+            aNewTransformA.translate(0.0, aScale.getY());
     }
 
     // calculate global char stretching scale parameters. Use non-mirrored sizes
@@ -1517,6 +1525,7 @@ void SdrTextObj::impDecomposeChainedTextPrimitive(
     OSL_ENSURE(pOutlinerParaObject, "impDecomposeBlockTextPrimitive used with no OutlinerParaObject (!)");
 
     const bool bVerticalWriting(pOutlinerParaObject->IsVertical());
+    const bool bTopToBottom(pOutlinerParaObject->IsTopToBottom());
     const Size aAnchorTextSize(Size(nAnchorTextWidth, nAnchorTextHeight));
 
     if(IsTextFrame())
@@ -1593,8 +1602,9 @@ void SdrTextObj::impDecomposeChainedTextPrimitive(
     // translate relative to given primitive to get same rotation and shear
     // as the master shape we are working on. For vertical, use the top-right
     // corner
-    const double fStartInX(bVerticalWriting ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
-    aNewTransformA.translate(fStartInX, aAdjustTranslate.getY());
+    const double fStartInX(bVerticalWriting && bTopToBottom ? aAdjustTranslate.getX() + aOutlinerScale.getX() : aAdjustTranslate.getX());
+    const double fStartInY(bVerticalWriting && !bTopToBottom ? aAdjustTranslate.getY() + aOutlinerScale.getY() : aAdjustTranslate.getY());
+    aNewTransformA.translate(fStartInX, fStartInY);
 
     // mirroring. We are now in aAnchorTextRange sizes. When mirroring in X and Y,
     // move the null point which was top left to bottom right.
diff --git a/svx/source/table/cell.cxx b/svx/source/table/cell.cxx
index 5eaa3f99b5b9..3f484d378245 100644
--- a/svx/source/table/cell.cxx
+++ b/svx/source/table/cell.cxx
@@ -51,6 +51,7 @@
 #include "svx/unoshape.hxx"
 #include "editeng/editobj.hxx"
 #include "editeng/boxitem.hxx"
+#include <editeng/charrotateitem.hxx>
 #include "svx/xflbstit.hxx"
 #include "svx/xflbmtit.hxx"
 #include <svx/svdpool.hxx>
@@ -89,6 +90,7 @@ static const SvxItemPropertySet* ImplGetSvxCellPropertySet()
         { OUString("BottomBorder"),                 SDRATTR_TABLE_BORDER,           cppu::UnoType<BorderLine>::get(), 0, BOTTOM_BORDER }, \
         { OUString("LeftBorder"),                   SDRATTR_TABLE_BORDER,           cppu::UnoType<BorderLine>::get(), 0, LEFT_BORDER }, \
         { OUString("RightBorder"),                  SDRATTR_TABLE_BORDER,           cppu::UnoType<BorderLine>::get(), 0, RIGHT_BORDER }, \
+        { OUString("RotateAngle"),                  SDRATTR_TABLE_TEXT_ROTATION,    cppu::UnoType<sal_Int32>::get(), 0, 0 }, \
 
         SVX_UNOEDIT_OUTLINER_PROPERTIES,
         SVX_UNOEDIT_CHAR_PROPERTIES,
@@ -291,7 +293,6 @@ namespace sdr
 
                         OutlinerParaObject* pTemp = pOutliner->CreateParaObject(0, nParaCount);
                         pOutliner->Clear();
-
                         mxCell->SetOutlinerParaObject(pTemp);
                     }
 
@@ -314,8 +315,7 @@ namespace sdr
                 bool bVertical(css::text::WritingMode_TB_RL == static_cast<const SvxWritingModeItem*>(pNewItem)->GetValue());
 
                 sdr::table::SdrTableObj& rObj = static_cast<sdr::table::SdrTableObj&>(GetSdrObject());
-                if( rObj.IsVerticalWriting() != bVertical )
-                    rObj.SetVerticalWriting(bVertical);
+                rObj.SetVerticalWriting(bVertical);
 
                 // Set a cell vertical property
                 OutlinerParaObject* pParaObj = mxCell->GetEditOutlinerParaObject();
@@ -334,6 +334,50 @@ namespace sdr
                 }
             }
 
+            if (pNewItem && (SDRATTR_TABLE_TEXT_ROTATION == nWhich))
+            {
+                const SvxTextRotateItem* pRotateItem = static_cast<const SvxTextRotateItem*>(pNewItem);
+
+                // Set a cell vertical property
+                OutlinerParaObject* pParaObj = mxCell->GetEditOutlinerParaObject();
+
+                const bool bOwnParaObj = pParaObj != nullptr;
+
+                if (pParaObj == nullptr)
+                    pParaObj = mxCell->GetOutlinerParaObject();
+
+                if (pParaObj)
+                {
+                    pParaObj->SetVertical(pRotateItem->IsVertical(), pRotateItem->IsTopToBottom());
+
+                    if (bOwnParaObj)
+                        delete pParaObj;
+                }
+
+               // Change autogrow direction
+                SdrTextObj& rObj = static_cast<SdrTextObj&>(GetSdrObject());
+
+                // rescue object size
+                Rectangle aObjectRect = rObj.GetSnapRect();
+
+                const SfxItemSet& rSet = rObj.GetObjectItemSet();
+                bool bAutoGrowWidth = static_cast<const SdrOnOffItem&>(rSet.Get(SDRATTR_TEXT_AUTOGROWWIDTH)).GetValue();
+                bool bAutoGrowHeight = static_cast<const SdrOnOffItem&>(rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT)).GetValue();
+
+                // prepare ItemSet to set exchanged width and height items
+                SfxItemSet aNewSet(*rSet.GetPool(),
+                    SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT,
+                    0, 0);
+
+                aNewSet.Put(rSet);
+                aNewSet.Put(makeSdrTextAutoGrowWidthItem(bAutoGrowHeight));
+                aNewSet.Put(makeSdrTextAutoGrowHeightItem(bAutoGrowWidth));
+                rObj.SetObjectItemSet(aNewSet);
+
+                // restore object size
+                rObj.SetSnapRect(aObjectRect);
+            }
+
             // call parent
             AttributeProperties::ItemChange( nWhich, pNewItem );
         }
@@ -1068,6 +1112,18 @@ void SAL_CALL Cell::setPropertyValue( const OUString& rPropertyName, const Any&
             mpProperties->SetObjectItem( XFillBmpTileItem( eMode == BitmapMode_REPEAT ) );
             return;
         }
+        case SDRATTR_TABLE_TEXT_ROTATION:
+        {
+            sal_Int32 nRotVal = 0;
+            if (!(rValue >>= nRotVal))
+                throw IllegalArgumentException();
+
+            if (nRotVal != 27000 && nRotVal != 9000 && nRotVal != 0)
+                throw IllegalArgumentException();
+
+            mpProperties->SetObjectItem(SvxTextRotateItem(nRotVal/10, SDRATTR_TABLE_TEXT_ROTATION));
+            return;
+        }
         default:
         {
             SfxItemSet aSet( GetModel()->GetItemPool(), pMap->nWID, pMap->nWID);
@@ -1183,6 +1239,11 @@ Any SAL_CALL Cell::getPropertyValue( const OUString& PropertyName ) throw(Unknow
                 return Any(  BitmapMode_NO_REPEAT );
             }
         }
+        case SDRATTR_TABLE_TEXT_ROTATION:
+        {
+            const SvxTextRotateItem& rTextRotate = static_cast<const SvxTextRotateItem&>(mpProperties->GetItem(SDRATTR_TABLE_TEXT_ROTATION));
+            return Any(sal_Int32(rTextRotate.GetValue() * 10));
+        }
         default:
         {
             SfxItemSet aSet( GetModel()->GetItemPool(), pMap->nWID, pMap->nWID);
diff --git a/svx/source/table/svdotable.cxx b/svx/source/table/svdotable.cxx
index d53ddfffd777..a4374b9a7633 100644
--- a/svx/source/table/svdotable.cxx
+++ b/svx/source/table/svdotable.cxx
@@ -1950,9 +1950,9 @@ bool SdrTableObj::IsVerticalWriting() const
 }
 
 
-void SdrTableObj::SetVerticalWriting(bool bVertical )
+void SdrTableObj::SetVerticalWriting(bool bVertical)
 {
-    if( bVertical != IsVerticalWriting() )
+    if(bVertical != IsVerticalWriting() )
     {
         SvxWritingModeItem aModeItem( css::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION );
         SetObjectItem( aModeItem );
diff --git a/svx/source/unodraw/unoshtxt.cxx b/svx/source/unodraw/unoshtxt.cxx
index 3a5705f64508..b7bd9a66fcba 100644
--- a/svx/source/unodraw/unoshtxt.cxx
+++ b/svx/source/unodraw/unoshtxt.cxx
@@ -636,7 +636,7 @@ SvxTextForwarder* SvxTextEditSourceImpl::GetBackgroundTextForwarder()
                 mpOutliner->SetStyleSheet( 0, pStyleSheet );
 
             if( bVertical )
-                mpOutliner->SetVertical( true );
+                mpOutliner->SetVertical( true, pOutlinerParaObject->IsTopToBottom());
         }
 
         // maybe we have to set the border attributes
diff --git a/xmloff/inc/xmlsdtypes.hxx b/xmloff/inc/xmlsdtypes.hxx
index 8e388cf032c7..86e81ba3ea5b 100644
--- a/xmloff/inc/xmlsdtypes.hxx
+++ b/xmloff/inc/xmlsdtypes.hxx
@@ -117,6 +117,8 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
+#define XML_SD_TYPE_CELL_ROTATION_ANGLE             (XML_SD_TYPES_START + 79 )
+
 #define CTF_NUMBERINGRULES          1000
 #define CTF_CONTROLWRITINGMODE      1001
 #define CTF_WRITINGMODE             1002
diff --git a/xmloff/source/draw/sdpropls.cxx b/xmloff/source/draw/sdpropls.cxx
index 72d6315fa088..3afbf338176c 100644
--- a/xmloff/source/draw/sdpropls.cxx
+++ b/xmloff/source/draw/sdpropls.cxx
@@ -32,6 +32,7 @@
 
 #include <com/sun/star/drawing/BitmapMode.hpp>
 #include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
 #include <xmloff/EnumPropertyHdl.hxx>
 #include <xmloff/NamedBoolPropertyHdl.hxx>
 #include <xmloff/WordWrapPropertyHdl.hxx>
@@ -62,6 +63,7 @@
 #include "XMLPercentOrMeasurePropertyHandler.hxx"
 #include "animations.hxx"
 #include <sax/tools/converter.hxx>
+#include "xmlsdtypes.hxx"
 
 #include "sdxmlexp_impl.hxx"
 
@@ -853,6 +855,52 @@ bool XMLSdHeaderFooterVisibilityTypeHdl::exportXML(
     return bRet;
 }
 
+class XMLSdRotationAngleTypeHdl : public XMLPropertyHandler
+{
+public:
+    virtual bool importXML(const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter) const override;
+    virtual bool exportXML(OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter) const override;
+};
+
+bool XMLSdRotationAngleTypeHdl::importXML(
+    const OUString& rStrImpValue,
+    css::uno::Any& rValue,
+    const SvXMLUnitConverter&) const
+{
+    sal_Int32 nValue;
+    bool const bRet = ::sax::Converter::convertNumber(nValue, rStrImpValue);
+    if (bRet)
+    {
+        nValue = (nValue % 360);
+        if (nValue < 0)
+            nValue = 360 + nValue;
+        sal_Int32 nAngle;
+        if (nValue < 45 || nValue > 315)
+            nAngle = 0;
+        else if (nValue < 180)
+            nAngle = 9000;
+        else /* if nValalue <= 315 ) */
+            nAngle = 27000;
+
+        rValue <<= nAngle;
+    }
+    return bRet;
+}
+
+bool XMLSdRotationAngleTypeHdl::exportXML(
+    OUString& rStrExpValue,
+    const Any& rValue,
+    const SvXMLUnitConverter&) const
+{
+    sal_Int32 nAngle;
+    bool bRet = (rValue >>= nAngle) && nAngle != 0;
+    if (bRet)
+    {
+        rStrExpValue = OUString::number(nAngle / 100);
+    }
+    return bRet;
+}
+
 XMLSdPropHdlFactory::XMLSdPropHdlFactory( uno::Reference< frame::XModel > const & xModel, SvXMLImport& rImport )
 : mxModel( xModel ), mpExport(nullptr), mpImport( &rImport )
 {
@@ -1154,6 +1202,9 @@ const XMLPropertyHandler* XMLSdPropHdlFactory::GetPropertyHandler( sal_Int32 nTy
             case XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE:
                 pHdl = new XMLSdHeaderFooterVisibilityTypeHdl();
                 break;
+            case XML_SD_TYPE_CELL_ROTATION_ANGLE:
+                pHdl = new XMLSdRotationAngleTypeHdl;
+                break;
         }
 
         if(pHdl)
@@ -1276,7 +1327,18 @@ void XMLShapeExportPropertyMapper::ContextFilter(
                 pControlWritingMode = property;
                 break;
             case CTF_TEXTWRITINGMODE:
-                pTextWritingMode = property;
+                {
+                    pTextWritingMode = property;
+                    sal_Int32 eWritingMode;
+                    if (property->maValue >>= eWritingMode)
+                    {
+                        if (text::WritingMode2::LR_TB == eWritingMode)
+                        {
+                            property->mnIndex = -1;
+                            pTextWritingMode = nullptr;
+                        }
+                    }
+                }
                 break;
             case CTF_REPEAT_OFFSET_X:
                 pRepeatOffsetX = property;
diff --git a/xmloff/source/table/XMLTableExport.cxx b/xmloff/source/table/XMLTableExport.cxx
index 4a4785788837..12d75906e471 100644
--- a/xmloff/source/table/XMLTableExport.cxx
+++ b/xmloff/source/table/XMLTableExport.cxx
@@ -44,6 +44,7 @@
 #include <xmloff/xmlexppr.hxx>
 #include <xmloff/xmlexp.hxx>
 #include <xmloff/xmltypes.hxx>
+#include "xmlsdtypes.hxx"
 #include <xmloff/maptype.hxx>
 #include <xmloff/prhdlfac.hxx>
 #include <xmloff/txtprmap.hxx>
@@ -62,6 +63,7 @@ using namespace ::com::sun::star::style;
 #define MAP_(name,prefix,token,type,context)  { name, sizeof(name)-1, prefix, token, type, context, SvtSaveOptions::ODFVER_010, false }
 #define CMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TABLE_COLUMN,context)
 #define RMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TABLE_ROW,context)
+#define CELLMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TABLE_CELL,context)
 #define MAP_END { nullptr, 0, 0, XML_EMPTY, 0, 0, SvtSaveOptions::ODFVER_010, false }
 
 const XMLPropertyMapEntry* getColumnPropertiesMap()
@@ -89,6 +91,17 @@ const XMLPropertyMapEntry* getRowPropertiesMap()
     return &aXMLRowProperties[0];
 }
 
+const XMLPropertyMapEntry* getCellPropertiesMap()
+{
+    static const XMLPropertyMapEntry aXMLCellProperties[] =
+    {
+        CELLMAP( "RotateAngle",     XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE,         XML_SD_TYPE_CELL_ROTATION_ANGLE,   0),
+        MAP_END
+    };
+
+    return &aXMLCellProperties[0];
+}
+
 class StringStatisticHelper
 {
 private:
@@ -167,6 +180,7 @@ XMLTableExport::XMLTableExport(SvXMLExport& rExp, const rtl::Reference< SvXMLExp
     {
         mxCellExportPropertySetMapper = xExportPropertyMapper;
         mxCellExportPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp));
+        mxCellExportPropertySetMapper->ChainExportMapper(new SvXMLExportPropertyMapper(new XMLPropertySetMapper(getCellPropertiesMap(), xFactoryRef.get(), true)));
     }
 

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list