[Libreoffice-commits] core.git: Branch 'feature/table_rotated_text' - 123 commits - accessibility/source android/source basctl/source basegfx/source basic/source binaryurp/source chart2/qa chart2/source comphelper/source compilerplugins/clang connectivity/source cppcanvas/source cui/source dbaccess/source desktop/source editeng/source extensions/source external/libmwaw filter/source forms/source .gitignore helpcontent2 hwpfilter/source i18npool/source icon-themes/breeze icon-themes/breeze_dark icon-themes/breeze_svg idlc/source include/comphelper include/editeng include/filter include/LibreOfficeKit include/rtl include/sfx2 include/svl include/svtools include/svx include/vcl lotuswordpro/source officecfg/registry oox/inc oox/source qadevOOo/tests registry/source reportdesign/source rsc/source sal/qa sax/source sccomp/qa sc/inc scp2/inc scp2/source sc/qa sc/source sdext/source sd/qa sd/source setup_native/source sfx2/source slideshow/source solenv/bin solenv/gbuild starmath/inc starmath/qa starmat h/source stoc/source svl/qa svl/source svtools/source svx/inc svx/source svx/uiconfig svx/UIConfig_svx.mk sw/inc sw/qa sw/source toolkit/source tools/source unoidl/source unotools/source unusedcode.easy unusedcode.exclude uui/source vcl/osx vcl/qa vcl/source vcl/unx vcl/win vcl/workben winaccessibility/source wizards/source writerfilter/source xmloff/inc xmloff/source xmlscript/source xmlsecurity/qa xmlsecurity/source

Tamás Zolnai tamas.zolnai at collabora.com
Fri Apr 14 21:41:30 UTC 2017


Rebased ref, commits from common ancestor:
commit 44325f5d7251d716440cb41cd3c5b3ca878939b2
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Fri Apr 14 17:03:28 2017 +0200

    Avoid using implicit assignment operator
    
    Change-Id: If9b67d16e468f9a705140da2c7b39721b47c5799

diff --git a/include/editeng/outlobj.hxx b/include/editeng/outlobj.hxx
index 1477e38d8b5b..24c806b6952e 100644
--- a/include/editeng/outlobj.hxx
+++ b/include/editeng/outlobj.hxx
@@ -46,6 +46,9 @@ struct OutlinerParaObjData
 
     OutlinerParaObjData( const OutlinerParaObjData& r );
 
+    // assignment operator
+    OutlinerParaObjData& operator=(const OutlinerParaObjData& rCandidate) = delete;
+
     // destructor
     ~OutlinerParaObjData();
 
commit 861fed7c5060c47003d3106266e1efab7a2a84f3
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Fri Apr 14 17:02:48 2017 +0200

    ODF import / export of rotated text of Impress cell
    
    Change-Id: I57136e32ed2db5e405a45e8e4bad1b8d459b7ae8

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 dd57ec01bf3d..80a03416d759 100644
--- a/sd/qa/unit/export-tests.cxx
+++ b/sd/qa/unit/export-tests.cxx
@@ -93,6 +93,7 @@ public:
     void testTransparentBackground();
     void testEmbeddedPdf();
     void testAuthorField();
+    void testTdf100926();
 
     CPPUNIT_TEST_SUITE(SdExportTest);
 
@@ -108,6 +109,7 @@ public:
     CPPUNIT_TEST(testTransparentBackground);
     CPPUNIT_TEST(testEmbeddedPdf);
     CPPUNIT_TEST(testAuthorField);
+    CPPUNIT_TEST(testTdf100926);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -571,6 +573,35 @@ void SdExportTest::testAuthorField()
     xDocShRef->DoClose();
 }
 
+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/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 b32204d11e52..83462fd3089f 100644
--- a/xmloff/source/draw/sdpropls.cxx
+++ b/xmloff/source/draw/sdpropls.cxx
@@ -27,6 +27,7 @@
 #include <com/sun/star/presentation/FadeEffect.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>
@@ -58,6 +59,7 @@
 #include "XMLPercentOrMeasurePropertyHandler.hxx"
 #include "animations.hxx"
 #include <sax/tools/converter.hxx>
+#include "xmlsdtypes.hxx"
 
 #include "sdxmlexp_impl.hxx"
 
@@ -843,6 +845,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 )
 {
@@ -1142,6 +1190,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)
@@ -1264,7 +1315,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 668e2b477931..6be73aa181e3 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)));
     }
 
     mxRowExportPropertySetMapper = new SvXMLExportPropertyMapper( new XMLPropertySetMapper( getRowPropertiesMap(), xFactoryRef.get(), true ) );
diff --git a/xmloff/source/table/XMLTableImport.cxx b/xmloff/source/table/XMLTableImport.cxx
index 8e8db41dd068..46e5b7ed04f1 100644
--- a/xmloff/source/table/XMLTableImport.cxx
+++ b/xmloff/source/table/XMLTableImport.cxx
@@ -216,6 +216,7 @@ XMLTableImport::XMLTableImport( SvXMLImport& rImport, const rtl::Reference< XMLP
     {
         mxCellImportPropertySetMapper = new SvXMLImportPropertyMapper( xCellPropertySetMapper.get(), rImport );
         mxCellImportPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImport));
+        mxCellImportPropertySetMapper->ChainImportMapper(new SvXMLImportPropertyMapper(new XMLPropertySetMapper(getCellPropertiesMap(), xFactoryRef.get(), true), rImport));
     }
 
     rtl::Reference < XMLPropertySetMapper > xRowMapper( new XMLPropertySetMapper( getRowPropertiesMap(), xFactoryRef.get(), false ) );
diff --git a/xmloff/source/table/table.hxx b/xmloff/source/table/table.hxx
index cb00e7cb13f4..2eddd38d5b83 100644
--- a/xmloff/source/table/table.hxx
+++ b/xmloff/source/table/table.hxx
@@ -34,6 +34,7 @@ extern const TableStyleElement* getTableStyleMap();
 extern const TableStyleElement*  getWriterSpecificTableStyleMap();
 extern const XMLPropertyMapEntry* getColumnPropertiesMap();
 extern const XMLPropertyMapEntry* getRowPropertiesMap();
+extern const XMLPropertyMapEntry* getCellPropertiesMap();
 
 #endif
 
commit 182c6f5e602a3532a202b55df62483bac63afaba
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Fri Apr 7 14:17:57 2017 +0200

    tdf#100926: PPTX import of table with rotated text
    
    Change-Id: I05a8e979ac11b179e15784023032a56edc5b569b

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/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index f45ae187d0db..881a43de6928 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -145,6 +145,7 @@ public:
     void testTdf104445();
     void testTdf105150();
     void testTdf105150PPT();
+    void testTdf100926();
 
     bool checkPattern(sd::DrawDocShellRef& rDocRef, int nShapeNumber, std::vector<sal_uInt8>& rExpected);
     void testPatternImport();
@@ -210,6 +211,7 @@ public:
     CPPUNIT_TEST(testTdf104445);
     CPPUNIT_TEST(testTdf105150);
     CPPUNIT_TEST(testTdf105150PPT);
+    CPPUNIT_TEST(testTdf100926);
     CPPUNIT_TEST(testPatternImport);
 
     CPPUNIT_TEST_SUITE_END();
@@ -2189,6 +2191,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();
commit 6f077877f08c2d0afbe265f899a009ad175edd4b
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Thu Apr 6 22:22:53 2017 +0200

    Implement RotateAngle API property for Impress table cells
    
    Change-Id: I01379c0fc21e8fe294bc882bf824f64502863ff4

diff --git a/svx/source/table/cell.cxx b/svx/source/table/cell.cxx
index 814e69ce3790..8da2f1555a06 100644
--- a/svx/source/table/cell.cxx
+++ b/svx/source/table/cell.cxx
@@ -90,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,
@@ -285,8 +286,6 @@ namespace sdr
 
                         OutlinerParaObject* pTemp = pOutliner->CreateParaObject(0, nParaCount);
                         pOutliner->Clear();
-                        pTemp->SetVertical(pParaObj->IsVertical(), pParaObj->IsTopToBottom());
-
                         mxCell->SetOutlinerParaObject(pTemp);
                     }
 
@@ -1102,6 +1101,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);
@@ -1217,6 +1228,11 @@ Any SAL_CALL Cell::getPropertyValue( const OUString& PropertyName )
                 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);
commit 220dc0b5015fa0d17fa36d61b87aea2ed0118379
Author: Tamás Zolnai <tamas.zolnai at collabora.com>
Date:   Wed Apr 5 15:12:11 2017 +0200

    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)
    
    Change-Id: Ifc2e0f171e9c840e86b365e9af2c30aa97ecd92e

diff --git a/editeng/source/editeng/editdoc.cxx b/editeng/source/editeng/editdoc.cxx
index 5cb51b1ea647..572402936587 100644
--- a/editeng/source/editeng/editdoc.cxx
+++ b/editeng/source/editeng/editdoc.cxx
@@ -1974,6 +1974,7 @@ EditDoc::EditDoc( SfxItemPool* pPool ) :
     pItemPool(pPool ? pPool : new EditEngineItemPool(false)),
     nDefTab(DEFTAB),
     bIsVertical(false),
+    bIsTopToBottomVert(false),
     bIsFixedCellHeight(false),
     bOwnerOfPool(pPool == nullptr),
     bModified(false)
@@ -2108,7 +2109,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 a31eaefc5739..d1c921d74d49 100644
--- a/editeng/source/editeng/editdoc.hxx
+++ b/editeng/source/editeng/editdoc.hxx
@@ -746,6 +746,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;
@@ -772,8 +773,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 4e2aa8d4cfe2..0a4c315bf970 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -428,9 +428,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
@@ -438,6 +438,11 @@ bool EditEngine::IsVertical() const
     return pImpEditEngine->IsVertical();
 }
 
+bool EditEngine::IsTopToBottom() const
+{
+    return pImpEditEngine->IsTopToBottom();
+}
+
 void EditEngine::SetFixedCellHeight( bool bUseFixedCellHeight )
 {
     pImpEditEngine->SetFixedCellHeight( bUseFixedCellHeight );
@@ -1777,8 +1782,16 @@ void EditEngine::StripPortions()
     tools::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 17f9f13e9497..778bb6677f5d 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -356,9 +356,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
@@ -560,6 +565,7 @@ EditTextObjectImpl::EditTextObjectImpl( EditTextObject* pFront, SfxItemPool* pP
     }
 
     bVertical = false;
+    bIsTopToBottomVert = false;
     bStoreUnicodeStrings = false;
     nScriptType = SvtScriptType::NONE;
 }
@@ -572,6 +578,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;
@@ -653,12 +660,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();
     }
 }
@@ -1088,7 +1105,7 @@ public:
 
 void EditTextObjectImpl::StoreData( SvStream& rOStream ) const
 {
-    sal_uInt16 nVer = 602;
+    sal_uInt16 nVer = 603;
     rOStream.WriteUInt16( nVer );
 
     rOStream.WriteBool( bOwnerOfPool );
@@ -1235,6 +1252,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 );
@@ -1487,6 +1505,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;
@@ -1577,7 +1602,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 d9efd1fb200d..928f4ba12b84 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 25df5d898fd8..43cb55259fb9 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();
+}
+
 tools::Rectangle ImpEditView::GetVisDocArea() const
 {
     return tools::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);
+        }
         // Move by aligned value does not necessarily result in aligned
         // rectangle ...
         aVisDocStartPos = pOutWin->LogicToPixel( aVisDocStartPos );
@@ -2101,8 +2143,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 fe0ce85c2386..651441ab8fab 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -295,6 +295,7 @@ public:
     const tools::Rectangle&    GetOutputArea() const   { return aOutArea; }
 
     bool            IsVertical() const;
+    bool            IsTopToBottom() const;
 
     bool            PostKeyEvent( const KeyEvent& rKeyEvent, vcl::Window* pFrameWin );
 
@@ -722,8 +723,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 4e656233dac0..462229e2f25e 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, tools::Rectangle aClipRect, Po
         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, tools::Rectangle aClipRect, Po
             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, tools::Rectangle aClipRect, Po
                 }
                 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, tools::Rectangle aClipRect, Po
                         }
                         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, tools::Rectangle aClipRect, Po
                                                 }
                                                 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, tools::Rectangle aClipRect, Po
                                                 }
                                                 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, tools::Rectangle aClipRect, Po
                                                     }
                                                     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, tools::Rectangle aClipRect, Po
                                             }
                                             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, tools::Rectangle aClipRect, Po
                                             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, tools::Rectangle aClipRect, Po
                                                 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, tools::Rectangle aClipRect, Po
                     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, tools::Rectangle aClipRect, Po
                 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, tools::Rectangle aClipRect, Po
             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, tools::Rectangle aClipRect, Po
         // 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 tools::Rectangle& rRect, Ou
     }
     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 99a926075737..ab1db9862c79 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -1023,7 +1023,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() )
@@ -1181,7 +1181,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/outliner/outlin2.cxx b/editeng/source/outliner/outlin2.cxx
index d3504c94b24f..08495c39fa07 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
diff --git a/editeng/source/outliner/outlobj.cxx b/editeng/source/outliner/outlobj.cxx
index 539e4c2b2652..1cbd51f5700c 100644
--- a/editeng/source/outliner/outlobj.cxx
+++ b/editeng/source/outliner/outlobj.cxx
@@ -130,12 +130,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 fec33b5d4944..292712cc6823 100644
--- a/include/editeng/charrotateitem.hxx
+++ b/include/editeng/charrotateitem.hxx
@@ -63,6 +63,7 @@ public:
     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;
 };
diff --git a/include/editeng/editeng.hxx b/include/editeng/editeng.hxx
index a8fa950a6805..6b3ba51a6578 100644
--- a/include/editeng/editeng.hxx
+++ b/include/editeng/editeng.hxx
@@ -242,8 +242,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 509954069b09..2833be068fa7 100644
--- a/include/editeng/editobj.hxx
+++ b/include/editeng/editobj.hxx
@@ -86,7 +86,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/outliner.hxx b/include/editeng/outliner.hxx
index 665497ed33a3..5d2ce0044517 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -684,7 +684,7 @@ public:
     void            Init( OutlinerMode nOutlinerMode );
     OutlinerMode    GetMode() const { return nOutlinerMode; }
 
-    void            SetVertical( bool bVertical );
+    void            SetVertical( bool bVertical, bool bTopToBottom = true);
     bool            IsVertical() const;
 
     void            SetFixedCellHeight( bool bUseFixedCellHeight );
diff --git a/include/editeng/outlobj.hxx b/include/editeng/outlobj.hxx
index b296d7907376..1477e38d8b5b 100644
--- a/include/editeng/outlobj.hxx
+++ b/include/editeng/outlobj.hxx
@@ -81,7 +81,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 f3bf1ea8484a..2afa2f94f4b8 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/include/svx/svdoashp.hxx b/include/svx/svdoashp.hxx
index 483455aa2d25..dd4d03789c51 100644
--- a/include/svx/svdoashp.hxx
+++ b/include/svx/svdoashp.hxx
@@ -210,7 +210,7 @@ public:
     virtual bool AdjustTextFrameWidthAndHeight() override;
     virtual bool IsAutoGrowHeight() const override;
     virtual bool IsAutoGrowWidth() const override;
-    virtual void SetVerticalWriting( bool bVertical ) override;
+    virtual void SetVerticalWriting(bool bVertical) override;
     virtual void TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const override;
     virtual void EndTextEdit( SdrOutliner& rOutl ) override;
     virtual void TakeTextAnchorRect( tools::Rectangle& rAnchorRect ) const override;
diff --git a/sd/source/ui/func/futext.cxx b/sd/source/ui/func/futext.cxx
index 4f9955ceea3a..e22615cb5728 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 7a09e8a8c313..427242539cc3 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>
@@ -320,6 +321,7 @@ SdrItemPool::SdrItemPool(
     rPoolDefaults[ SDRATTR_TABLE_BORDER_INNER - SDRATTR_START ] =  pBoxInfoItem;
     rPoolDefaults[ SDRATTR_TABLE_BORDER_TLBR - SDRATTR_START ] = new SvxLineItem( SDRATTR_TABLE_BORDER_TLBR );
     rPoolDefaults[ SDRATTR_TABLE_BORDER_BLTR - SDRATTR_START ] = new SvxLineItem( SDRATTR_TABLE_BORDER_BLTR );
+    rPoolDefaults[ 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 6e75fd299131..50522622e646 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);
@@ -1529,6 +1529,7 @@ bool SdrTextObj::IsVerticalWriting() const
 void SdrTextObj::SetVerticalWriting(bool bVertical)
 {
     OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+
     if( !pOutlinerParaObject && bVertical )
     {
         // we only need to force a outliner para object if the default of
@@ -1537,7 +1538,8 @@ void SdrTextObj::SetVerticalWriting(bool bVertical)
         pOutlinerParaObject = GetOutlinerParaObject();
     }
 
-    if( pOutlinerParaObject && (pOutlinerParaObject->IsVertical() != bVertical) )
+    if (pOutlinerParaObject &&
+        (pOutlinerParaObject->IsVertical() != bVertical))
     {
         // get item settings
         const SfxItemSet& rSet = GetObjectItemSet();
@@ -1564,14 +1566,14 @@ void SdrTextObj::SetVerticalWriting(bool bVertical)
         aNewSet.Put(makeSdrTextAutoGrowHeightItem(bAutoGrowWidth));
 
         // Exchange horz and vert adjusts
-        switch(eVert)
+        switch (eVert)
         {
             case SDRTEXTVERTADJUST_TOP: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT)); break;
             case SDRTEXTVERTADJUST_CENTER: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER)); break;
             case SDRTEXTVERTADJUST_BOTTOM: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT)); break;
             case SDRTEXTVERTADJUST_BLOCK: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK)); break;
         }
-        switch(eHorz)
+        switch (eHorz)
         {
             case SDRTEXTHORZADJUST_LEFT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM)); break;
             case SDRTEXTHORZADJUST_CENTER: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER)); break;
@@ -1582,7 +1584,7 @@ void SdrTextObj::SetVerticalWriting(bool bVertical)
         SetObjectItemSet(aNewSet);
 
         pOutlinerParaObject = GetOutlinerParaObject();
-        if( pOutlinerParaObject )
+        if (pOutlinerParaObject)
         {
             // set ParaObject orientation accordingly
             pOutlinerParaObject->SetVertical(bVertical);
@@ -1593,7 +1595,6 @@ void SdrTextObj::SetVerticalWriting(bool bVertical)
     }
 }
 
-
 // transformation interface for StarOfficeAPI. This implements support for
 // homogeneous 3x3 matrices containing the transformation of the SdrObject. At the
 // moment it contains a shearX, rotation and translation, but for setting all linear
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx
index 926ae34dfc31..a05a428b6798 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 41601c98be83..814e69ce3790 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>
@@ -284,6 +285,7 @@ namespace sdr
 
                         OutlinerParaObject* pTemp = pOutliner->CreateParaObject(0, nParaCount);
                         pOutliner->Clear();
+                        pTemp->SetVertical(pParaObj->IsVertical(), pParaObj->IsTopToBottom());
 
                         mxCell->SetOutlinerParaObject(pTemp);
                     }
@@ -307,8 +309,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();
@@ -327,6 +328,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
+                tools::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 );
         }
diff --git a/svx/source/table/svdotable.cxx b/svx/source/table/svdotable.cxx
index 7aea17aebfdf..0b0596bae078 100644
--- a/svx/source/table/svdotable.cxx
+++ b/svx/source/table/svdotable.cxx
@@ -1943,9 +1943,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 cb5b73836645..0d688e55bf3c 100644
--- a/svx/source/unodraw/unoshtxt.cxx
+++ b/svx/source/unodraw/unoshtxt.cxx
@@ -635,7 +635,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
commit d5215e0e58febf582b18ad38f5745f8ae924cc1f
Author: Bartosz Kosiorek <gang65 at poczta.onet.pl>
Date:   Thu Mar 23 00:24:34 2017 +0100

    unit test for CEILING and FLOOR .xlsx export, tdf#100011
    
    Change-Id: I2ce45db4ae905dedf7c3dc8fb0fd9519ace6c3aa
    Reviewed-on: https://gerrit.libreoffice.org/35549
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins <ci at libreoffice.org>

diff --git a/sc/qa/unit/data/ods/ceiling-floor.ods b/sc/qa/unit/data/ods/ceiling-floor.ods
new file mode 100644
index 000000000000..051518b6fc4a
Binary files /dev/null and b/sc/qa/unit/data/ods/ceiling-floor.ods differ
diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index ffb3bbf15157..6cc4bbb407a1 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -144,9 +144,11 @@ public:
 
     void testCeilingFloor( sal_uLong nFormatType );
     void testCeilingFloorXLSX();
+    void testCeilingFloorODSToXLSX();
     void testCeilingFloorXLS();
     void testCeilingFloorODS();
 
+
 #if !defined _WIN32
     void testRelativePathsODS();
 #endif
@@ -239,6 +241,7 @@ public:
     CPPUNIT_TEST(testFunctionsExcel2010XLS);
     CPPUNIT_TEST(testFunctionsExcel2010ODS);
     CPPUNIT_TEST(testCeilingFloorXLSX);
+    CPPUNIT_TEST(testCeilingFloorODSToXLSX);
     CPPUNIT_TEST(testCeilingFloorXLS);
     CPPUNIT_TEST(testCeilingFloorODS);
 #if !defined(_WIN32)
@@ -2723,6 +2726,20 @@ void ScExportTest::testCeilingFloorXLSX()
     testCeilingFloor(FORMAT_XLSX);
 }
 
+void ScExportTest::testCeilingFloorODSToXLSX()
+{
+    // tdf#100011 - Cannot open sheet containg FLOOR/CEILING functions by MS Excel, after export to .xlsx
+    ScDocShellRef xShell = loadDoc("ceiling-floor.", FORMAT_ODS);
+    CPPUNIT_ASSERT_MESSAGE("Failed to load the document.", xShell.is());
+
+    std::shared_ptr<utl::TempFile> pXPathFile = ScBootstrapFixture::exportTo(&(*xShell), FORMAT_XLSX);
+    xmlDocPtr pSheet = XPathHelper::parseExport(pXPathFile, m_xSFactory, "xl/workbook.xml");
+    CPPUNIT_ASSERT(pSheet);
+
+    // there shouldn't be any defined names during export of FLOOR and CEILING functions to .xlsx
+    assertXPath(pSheet, "/x:workbook/x:definedNames", 0);
+}
+
 void ScExportTest::testCeilingFloorXLS()
 {
     testCeilingFloor(FORMAT_XLS);
@@ -2733,6 +2750,7 @@ void ScExportTest::testCeilingFloorODS()
     testCeilingFloor(FORMAT_ODS);
 }
 
+
 #if !defined _WIN32
 void ScExportTest::testRelativePathsODS()
 {
commit 54f6a0fe470096f6bdc3942e9f3032e40dbfcd23
Author: Yousuf Philips <philipz85 at hotmail.com>
Date:   Thu Apr 6 19:33:20 2017 +0400

    tdf#104706 Enable icon for Clear Direct Formatting command
    
    Change-Id: Iba3cbd8148794ac984a91d22d33cdec1f4453c5f
    Reviewed-on: https://gerrit.libreoffice.org/36221
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Katarina Behrens <Katarina.Behrens at cib.de>

diff --git a/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu
index 601c3cedbfde..6c168337d199 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu
@@ -41,6 +41,9 @@
         <prop oor:name="Label" oor:type="xs:string">
           <value xml:lang="en-US">Clear ~Direct Formatting</value>
         </prop>
+        <prop oor:name="Properties" oor:type="xs:int">
+          <value>1</value>
+        </prop>
       </node>
       <node oor:name=".uno:ClearArrowPrecedents" oor:op="replace">
         <prop oor:name="Label" oor:type="xs:string">
commit 4c62515d5b6ec5876cafb1165cd9501502fa4c87
Author: Stephan Bergmann <sbergman at redhat.com>
Date:   Thu Apr 6 22:48:24 2017 +0200

    loplugin:redundantcast
    
    Change-Id: I925879cf8df630e4e20773c363b9a27a572f3093

diff --git a/vcl/osx/salnsmenu.mm b/vcl/osx/salnsmenu.mm
index f777a44dba15..fb1f7fb5d4d3 100644
--- a/vcl/osx/salnsmenu.mm
+++ b/vcl/osx/salnsmenu.mm
@@ -234,7 +234,7 @@ SAL_WNODEPRECATED_DECLARATIONS_POP
             aSize.width = 2;
             for( size_t i = 0; i < rButtons.size(); ++i )
             {
-                NSRect aImgRect = { { static_cast<CGFloat>(aSize.width),
+                NSRect aImgRect = { { aSize.width,
                                       static_cast<CGFloat>(floor((aSize.height-rButtons[i].maButton.maImage.GetSizePixel().Height())/2)) },
                                     { static_cast<CGFloat>(rButtons[i].maButton.maImage.GetSizePixel().Width()),
                                       static_cast<CGFloat>(rButtons[i].maButton.maImage.GetSizePixel().Height()) } };
commit d3099d03d5302303b9b7a3c29093455ff58be1ae
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Apr 5 10:10:46 2017 +0100

    split getAccessibleParent
    
    Change-Id: I579064ec8a6d419f0b065f94d505103d3629c483

diff --git a/sw/source/core/access/acccell.cxx b/sw/source/core/access/acccell.cxx
index 824169db9604..f1756996c17d 100644
--- a/sw/source/core/access/acccell.cxx
+++ b/sw/source/core/access/acccell.cxx
@@ -110,7 +110,7 @@ SwAccessibleCell::SwAccessibleCell(std::shared_ptr<SwAccessibleMap> const& pInit
     m_bIsSelected = IsSelected();
 
     css::uno::Reference<css::accessibility::XAccessible> xTableReference(
-        getAccessibleParent());
+        getAccessibleParentImpl());
     css::uno::Reference<css::accessibility::XAccessibleContext> xContextTable(
         xTableReference, css::uno::UNO_QUERY);
     SAL_WARN_IF(
diff --git a/sw/source/core/access/acccontext.cxx b/sw/source/core/access/acccontext.cxx
index cba7854b5c35..a40303b866bb 100644
--- a/sw/source/core/access/acccontext.cxx
+++ b/sw/source/core/access/acccontext.cxx
@@ -630,12 +630,10 @@ uno::Reference< XAccessible> SAL_CALL
     return xChild;
 }
 
-uno::Reference< XAccessible> SAL_CALL SwAccessibleContext::getAccessibleParent()
+uno::Reference< XAccessible> SAL_CALL SwAccessibleContext::getAccessibleParentImpl()
 {
     SolarMutexGuard aGuard;
 
-    ThrowIfDisposed();
-
     const SwFrame *pUpper = GetParent();
     OSL_ENSURE( pUpper != nullptr || m_isDisposing, "no upper found" );
 
@@ -654,6 +652,15 @@ uno::Reference< XAccessible> SAL_CALL SwAccessibleContext::getAccessibleParent()
     return xAcc;
 }
 
+uno::Reference< XAccessible> SAL_CALL SwAccessibleContext::getAccessibleParent()
+{
+    SolarMutexGuard aGuard;
+
+    ThrowIfDisposed();
+
+    return getAccessibleParentImpl();
+}
+
 sal_Int32 SAL_CALL SwAccessibleContext::getAccessibleIndexInParent()
 {
     SolarMutexGuard aGuard;
diff --git a/sw/source/core/access/acccontext.hxx b/sw/source/core/access/acccontext.hxx
index b5a0dd0e6837..1d4808bf34da 100644
--- a/sw/source/core/access/acccontext.hxx
+++ b/sw/source/core/access/acccontext.hxx
@@ -201,6 +201,10 @@ protected:
 
     virtual ~SwAccessibleContext() override;
 
+    // Return a reference to the parent.
+    css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+        getAccessibleParentImpl();
+
 public:
     SwAccessibleContext( std::shared_ptr<SwAccessibleMap> const& pMap,
                          sal_Int16 nRole, const SwFrame *pFrame );
commit 4dd95cadcd330aee49b3c84d3e336b808217af46
Author: Eike Rathke <erack at redhat.com>
Date:   Thu Apr 6 21:31:05 2017 +0200

    these FUNCFLAG_EXPORTONLY need also FUNCFLAG_MACROCALL_NEW, tdf#100011 related
    
    Maybe one day we'll actually use these tables also for export
    capabilities ...
    
    Change-Id: If3d55ec008e321d95b21e0d284c7d58d13a2399b

diff --git a/sc/source/filter/oox/formulabase.cxx b/sc/source/filter/oox/formulabase.cxx
index 4a2821cc1a1c..a4d80cdd9216 100644
--- a/sc/source/filter/oox/formulabase.cxx
+++ b/sc/source/filter/oox/formulabase.cxx
@@ -784,7 +784,7 @@ static const FunctionData saFuncTable2013[] =
     { "BITRSHIFT",              "BITRSHIFT",            NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     { "BITXOR",                 "BITXOR",               NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     { "COM.MICROSOFT.CEILING.MATH", "CEILING.MATH",     NOID,   NOID,   1,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
-    { "CEILING",                "CEILING.MATH",         NOID,   NOID,   1,  3,  V, { VR }, FUNCFLAG_EXPORTONLY },
+    { "CEILING",                "CEILING.MATH",         NOID,   NOID,   1,  3,  V, { VR }, FUNCFLAG_EXPORTONLY | FUNCFLAG_MACROCALL_NEW },
     { "COMBINA",                "COMBINA",              NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     { "COT",                    "COT",                  NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     { "COTH",                   "COTH",                 NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
@@ -795,7 +795,7 @@ static const FunctionData saFuncTable2013[] =
     { "COM.MICROSOFT.ENCODEURL","ENCODEURL",            NOID,   NOID,   1,  1,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     { "COM.MICROSOFT.FILTERXML","FILTERXML",            NOID,   NOID,   2,  2,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     { "COM.MICROSOFT.FLOOR.MATH", "FLOOR.MATH",         NOID,   NOID,   1,  3,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
-    { "FLOOR",                  "FLOOR.MATH",           NOID,   NOID,   1,  3,  V, { VR }, FUNCFLAG_EXPORTONLY },
+    { "FLOOR",                  "FLOOR.MATH",           NOID,   NOID,   1,  3,  V, { VR }, FUNCFLAG_EXPORTONLY | FUNCFLAG_MACROCALL_NEW },
     // NOTE: this FDIST is not our LEGACY.FDIST
     { nullptr/*"FDIST"*/,             "FDIST",                NOID,   NOID,   3,  4,  V, { VR }, FUNCFLAG_MACROCALL_NEW },
     // NOTE: this FINV is not our LEGACY.FINV
commit 883e6f7e0d1f70072d38593a466c542c684d43fc
Author: Stephan Bergmann <sbergman at redhat.com>
Date:   Thu Apr 6 21:26:58 2017 +0200

    No real need for OPropertyExport::AddAttributeASCII
    
    Change-Id: Ia8e62909ab484240468708ad1ff99a5e1cdc779c

diff --git a/xmloff/source/forms/propertyexport.cxx b/xmloff/source/forms/propertyexport.cxx
index 11b40dfc7c0c..46a2550ada7f 100644
--- a/xmloff/source/forms/propertyexport.cxx
+++ b/xmloff/source/forms/propertyexport.cxx
@@ -368,7 +368,7 @@ namespace xmloff
         else
         {
             if (!_bVoidDefault)
-                AddAttributeASCII(_nNamespaceKey, _pAttributeName, "");
+                AddAttribute(_nNamespaceKey, _pAttributeName, OUString());
         }
 
         // the property does not need to be handled anymore
@@ -634,14 +634,6 @@ namespace xmloff
         m_rContext.getGlobalContext().AddAttribute( _nPrefix, _rName, _rValue );
     }
 
-    void OPropertyExport::AddAttributeASCII(sal_uInt16 _nPrefix, const sal_Char* _pName, const sal_Char *pValue)
-    {
-        OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName(OUString::createFromAscii(_pName)).isEmpty(),
-            "OPropertyExport::AddAttributeASCII: already have such an attribute");
-
-        m_rContext.getGlobalContext().AddAttributeASCII(_nPrefix, _pName, pValue);
-    }
-
     void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue)
     {
         OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::xmloff::token::GetXMLToken(_eName)).isEmpty(),
diff --git a/xmloff/source/forms/propertyexport.hxx b/xmloff/source/forms/propertyexport.hxx
index 779423272c9d..8bdf3bf0fc93 100644
--- a/xmloff/source/forms/propertyexport.hxx
+++ b/xmloff/source/forms/propertyexport.hxx
@@ -358,7 +358,6 @@ namespace xmloff
 #ifdef DBG_UTIL
                 void AddAttribute(sal_uInt16 _nPrefix, const sal_Char* _pName, const OUString& _rValue);
                 void AddAttribute( sal_uInt16 _nPrefix, const OUString& _rName, const OUString& _rValue );
-                void AddAttributeASCII( sal_uInt16 nPrefix, const sal_Char *pName, const sal_Char *pValue );
                 void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue);
                 void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue );
 #else
@@ -367,8 +366,6 @@ namespace xmloff
             { m_rContext.getGlobalContext().AddAttribute(_nPrefix, _pName, _rValue); }
         inline void AddAttribute( sal_uInt16 _nPrefix, const OUString& _rName, const OUString& _rValue )
             { m_rContext.getGlobalContext().AddAttribute( _nPrefix, _rName, _rValue ); }
-        inline  void AddAttributeASCII( sal_uInt16 _nPrefix, const sal_Char* _pName, const sal_Char *pValue )
-            { m_rContext.getGlobalContext().AddAttributeASCII(_nPrefix, _pName, pValue); }
         inline void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue)
             { m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _rValue); }
         inline void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue )
commit ea01a08763e56a7de66f0c24655a627669c8a7f7
Author: Eike Rathke <erack at redhat.com>
Date:   Thu Apr 6 21:15:27 2017 +0200

    Resolves: tdf#100011 (re-)add ocCeil and ocFloor .xls(x) export mappings
    
    ... for CEILING and FLOOR that were lost when introducing CEILING.MATH
    and FLOOR.MATH which are semantically identical, but the export needs a
    distinct known mapping otherwise the function is stored as a macro call,
    which Excel dislikes.
    
    Change-Id: Id371c1732984a8e5567f74fd265b9aee88fb1898

diff --git a/sc/source/filter/excel/xlformula.cxx b/sc/source/filter/excel/xlformula.cxx
index 684ce569be47..0978c24e4864 100644
--- a/sc/source/filter/excel/xlformula.cxx
+++ b/sc/source/filter/excel/xlformula.cxx
@@ -408,6 +408,9 @@ static const XclFunctionInfo saFuncTable_Oox[] =
 #define EXC_FUNCENTRY_V_VR_IMPORT( opcode, minparam, maxparam, flags, asciiname ) \
     { opcode, NOID, minparam,     maxparam,     V, { VR },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
 
+#define EXC_FUNCENTRY_V_RO_EXPORT( opcode, minparam, maxparam, flags, asciiname ) \
+    { opcode,  255, (minparam)+1, (maxparam)+1, V, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
+
 #define EXC_FUNCENTRY_A_VR( opcode, minparam, maxparam, flags, asciiname ) \
     { opcode, NOID, minparam,     maxparam,     A, { VR },       EXC_FUNCFLAG_IMPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }, \
     { opcode,  255, (minparam)+1, (maxparam)+1, A, { RO_E, RO }, EXC_FUNCFLAG_EXPORTONLY|(flags), EXC_FUNCNAME( asciiname ) }
@@ -524,6 +527,7 @@ static const XclFunctionInfo saFuncTable_2013[] =
     EXC_FUNCENTRY_V_VR(         ocBitRshift,     2,  2,  0,  "BITRSHIFT" ),
     EXC_FUNCENTRY_V_VR(         ocBitXor,        2,  2,  0,  "BITXOR" ),
     EXC_FUNCENTRY_V_VR(         ocCeil_Math,     1,  3,  0,  "CEILING.MATH" ),
+    EXC_FUNCENTRY_V_RO_EXPORT(  ocCeil,          1,  3,  0,  "CEILING.MATH" ),
     EXC_FUNCENTRY_V_VR(         ocCombinA,       2,  2,  0,  "COMBINA" ),
     EXC_FUNCENTRY_V_VR_IMPORT(  ocCot,           1,  1,  0,  "COT" ),
     EXC_FUNCENTRY_V_VR_IMPORT(  ocCotHyp,        1,  1,  0,  "COTH" ),
@@ -538,6 +542,7 @@ static const XclFunctionInfo saFuncTable_2013[] =
     EXC_FUNCENTRY_V_VR(         ocNoName,        3,  3,  0,  "FINV" ),
     EXC_FUNCENTRY_V_VR(         ocFilterXML,     2,  2,  0,  "FILTERXML" ),
     EXC_FUNCENTRY_V_VR(         ocFloor_Math,    1,  3,  0,  "FLOOR.MATH" ),
+    EXC_FUNCENTRY_V_RO_EXPORT(  ocFloor,         1,  3,  0,  "FLOOR.MATH" ),
     EXC_FUNCENTRY_V_RO(         ocFormula,       1,  1,  0,  "FORMULATEXT" ),
     EXC_FUNCENTRY_V_VR(         ocGamma,         1,  1,  0,  "GAMMA" ),
     EXC_FUNCENTRY_V_VR(         ocGauss,         1,  1,  0,  "GAUSS" ),
commit 20feed528a9b9d57b35805611a4279000a474c3d
Author: Justin Luth <justin_luth at sil.org>
Date:   Thu Apr 6 13:06:29 2017 +0300

    tdf#106974 docx export: Crop is "long", not sal_Int16
    
    I got size sal_Int16 from the return value type of the border
    spacing, but somehow failed to lookup the return value of GraphicCrop.
    It now matches .doc export's sal_Int32.
    Bad mistake: regression 8eff1decd91cbfb10094c25d4cf1d2b434a4da72
    
    Change-Id: Ie149630b9da9a067de319149f23ca21f78a186cf
    Reviewed-on: https://gerrit.libreoffice.org/36200
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Stahl <mstahl at redhat.com>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf106974_int32Crop.docx b/sw/qa/extras/ooxmlexport/data/tdf106974_int32Crop.docx
new file mode 100755
index 000000000000..e73cf5e28dcf
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf106974_int32Crop.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx
index 7f36628e2164..a431fc812b07 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx
@@ -661,6 +661,16 @@ DECLARE_OOXMLEXPORT_TEST(testImageCrop, "ImageCrop.docx")
     CPPUNIT_ASSERT_EQUAL( sal_Int32( 2291 ), aGraphicCropStruct.Bottom );
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf106974_int32Crop, "tdf106974_int32Crop.docx")
+{
+    uno::Reference<drawing::XShape> image = getShape(1);
+    uno::Reference<beans::XPropertySet> imageProperties(image, uno::UNO_QUERY);
+    css::text::GraphicCrop aGraphicCropStruct;
+
+    imageProperties->getPropertyValue( "GraphicCrop" ) >>= aGraphicCropStruct;
+    CPPUNIT_ASSERT( sal_Int32( 46000 ) < aGraphicCropStruct.Right );
+}
+
 DECLARE_OOXMLEXPORT_TEST(testLineSpacingexport, "test_line_spacing.docx")
 {
      // The Problem was that the w:line attribute value in w:spacing tag was incorrect
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index dc8ab99bc126..d63cba52dccf 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -4163,10 +4163,10 @@ void DocxAttributeOutput::WriteSrcRect(const SdrObject* pSdrObj, const SwFrameFo
 
     css::text::GraphicCrop aGraphicCropStruct;
     xPropSet->getPropertyValue( "GraphicCrop" ) >>= aGraphicCropStruct;
-    sal_Int16 nCropL = aGraphicCropStruct.Left;
-    sal_Int16 nCropR = aGraphicCropStruct.Right;
-    sal_Int16 nCropT = aGraphicCropStruct.Top;
-    sal_Int16 nCropB = aGraphicCropStruct.Bottom;
+    sal_Int32 nCropL = aGraphicCropStruct.Left;
+    sal_Int32 nCropR = aGraphicCropStruct.Right;
+    sal_Int32 nCropT = aGraphicCropStruct.Top;
+    sal_Int32 nCropB = aGraphicCropStruct.Bottom;
 
     // simulate border padding as a negative crop.
     const SfxPoolItem* pItem;
commit d8604338c4b289c01d311b95a5587b250f0d6ff2
Author: Jochen Nitschke <j.nitschke+logerrit at ok.de>
Date:   Thu Apr 6 12:22:56 2017 +0200

    make page size compile time constant
    
    on educated guess
    > std::numeric_limits<sal_uInt32>::max() - sizeof(few fields) + 1
    is always greater 1000
    
    Change-Id: If0e91e27aabc2bda4beccb5e98eb20a7c890e2f0
    Reviewed-on: https://gerrit.libreoffice.org/36201
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>

diff --git a/svl/source/misc/strmadpt.cxx b/svl/source/misc/strmadpt.cxx
index c444838f84d9..1e36c637a388 100644
--- a/svl/source/misc/strmadpt.cxx
+++ b/svl/source/misc/strmadpt.cxx
@@ -54,6 +54,7 @@ private:
         sal_uInt32 m_nOffset;
         sal_Int8 m_aBuffer[1];
     };
+    static const sal_uInt32 m_nPageSize = 1000;
 
     std::multiset< sal_uInt32 > m_aMarks;
     Page * m_pFirstPage;
@@ -62,7 +63,6 @@ private:
     sal_Int8 * m_pReadBuffer;
     sal_uInt32 m_nReadBufferSize;
     sal_uInt32 m_nReadBufferFilled;
-    sal_uInt32 m_nPageSize;
     sal_uInt32 m_nPages;
     bool m_bEOF;
 
@@ -95,10 +95,6 @@ SvDataPipe_Impl::SvDataPipe_Impl()
     , m_pReadBuffer( nullptr )
     , m_nReadBufferSize( 0 )
     , m_nReadBufferFilled( 0 )
-    , m_nPageSize(std::min< sal_uInt32 >(
-                          1000,
-                          sal_uInt32(std::numeric_limits< sal_uInt32 >::max()
-                                     - sizeof (Page) + 1)))
     , m_nPages( 0 )
     , m_bEOF( false )
 {}
commit 6591934e66827bf01f1cff5bcbe7335fd5d5b970
Author: Zdeněk Crhonek <zcrhonek at gmail.com>
Date:   Wed Apr 5 20:52:06 2017 +0200

    add BAHTTEXT test case
    
    Change-Id: Ib6c4781b6a0a482539dfeea81dc1044f6d56e1d9
    Reviewed-on: https://gerrit.libreoffice.org/36163
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Zdenek Crhonek <zcrhonek at gmail.com>

diff --git a/sc/qa/unit/data/functions/text/fods/bahttext.fods b/sc/qa/unit/data/functions/text/fods/bahttext.fods
new file mode 100644
index 000000000000..04b227d2aec3
--- /dev/null
+++ b/sc/qa/unit/data/functions/text/fods/bahttext.fods
@@ -0,0 +1,4967 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:scr
 ipt="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:form
 x="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">
+ <office:meta><meta:creation-date>2017-04-05T20:50:35.229857290</meta:creation-date><meta:editing-duration>P0D</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:generator>LibreOfficeDev/5.4.0.0.alpha0$Linux_X86_64 LibreOffice_project/8e5437ea859e78f7de2730bfa60ab6d27534f286</meta:generator><meta:document-statistic meta:table-count="2" meta:cell-count="127" meta:object-count="0"/></office:meta>
+ <office:settings>
+  <config:config-item-set config:name="ooo:view-settings">
+   <config:config-item config:name="VisibleAreaTop" config:type="int">0</config:config-item>
+   <config:config-item config:name="VisibleAreaLeft" config:type="int">0</config:config-item>
+   <config:config-item config:name="VisibleAreaWidth" config:type="int">100465</config:config-item>
+   <config:config-item config:name="VisibleAreaHeight" config:type="int">11537</config:config-item>
+   <config:config-item-map-indexed config:name="Views">
+    <config:config-item-map-entry>
+     <config:config-item config:name="ViewId" config:type="string">view1</config:config-item>
+     <config:config-item-map-named config:name="Tables">
+      <config:config-item-map-entry config:name="Sheet1">
+       <config:config-item config:name="CursorPositionX" config:type="int">2</config:config-item>
+       <config:config-item config:name="CursorPositionY" config:type="int">8</config:config-item>
+       <config:config-item config:name="HorizontalSplitMode" config:type="short">0</config:config-item>
+       <config:config-item config:name="VerticalSplitMode" config:type="short">0</config:config-item>
+       <config:config-item config:name="HorizontalSplitPosition" config:type="int">0</config:config-item>
+       <config:config-item config:name="VerticalSplitPosition" config:type="int">0</config:config-item>
+       <config:config-item config:name="ActiveSplitRange" config:type="short">2</config:config-item>
+       <config:config-item config:name="PositionLeft" config:type="int">0</config:config-item>
+       <config:config-item config:name="PositionRight" config:type="int">0</config:config-item>
+       <config:config-item config:name="PositionTop" config:type="int">0</config:config-item>
+       <config:config-item config:name="PositionBottom" config:type="int">0</config:config-item>
+       <config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
+       <config:config-item config:name="ZoomValue" config:type="int">100</config:config-item>
+       <config:config-item config:name="PageViewZoomValue" config:type="int">60</config:config-item>
+       <config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item>
+       <config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">false</config:config-item>
+      </config:config-item-map-entry>
+      <config:config-item-map-entry config:name="Sheet2">
+       <config:config-item config:name="CursorPositionX" config:type="int">4</config:config-item>
+       <config:config-item config:name="CursorPositionY" config:type="int">1</config:config-item>
+       <config:config-item config:name="HorizontalSplitMode" config:type="short">0</config:config-item>
+       <config:config-item config:name="VerticalSplitMode" config:type="short">0</config:config-item>
+       <config:config-item config:name="HorizontalSplitPosition" config:type="int">0</config:config-item>
+       <config:config-item config:name="VerticalSplitPosition" config:type="int">0</config:config-item>
+       <config:config-item config:name="ActiveSplitRange" config:type="short">2</config:config-item>
+       <config:config-item config:name="PositionLeft" config:type="int">0</config:config-item>
+       <config:config-item config:name="PositionRight" config:type="int">0</config:config-item>
+       <config:config-item config:name="PositionTop" config:type="int">0</config:config-item>
+       <config:config-item config:name="PositionBottom" config:type="int">0</config:config-item>
+       <config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
+       <config:config-item config:name="ZoomValue" config:type="int">100</config:config-item>
+       <config:config-item config:name="PageViewZoomValue" config:type="int">60</config:config-item>
+       <config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item>
+       <config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">false</config:config-item>
+      </config:config-item-map-entry>
+     </config:config-item-map-named>
+     <config:config-item config:name="ActiveTable" config:type="string">Sheet2</config:config-item>
+     <config:config-item config:name="HorizontalScrollbarWidth" config:type="int">1241</config:config-item>
+     <config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
+     <config:config-item config:name="ZoomValue" config:type="int">100</config:config-item>
+     <config:config-item config:name="PageViewZoomValue" config:type="int">60</config:config-item>
+     <config:config-item config:name="ShowPageBreakPreview" config:type="boolean">false</config:config-item>
+     <config:config-item config:name="ShowZeroValues" config:type="boolean">true</config:config-item>
+     <config:config-item config:name="ShowNotes" config:type="boolean">true</config:config-item>
+     <config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item>
+     <config:config-item config:name="GridColor" config:type="long">12632256</config:config-item>
+     <config:config-item config:name="ShowPageBreaks" config:type="boolean">true</config:config-item>
+     <config:config-item config:name="HasColumnRowHeaders" config:type="boolean">true</config:config-item>
+     <config:config-item config:name="HasSheetTabs" config:type="boolean">true</config:config-item>
+     <config:config-item config:name="IsOutlineSymbolsSet" config:type="boolean">true</config:config-item>
+     <config:config-item config:name="IsValueHighlightingEnabled" config:type="boolean">true</config:config-item>
+     <config:config-item config:name="IsSnapToRaster" config:type="boolean">false</config:config-item>
+     <config:config-item config:name="RasterIsVisible" config:type="boolean">false</config:config-item>

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list