[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.2' - 5 commits - editeng/source include/editeng include/xmloff offapi/com schema/libreoffice sw/qa sw/source xmloff/source

Miklos Vajna (via logerrit) logerrit at kemper.freedesktop.org
Mon Jul 1 15:21:15 UTC 2019


 editeng/source/items/frmitems.cxx                           |   17 ++
 include/editeng/frmdir.hxx                                  |    5 
 include/editeng/frmdiritem.hxx                              |    1 
 include/xmloff/xmltoken.hxx                                 |    1 
 offapi/com/sun/star/text/WritingMode2.idl                   |    7 +
 schema/libreoffice/OpenDocument-schema-v1.3+libreoffice.rng |   11 +
 sw/qa/extras/odfexport/data/btlr-cell.odt                   |binary
 sw/qa/extras/odfexport/odfexport.cxx                        |   20 ++
 sw/source/core/inc/frame.hxx                                |   15 +-
 sw/source/core/inc/frmtool.hxx                              |    7 -
 sw/source/core/inc/swfont.hxx                               |   29 ++--
 sw/source/core/layout/calcmove.cxx                          |    2 
 sw/source/core/layout/colfrm.cxx                            |    2 
 sw/source/core/layout/findfrm.cxx                           |    1 
 sw/source/core/layout/newfrm.cxx                            |   61 ++++++++
 sw/source/core/layout/paintfrm.cxx                          |   26 ++-
 sw/source/core/layout/ssfrm.cxx                             |    4 
 sw/source/core/layout/wsfrm.cxx                             |   14 +-
 sw/source/core/text/inftxt.cxx                              |   23 ++-
 sw/source/core/text/itratr.cxx                              |    9 -
 sw/source/core/text/itratr.hxx                              |    3 
 sw/source/core/text/redlnitr.cxx                            |   16 +-
 sw/source/core/text/txtfrm.cxx                              |   15 ++
 sw/source/core/txtnode/fntcache.cxx                         |   25 ++-
 sw/source/core/txtnode/swfont.cxx                           |   83 ++++++++----
 sw/source/core/unocore/unotbl.cxx                           |    8 -
 sw/source/filter/xml/xmlexpit.cxx                           |   44 +++++-
 sw/source/filter/xml/xmlimpit.cxx                           |   31 +++-
 sw/source/filter/xml/xmlitemm.cxx                           |    1 
 xmloff/source/core/xmltoken.cxx                             |    1 
 xmloff/source/token/tokens.txt                              |    1 
 31 files changed, 374 insertions(+), 109 deletions(-)

New commits:
commit 7dce046c8816eb449d6ecf5a40c51519fe037361
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Feb 13 14:01:57 2019 +0100
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Mon Jul 1 16:58:45 2019 +0200

    sw btlr writing mode: implement ODF filter
    
    An easy way would be to just extend aXML_WritingDirection_Enum, but then
    we would write the new attribute value to a non-extension namespace.
    
    So special case the new attribute value during both import and export
    (and only for table cells as a start).
    
    Reviewed-on: https://gerrit.libreoffice.org/67770
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 8af98ac8bf0ac8795999ecbf061d3c094f7c3be4)
    
    Conflicts:
            sw/source/filter/xml/xmlimpit.cxx
    
    Change-Id: I431bf99693c4a3452e91f241bd2f0fcfc72c68fd

diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 815d84c599f9..bebbcb7f08ac 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -2183,6 +2183,7 @@ namespace xmloff { namespace token {
 
         XML_RL_TB,
         XML_TB_LR,
+        XML_BT_LR,
         XML_LR,
         XML_RL,
         XML_TB,
diff --git a/schema/libreoffice/OpenDocument-schema-v1.3+libreoffice.rng b/schema/libreoffice/OpenDocument-schema-v1.3+libreoffice.rng
index d59314e99771..956ccc2f02e4 100644
--- a/schema/libreoffice/OpenDocument-schema-v1.3+libreoffice.rng
+++ b/schema/libreoffice/OpenDocument-schema-v1.3+libreoffice.rng
@@ -2323,6 +2323,17 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
     </rng:optional>
   </rng:define>
 
+  <!-- TODO no proposal -->
+  <rng:define name="common-writing-mode-attlist" combine="interleave">
+    <rng:optional>
+      <rng:attribute name="loext:writing-mode">
+        <rng:choice>
+          <rng:value>bt-lr</rng:value>
+        </rng:choice>
+      </rng:attribute>
+    </rng:optional>
+  </rng:define>
+
   <!-- just a test-case for user-defined attributes, move along, nothing to see here... -->
   <rng:define name="style-table-cell-properties-attlist" combine="interleave">
     <rng:optional>
diff --git a/sw/qa/extras/odfexport/data/btlr-cell.odt b/sw/qa/extras/odfexport/data/btlr-cell.odt
new file mode 100644
index 000000000000..c010fa9f51b6
Binary files /dev/null and b/sw/qa/extras/odfexport/data/btlr-cell.odt differ
diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx
index 7031430efede..a47028c91b73 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -32,6 +32,7 @@
 #include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
 #include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
 #include <comphelper/storagehelper.hxx>
 #include <comphelper/fileformat.h>
 #include <comphelper/propertysequence.hxx>
@@ -1391,6 +1392,25 @@ DECLARE_ODFEXPORT_TEST(testWhitespace, "whitespace.odt")
     CPPUNIT_ASSERT(!xPortions->hasMoreElements());
 }
 
+DECLARE_ODFEXPORT_TEST(testBtlrCell, "btlr-cell.odt")
+{
+    // Without the accompanying fix in place, this test would have failed, as
+    // the btlr text direction in the A1 cell was lost on ODF import and
+    // export.
+    uno::Reference<text::XTextTablesSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XNameAccess> xTables = xSupplier->getTextTables();
+    uno::Reference<text::XTextTable> xTable(xTables->getByName("Table1"), uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xA1(xTable->getCellByName("A1"), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(text::WritingMode2::BT_LR, getProperty<sal_Int16>(xA1, "WritingMode"));
+
+    uno::Reference<beans::XPropertySet> xB1(xTable->getCellByName("B1"), uno::UNO_QUERY);
+    auto nActual = getProperty<sal_Int16>(xB1, "WritingMode");
+    CPPUNIT_ASSERT(nActual == text::WritingMode2::LR_TB || nActual == text::WritingMode2::CONTEXT);
+
+    uno::Reference<beans::XPropertySet> xC1(xTable->getCellByName("C1"), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(text::WritingMode2::TB_RL, getProperty<sal_Int16>(xC1, "WritingMode"));
+}
+
 DECLARE_ODFEXPORT_TEST(testFdo86963, "fdo86963.odt")
 {
     // Export of this document failed with beans::UnknownPropertyException.
diff --git a/sw/source/filter/xml/xmlexpit.cxx b/sw/source/filter/xml/xmlexpit.cxx
index b04d8f085e13..1c0a3a9d609b 100644
--- a/sw/source/filter/xml/xmlexpit.cxx
+++ b/sw/source/filter/xml/xmlexpit.cxx
@@ -46,6 +46,7 @@
 #include <editeng/formatbreakitem.hxx>
 #include <editeng/keepitem.hxx>
 #include <editeng/brushitem.hxx>
+#include <editeng/frmdiritem.hxx>
 #include <fmtpdsc.hxx>
 #include <fmtornt.hxx>
 #include <fmtfsize.hxx>
@@ -202,16 +203,41 @@ void SvXMLExportItemMapper::exportXML( const SvXMLExport& rExport,
     }
     else if( 0 == (rEntry.nMemberId & MID_SW_FLAG_ELEMENT_ITEM_EXPORT) )
     {
-        OUString aValue;
-        if( QueryXMLValue(rItem, aValue,
-                          static_cast< sal_uInt16 >(
-                                          rEntry.nMemberId & MID_SW_FLAG_MASK ),
-                             rUnitConverter ) )
+        bool bDone = false;
+        switch (rItem.Which())
         {
-            const OUString sName(
-                rNamespaceMap.GetQNameByKey( rEntry.nNameSpace,
-                                             GetXMLToken(rEntry.eLocalName)));
-            rAttrList.AddAttribute( sName, aValue );
+            case RES_FRAMEDIR:
+            {
+                // Write bt-lr to the extension namespace, handle other values
+                // below.
+                auto pDirection = static_cast<const SvxFrameDirectionItem*>(&rItem);
+                if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
+                    && pDirection->GetValue() == SvxFrameDirection::Vertical_LR_BT)
+                {
+                    const OUString sName(rNamespaceMap.GetQNameByKey(
+                        XML_NAMESPACE_LO_EXT, GetXMLToken(XML_WRITING_MODE)));
+                    rAttrList.AddAttribute(sName, GetXMLToken(XML_BT_LR));
+                }
+                if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
+                    || pDirection->GetValue() == SvxFrameDirection::Vertical_LR_BT)
+                    bDone = true;
+                break;
+            }
+        }
+
+        if (!bDone)
+        {
+            OUString aValue;
+            if( QueryXMLValue(rItem, aValue,
+                              static_cast< sal_uInt16 >(
+                                              rEntry.nMemberId & MID_SW_FLAG_MASK ),
+                                 rUnitConverter ) )
+            {
+                const OUString sName(
+                    rNamespaceMap.GetQNameByKey( rEntry.nNameSpace,
+                                                 GetXMLToken(rEntry.eLocalName)));
+                rAttrList.AddAttribute( sName, aValue );
+            }
         }
     }
 }
diff --git a/sw/source/filter/xml/xmlimpit.cxx b/sw/source/filter/xml/xmlimpit.cxx
index 184a6e6194f1..9eb42a3b785a 100644
--- a/sw/source/filter/xml/xmlimpit.cxx
+++ b/sw/source/filter/xml/xmlimpit.cxx
@@ -42,6 +42,7 @@
 #include <editeng/formatbreakitem.hxx>
 #include <editeng/keepitem.hxx>
 #include <editeng/brushitem.hxx>
+#include <editeng/frmdir.hxx>
 #include <fmtpdsc.hxx>
 #include <fmtornt.hxx>
 #include <fmtfsize.hxx>
@@ -53,6 +54,7 @@
 #include "xmlithlp.hxx"
 #include <com/sun/star/uno/Any.hxx>
 #include <osl/diagnose.h>
+#include <sal/log.hxx>
 
 using ::editeng::SvxBorderLine;
 using namespace ::com::sun::star;
@@ -906,18 +908,29 @@ bool SvXMLImportItemMapper::PutXMLValue(
 
         case RES_FRAMEDIR:
         {
-            const XMLPropertyHandler* pWritingModeHandler =
-                XMLPropertyHandlerFactory::CreatePropertyHandler(
-                    XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT );
-            if( pWritingModeHandler != nullptr )
+            if (IsXMLToken(rValue, XML_BT_LR))
             {
+                // Read bt-lr from the extension namespace, handle other values
+                // below.
                 Any aAny;
-                bOk = pWritingModeHandler->importXML( rValue, aAny,
-                                                      rUnitConverter );
-                if( bOk )
-                    bOk = rItem.PutValue( aAny, 0 );
+                aAny <<= static_cast<sal_uInt16>(SvxFrameDirection::Vertical_LR_BT);
+                bOk = rItem.PutValue(aAny, 0);
+            }
+            else
+            {
+                const XMLPropertyHandler* pWritingModeHandler =
+                    XMLPropertyHandlerFactory::CreatePropertyHandler(
+                        XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT );
+                if( pWritingModeHandler != nullptr )
+                {
+                    Any aAny;
+                    bOk = pWritingModeHandler->importXML( rValue, aAny,
+                                                          rUnitConverter );
+                    if( bOk )
+                        bOk = rItem.PutValue( aAny, 0 );
 
-                delete pWritingModeHandler;
+                    delete pWritingModeHandler;
+                }
             }
         }
         break;
diff --git a/sw/source/filter/xml/xmlitemm.cxx b/sw/source/filter/xml/xmlitemm.cxx
index 417e0a5d96c1..0757bdd57604 100644
--- a/sw/source/filter/xml/xmlitemm.cxx
+++ b/sw/source/filter/xml/xmlitemm.cxx
@@ -282,6 +282,7 @@ SvXMLItemMapEntry const aXMLTableCellItemMap[] =
 
     // RES_FRAMEDIR
     MAP_ENTRY( STYLE, WRITING_MODE, RES_FRAMEDIR, 0 ),
+    MAP_ENTRY( LO_EXT, WRITING_MODE, RES_FRAMEDIR, 0 ),
 
     M_END
 };
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 8a40bdc11fc9..b83298799104 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -2186,6 +2186,7 @@ namespace xmloff { namespace token {
 
         TOKEN( "rl-tb",                           XML_RL_TB ),
         TOKEN( "tb-lr",                           XML_TB_LR ),
+        TOKEN( "bt-lr",                           XML_BT_LR ),
         TOKEN( "lr",                              XML_LR ),
         TOKEN( "rl",                              XML_RL ),
         TOKEN( "tb",                              XML_TB ),
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index c57d2b646ddc..d6d832ea5343 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -2088,6 +2088,7 @@ stock-gain-marker
 stock-range-line
 rl-tb
 tb-lr
+bt-lr
 lr
 rl
 tb
commit abbff658a428aee5105bcb0143c4819eb309e9b8
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Tue Feb 12 17:50:59 2019 +0100
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Mon Jul 1 16:56:11 2019 +0200

    sw btlr writing mode layout: implement unmapping of this direction
    
    Fix various cases which trigger this warning:
    
    warn:legacy.osl:10975:10975:sw/source/core/txtnode/swfont.cxx:427: Unsupported direction
    
    Which means that we tried to work with a VCL direction of 900, without
    passing around the btlr flag accordingly.
    
    Change-Id: I96374fc949f60e8324c5a84de48b710b6461bafb
    Reviewed-on: https://gerrit.libreoffice.org/67746
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    (cherry picked from commit cb9f393a5293c0f39d76b703154f8392c45f8047)

diff --git a/sw/source/core/inc/frmtool.hxx b/sw/source/core/inc/frmtool.hxx
index 3496b6d5eb59..a031d11ea136 100644
--- a/sw/source/core/inc/frmtool.hxx
+++ b/sw/source/core/inc/frmtool.hxx
@@ -108,12 +108,13 @@ void SwAlignGrfRect( SwRect *pGrfRect, const OutputDevice &rOut );
  * @param[in]   rFont            font object of actual text, which specify the border
  * @param[in]   rPaintArea       rectangle area in which line portion takes place
  * @param[in]   bVerticalLayout  corresponding text frame verticality
+ * @param[in]   bVerticalLayoutLRBT corresponding text frame verticality (LRBT subset)
  * @param[in]   bJoinWithPrev    leave border with which actual border joins to the previous portion
  * @param[in]   bJoinWithNext    leave border with which actual border joins to the next portion
 **/
-void PaintCharacterBorder(
-    const SwFont& rFont, const SwRect& rPaintArea, const bool bVerticalLayout,
-    const bool bJoinWithPrev, const bool bJoinWithNext );
+void PaintCharacterBorder(const SwFont& rFont, const SwRect& rPaintArea, const bool bVerticalLayout,
+                          const bool bVerticalLayoutLRBT, const bool bJoinWithPrev,
+                          const bool bJoinWithNext);
 
 // get Fly, if no List is given use the current shell
 // Implementation in feshview.cxx
diff --git a/sw/source/core/inc/swfont.hxx b/sw/source/core/inc/swfont.hxx
index cc299a1d3fba..2e1369450c89 100644
--- a/sw/source/core/inc/swfont.hxx
+++ b/sw/source/core/inc/swfont.hxx
@@ -46,7 +46,7 @@ const sal_Unicode CH_TAB   = '\t';  // \t
 const sal_Unicode CH_PAR    = 0xB6;     // paragraph
 const sal_Unicode CH_BULLET = 0xB7;     // centered dot
 
-sal_uInt16 UnMapDirection( sal_uInt16 nDir, const bool bVertFormat );
+sal_uInt16 UnMapDirection( sal_uInt16 nDir, const bool bVertFormat, const bool bVertFormatLRBT );
 
 class SwSubFont : public SvxFont
 {
@@ -282,7 +282,8 @@ public:
     FontWeight GetWeight() const { return m_aSub[m_nActual].GetWeight(); }
     FontEmphasisMark GetEmphasisMark() const
         { return m_aSub[m_nActual].GetEmphasisMark(); }
-    sal_uInt16 GetOrientation( const bool bVertLayout = false ) const;
+    sal_uInt16 GetOrientation(const bool bVertLayout = false,
+                              const bool bVertFormatLRBT = false) const;
 
     const OUString& GetName( const SwFontScript nWhich ) const
         { return m_aSub[nWhich].GetFamilyName(); }
@@ -339,10 +340,14 @@ public:
     const boost::optional<editeng::SvxBorderLine>& GetLeftBorder() const { return m_aLeftBorder; }
 
     // Get absolute border correspond to the layout verticality and orientation.
-    const boost::optional<editeng::SvxBorderLine>& GetAbsTopBorder( const bool bVertLayout ) const;
-    const boost::optional<editeng::SvxBorderLine>& GetAbsBottomBorder( const bool bVertLayout ) const;
-    const boost::optional<editeng::SvxBorderLine>& GetAbsRightBorder( const bool bVertLayout ) const;
-    const boost::optional<editeng::SvxBorderLine>& GetAbsLeftBorder( const bool bVertLayout ) const;
+    const boost::optional<editeng::SvxBorderLine>&
+    GetAbsTopBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const;
+    const boost::optional<editeng::SvxBorderLine>&
+    GetAbsBottomBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const;
+    const boost::optional<editeng::SvxBorderLine>&
+    GetAbsRightBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const;
+    const boost::optional<editeng::SvxBorderLine>&
+    GetAbsLeftBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const;
 
     void SetTopBorderDist( const sal_uInt16 nTopDist );
     void SetBottomBorderDist( const sal_uInt16 nBottomDist );
@@ -376,9 +381,12 @@ public:
      *
      * @param[in]   bVertLayout true, if the container layout is vertical
      *                          false, otherwise
+     * @param[in]   bVertLayoutLRBT true if the container layout is vertical
+     *                          (bottom to top, left to right), false otherwise
      * @return      absolute location
     **/
-    SvxShadowLocation GetAbsShadowLocation( const bool bVertLayout ) const;
+    SvxShadowLocation GetAbsShadowLocation(const bool bVertLayout,
+                                           const bool bVertLayoutLRBT) const;
 
     /**
      * Calculate the shadow space on the specified side dependent from
@@ -388,12 +396,14 @@ public:
      * @param[in]   nShadow     specify the side
      * @param[in]   bVertLayout true, if the container layout is vertical
      *                          false, otherwise
+     * @param[in]   bVertLayoutLRBT true if the container layout is vertical
+     *                          (bottom to top, left to right), false otherwise
      * @param[in]   bSkipLeft   relative left shadow space is skipped
      * @param[in]   bSkipRight  relative right shadow space is skipped
      * @return      the shadow space
     **/
     sal_uInt16 CalcShadowSpace(
-        const SvxShadowItemSide nShadow, const bool bVertLayout,
+        const SvxShadowItemSide nShadow, const bool bVertLayout, const bool bVertLayoutLRBT,
         const bool bSkipLeft, const bool bSkipRight ) const;
 
     void dumpAsXml( xmlTextWriterPtr writer ) const;
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index 1ec4e721b3ea..afbd85ffcea1 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -4696,6 +4696,7 @@ void PaintCharacterBorder(
     const SwFont& rFont,
     const SwRect& rPaintArea,
     const bool bVerticalLayout,
+    const bool bVerticalLayoutLRBT,
     const bool bJoinWithPrev,
     const bool bJoinWithNext )
 {
@@ -4707,7 +4708,7 @@ void PaintCharacterBorder(
     bool bLeft = true;
     bool bRight = true;
 
-    switch( rFont.GetOrientation(bVerticalLayout) )
+    switch (rFont.GetOrientation(bVerticalLayout, bVerticalLayoutLRBT))
     {
         case 0 :
             bLeft = !bJoinWithPrev;
@@ -4731,7 +4732,7 @@ void PaintCharacterBorder(
     {
         const SvxShadowItem aShadow(
             0, &rFont.GetShadowColor(), rFont.GetShadowWidth(),
-            rFont.GetAbsShadowLocation(bVerticalLayout));
+            rFont.GetAbsShadowLocation(bVerticalLayout, bVerticalLayoutLRBT));
 
         if( aShadow.GetLocation() != SvxShadowLocation::NONE )
         {
@@ -4744,10 +4745,19 @@ void PaintCharacterBorder(
         basegfx::utils::createScaleTranslateB2DHomMatrix(
             aAlignedRect.Width(), aAlignedRect.Height(),
             aAlignedRect.Left(), aAlignedRect.Top()));
-    const svx::frame::Style aStyleTop(bTop ? rFont.GetAbsTopBorder(bVerticalLayout).get_ptr() : nullptr, 1.0);
-    const svx::frame::Style aStyleRight(bRight ? rFont.GetAbsRightBorder(bVerticalLayout).get_ptr() : nullptr, 1.0);
-    const svx::frame::Style aStyleBottom(bBottom ? rFont.GetAbsBottomBorder(bVerticalLayout).get_ptr() : nullptr, 1.0);
-    const svx::frame::Style aStyleLeft(bLeft ? rFont.GetAbsLeftBorder(bVerticalLayout).get_ptr() : nullptr, 1.0);
+    const svx::frame::Style aStyleTop(
+        bTop ? rFont.GetAbsTopBorder(bVerticalLayout, bVerticalLayoutLRBT).get_ptr() : nullptr,
+        1.0);
+    const svx::frame::Style aStyleRight(
+        bRight ? rFont.GetAbsRightBorder(bVerticalLayout, bVerticalLayoutLRBT).get_ptr() : nullptr,
+        1.0);
+    const svx::frame::Style aStyleBottom(
+        bBottom ? rFont.GetAbsBottomBorder(bVerticalLayout, bVerticalLayoutLRBT).get_ptr()
+                : nullptr,
+        1.0);
+    const svx::frame::Style aStyleLeft(
+        bLeft ? rFont.GetAbsLeftBorder(bVerticalLayout, bVerticalLayoutLRBT).get_ptr() : nullptr,
+        1.0);
     drawinglayer::primitive2d::Primitive2DContainer aBorderLineTarget;
 
     aBorderLineTarget.append(
diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx
index 29ef2035bee7..6714588fed8f 100644
--- a/sw/source/core/text/inftxt.cxx
+++ b/sw/source/core/text/inftxt.cxx
@@ -778,10 +778,19 @@ void SwTextPaintInfo::CalcRect( const SwLinePortion& rPor,
         const bool bJoinWithNext =
             static_cast<const SwTextPortion&>(rPor).GetJoinBorderWithNext();
         const bool bIsVert = GetTextFrame()->IsVertical();
-        aRect.Top(aRect.Top() + GetFont()->CalcShadowSpace(SvxShadowItemSide::TOP, bIsVert, bJoinWithPrev, bJoinWithNext ));
-        aRect.Bottom(aRect.Bottom() - GetFont()->CalcShadowSpace(SvxShadowItemSide::BOTTOM, bIsVert, bJoinWithPrev, bJoinWithNext ));
-        aRect.Left(aRect.Left() + GetFont()->CalcShadowSpace(SvxShadowItemSide::LEFT, bIsVert, bJoinWithPrev, bJoinWithNext ));
-        aRect.Right(aRect.Right() - GetFont()->CalcShadowSpace(SvxShadowItemSide::RIGHT, bIsVert, bJoinWithPrev, bJoinWithNext ));
+        const bool bIsVertLRBT = GetTextFrame()->IsVertLRBT();
+        aRect.Top(aRect.Top()
+                  + GetFont()->CalcShadowSpace(SvxShadowItemSide::TOP, bIsVert, bIsVertLRBT,
+                                               bJoinWithPrev, bJoinWithNext));
+        aRect.Bottom(aRect.Bottom()
+                     - GetFont()->CalcShadowSpace(SvxShadowItemSide::BOTTOM, bIsVert, bIsVertLRBT,
+                                                  bJoinWithPrev, bJoinWithNext));
+        aRect.Left(aRect.Left()
+                   + GetFont()->CalcShadowSpace(SvxShadowItemSide::LEFT, bIsVert, bIsVertLRBT,
+                                                bJoinWithPrev, bJoinWithNext));
+        aRect.Right(aRect.Right()
+                    - GetFont()->CalcShadowSpace(SvxShadowItemSide::RIGHT, bIsVert, bIsVertLRBT,
+                                                 bJoinWithPrev, bJoinWithNext));
     }
 
     if ( pRect )
@@ -1263,9 +1272,9 @@ void SwTextPaintInfo::DrawBorder( const SwLinePortion &rPor ) const
     CalcRect( rPor, &aDrawArea );
     if ( aDrawArea.HasArea() )
     {
-        PaintCharacterBorder(
-            *m_pFnt, aDrawArea, GetTextFrame()->IsVertical(),
-            rPor.GetJoinBorderWithPrev(), rPor.GetJoinBorderWithNext());
+        PaintCharacterBorder(*m_pFnt, aDrawArea, GetTextFrame()->IsVertical(),
+                             GetTextFrame()->IsVertLRBT(), rPor.GetJoinBorderWithPrev(),
+                             rPor.GetJoinBorderWithNext());
     }
 }
 
diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx
index 175821ab90ef..9a9ebafcbdaa 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -253,18 +253,20 @@ struct CalcLinePosData
     vcl::Font& rFont;
     TextFrameIndex const nCnt;
     const bool bSwitchH2V;
+    const bool bSwitchH2VLRBT;
     const bool bSwitchL2R;
     long const nHalfSpace;
     long* const pKernArray;
     const bool bBidiPor;
 
     CalcLinePosData( SwDrawTextInfo& _rInf, vcl::Font& _rFont,
-          TextFrameIndex const _nCnt, const bool _bSwitchH2V, const bool _bSwitchL2R,
+          TextFrameIndex const _nCnt, const bool _bSwitchH2V, const bool _bSwitchH2VLRBT, const bool _bSwitchL2R,
                       long _nHalfSpace, long* _pKernArray, const bool _bBidiPor) :
         rInf( _rInf ),
         rFont( _rFont ),
         nCnt( _nCnt ),
         bSwitchH2V( _bSwitchH2V ),
+        bSwitchH2VLRBT( _bSwitchH2VLRBT ),
         bSwitchL2R( _bSwitchL2R ),
         nHalfSpace( _nHalfSpace ),
         pKernArray( _pKernArray ),
@@ -295,8 +297,9 @@ static void lcl_calcLinePos( const CalcLinePosData &rData,
     sal_Int32 nKernStart = nStart ? rData.pKernArray[sal_Int32(nStart) - 1] : 0;
     sal_Int32 nKernEnd = rData.pKernArray[sal_Int32(nEnd) - 1];
 
-    const sal_uInt16 nDir = rData.bBidiPor ? 1800 :
-        UnMapDirection( rData.rFont.GetOrientation(), rData.bSwitchH2V );
+    const sal_uInt16 nDir = rData.bBidiPor ? 1800
+                                           : UnMapDirection(rData.rFont.GetOrientation(),
+                                                            rData.bSwitchH2V, rData.bSwitchH2VLRBT);
 
     switch ( nDir )
     {
@@ -933,6 +936,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
     // line of the ExtendedAttributeSets will appear in the font color first
 
     const bool bSwitchH2V = rInf.GetFrame() && rInf.GetFrame()->IsVertical();
+    const bool bSwitchH2VLRBT = rInf.GetFrame() && rInf.GetFrame()->IsVertLRBT();
     const bool bSwitchL2R = rInf.GetFrame() && rInf.GetFrame()->IsRightToLeft() &&
                             ! rInf.IsIgnoreFrameRTL();
     const ComplexTextLayoutFlags nMode = rInf.GetOut().GetLayoutMode();
@@ -1721,11 +1725,10 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                         Point aEnd;
                         long nKernVal = pKernArray[sal_Int32(rInf.GetLen()) - 1];
 
-                        const sal_uInt16 nDir = bBidiPor ?
-                                        1800 :
-                                        UnMapDirection(
-                                            GetFont().GetOrientation(),
-                                            bSwitchH2V );
+                        const sal_uInt16 nDir = bBidiPor
+                                                    ? 1800
+                                                    : UnMapDirection(GetFont().GetOrientation(),
+                                                                     bSwitchH2V, bSwitchH2VLRBT);
 
                         switch ( nDir )
                         {
@@ -1775,9 +1778,9 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                 // anything to do?
                 if (rInf.GetWrong() || rInf.GetGrammarCheck() || rInf.GetSmartTags())
                 {
-                    CalcLinePosData aCalcLinePosData(rInf, GetFont(),
-                            nCnt, bSwitchH2V, bSwitchL2R,
-                            nHalfSpace, pKernArray.get(), bBidiPor);
+                    CalcLinePosData aCalcLinePosData(rInf, GetFont(), nCnt, bSwitchH2V,
+                                                     bSwitchH2VLRBT, bSwitchL2R, nHalfSpace,
+                                                     pKernArray.get(), bBidiPor);
 
                     SwForbidden aForbidden;
                     // draw line for smart tag data
diff --git a/sw/source/core/txtnode/swfont.cxx b/sw/source/core/txtnode/swfont.cxx
index a7797412e484..d00a96817a28 100644
--- a/sw/source/core/txtnode/swfont.cxx
+++ b/sw/source/core/txtnode/swfont.cxx
@@ -126,9 +126,9 @@ void SwFont::SetLeftBorder( const editeng::SvxBorderLine* pLeftBorder )
 }
 
 const boost::optional<editeng::SvxBorderLine>&
-SwFont::GetAbsTopBorder( const bool bVertLayout ) const
+SwFont::GetAbsTopBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const
 {
-    switch( GetOrientation( bVertLayout ) )
+    switch (GetOrientation(bVertLayout, bVertLayoutLRBT))
     {
         case 0 :
             return m_aTopBorder;
@@ -150,9 +150,9 @@ SwFont::GetAbsTopBorder( const bool bVertLayout ) const
 }
 
 const boost::optional<editeng::SvxBorderLine>&
-SwFont::GetAbsBottomBorder( const bool bVertLayout ) const
+SwFont::GetAbsBottomBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const
 {
-    switch( GetOrientation( bVertLayout ) )
+    switch (GetOrientation(bVertLayout, bVertLayoutLRBT))
     {
         case 0 :
             return m_aBottomBorder;
@@ -174,9 +174,9 @@ SwFont::GetAbsBottomBorder( const bool bVertLayout ) const
 }
 
 const boost::optional<editeng::SvxBorderLine>&
-SwFont::GetAbsLeftBorder( const bool bVertLayout ) const
+SwFont::GetAbsLeftBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const
 {
-    switch( GetOrientation( bVertLayout ) )
+    switch (GetOrientation(bVertLayout, bVertLayoutLRBT))
     {
         case 0 :
             return m_aLeftBorder;
@@ -198,9 +198,9 @@ SwFont::GetAbsLeftBorder( const bool bVertLayout ) const
 }
 
 const boost::optional<editeng::SvxBorderLine>&
-SwFont::GetAbsRightBorder( const bool bVertLayout ) const
+SwFont::GetAbsRightBorder(const bool bVertLayout, const bool bVertLayoutLRBT) const
 {
-    switch( GetOrientation( bVertLayout ) )
+    switch (GetOrientation(bVertLayout, bVertLayoutLRBT))
     {
         case 0 :
             return m_aRightBorder;
@@ -221,10 +221,11 @@ SwFont::GetAbsRightBorder( const bool bVertLayout ) const
     }
 }
 
-SvxShadowLocation SwFont::GetAbsShadowLocation( const bool bVertLayout ) const
+SvxShadowLocation SwFont::GetAbsShadowLocation(const bool bVertLayout,
+                                               const bool bVertLayoutLRBT) const
 {
     SvxShadowLocation aLocation = SvxShadowLocation::NONE;
-    switch( GetOrientation( bVertLayout ) )
+    switch (GetOrientation(bVertLayout, bVertLayoutLRBT))
     {
         case 0:
             aLocation = m_aShadowLocation;
@@ -303,13 +304,13 @@ SvxShadowLocation SwFont::GetAbsShadowLocation( const bool bVertLayout ) const
     return aLocation;
 }
 
-sal_uInt16 SwFont::CalcShadowSpace(
-        const SvxShadowItemSide nShadow, const bool bVertLayout,
-        const bool bSkipLeft, const bool bSkipRight ) const
+sal_uInt16 SwFont::CalcShadowSpace(const SvxShadowItemSide nShadow, const bool bVertLayout,
+                                   const bool bVertLayoutLRBT, const bool bSkipLeft,
+                                   const bool bSkipRight) const
 {
     sal_uInt16 nSpace = 0;
-    const sal_uInt16 nOrient = GetOrientation( bVertLayout );
-    const SvxShadowLocation aLoc = GetAbsShadowLocation( bVertLayout );
+    const sal_uInt16 nOrient = GetOrientation(bVertLayout, bVertLayoutLRBT);
+    const SvxShadowLocation aLoc = GetAbsShadowLocation(bVertLayout, bVertLayoutLRBT);
     switch( nShadow )
     {
         case SvxShadowItemSide::TOP:
@@ -394,8 +395,22 @@ static sal_uInt16 MapDirection(sal_uInt16 nDir, const bool bVertFormat, const bo
 
 // maps the absolute direction set at the font to its logical counterpart
 // in the rotated environment
-sal_uInt16 UnMapDirection( sal_uInt16 nDir, const bool bVertFormat )
+sal_uInt16 UnMapDirection(sal_uInt16 nDir, const bool bVertFormat, const bool bVertFormatLRBT)
 {
+    if (bVertFormatLRBT)
+    {
+        switch (nDir)
+        {
+            case 900:
+                nDir = 0;
+                break;
+            default:
+                SAL_WARN("sw.core", "unsupported direction for VertLRBT");
+                break;
+        }
+        return nDir;
+    }
+
     if ( bVertFormat )
     {
         switch ( nDir )
@@ -419,9 +434,9 @@ sal_uInt16 UnMapDirection( sal_uInt16 nDir, const bool bVertFormat )
     return nDir;
 }
 
-sal_uInt16 SwFont::GetOrientation( const bool bVertFormat ) const
+sal_uInt16 SwFont::GetOrientation(const bool bVertFormat, const bool bVertFormatLRBT) const
 {
-    return UnMapDirection( m_aSub[m_nActual].GetOrientation(), bVertFormat );
+    return UnMapDirection(m_aSub[m_nActual].GetOrientation(), bVertFormat, bVertFormatLRBT);
 }
 
 void SwFont::SetVertical(sal_uInt16 nDir, const bool bVertFormat, const bool bVertLayoutLRBT)
@@ -1383,8 +1398,14 @@ void SwSubFont::CalcEsc( SwDrawTextInfo const & rInf, Point& rPos )
 {
     long nOfst;
 
-    const sal_uInt16 nDir = UnMapDirection(
-                GetOrientation(), rInf.GetFrame() && rInf.GetFrame()->IsVertical() );
+    bool bVert = false;
+    bool bVertLRBT = false;
+    if (rInf.GetFrame())
+    {
+        bVert = rInf.GetFrame()->IsVertical();
+        bVertLRBT = rInf.GetFrame()->IsVertLRBT();
+    }
+    const sal_uInt16 nDir = UnMapDirection(GetOrientation(), bVert, bVertLRBT);
 
     switch ( GetEscapement() )
     {
@@ -1454,9 +1475,14 @@ void SwDrawTextInfo::Shift( sal_uInt16 nDir )
     const bool bBidiPor = ( GetFrame() && GetFrame()->IsRightToLeft() ) !=
                           ( ComplexTextLayoutFlags::Default != ( ComplexTextLayoutFlags::BiDiRtl & GetpOut()->GetLayoutMode() ) );
 
-    nDir = bBidiPor ?
-            1800 :
-            UnMapDirection( nDir, GetFrame() && GetFrame()->IsVertical() );
+    bool bVert = false;
+    bool bVertLRBT = false;
+    if (GetFrame())
+    {
+        bVert = GetFrame()->IsVertical();
+        bVertLRBT = GetFrame()->IsVertLRBT();
+    }
+    nDir = bBidiPor ? 1800 : UnMapDirection(nDir, bVert, bVertLRBT);
 
     switch ( nDir )
     {
commit 0ef51db33170f90062868622f1a0cc5d8b6ebad1
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Tue Feb 12 16:38:47 2019 +0100
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Mon Jul 1 16:56:03 2019 +0200

    sw btlr writing mode: implement initial layout
    
    The bulk of this commit is reasonably straightforward, the interesting parts
    are:
    
    - SwFrame::CheckDir() is where the layout reads the doc model, i.e. sets the
      new SwFrame::mbVertLRBT.
    
    - We had 3 text directions previously: horizontal, vertical (implicitly RL) and
      vertical LR (implicitly TB). This adds a 4th text direction for the LRBT case.
    
    - SwTextFrame::SwitchHorizontalToVertical() is responsible for re-locating the
      origo of a string to be painted from the top left to the bottom left corner (in
      addition to the height/width swap that's done for all vertical directions).
    
    - Finally MapDirection() is the place where we map Writer's new btlr mode (with
      no character rotation) to VCL's 900 (90 degrees) rotated direction.
    
    No functional changes intended for existing text directions. Lots of places are
    still not yet adapted, but this is good enough to paint a single word in a
    table cell at the correct position with the correct direction.
    
    Change-Id: I465c62db6562d8a2be140c3d37473e590830139e
    Reviewed-on: https://gerrit.libreoffice.org/67740
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit e8b9572bf89f55463f2c879a401ed62efc165d95)

diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index 0a9a1ea823c0..5f9a2cfcf886 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -404,6 +404,7 @@ protected:
     bool mbVertical    : 1;
 
     bool mbVertLR      : 1;
+    bool mbVertLRBT    : 1;
 
     bool mbValidLineNum  : 1;
     bool mbFixSize       : 1;
@@ -602,6 +603,7 @@ public:
 
     inline bool IsVertical() const;
     inline bool IsVertLR() const;
+    inline bool IsVertLRBT() const;
 
     void SetDerivedVert( bool bNew ){ mbDerivedVert = bNew; }
     void SetInvalidVert( bool bNew) { mbInvalidVert = bNew; }
@@ -955,6 +957,10 @@ inline bool SwFrame::IsVertLR() const
 {
     return mbVertLR;
 }
+inline bool SwFrame::IsVertLRBT() const
+{
+    return mbVertLRBT;
+}
 inline bool SwFrame::IsRightToLeft() const
 {
     if( mbInvalidR2L )
@@ -1312,21 +1318,23 @@ struct SwRectFnCollection
 typedef SwRectFnCollection* SwRectFn;
 
 // This class allows to use proper methods regardless of orientation (LTR/RTL, horizontal or vertical)
-extern SwRectFn fnRectHori, fnRectVert, fnRectVertL2R;
+extern SwRectFn fnRectHori, fnRectVert, fnRectVertL2R, fnRectVertL2RB2T;
 class SwRectFnSet {
 public:
     explicit SwRectFnSet(const SwFrame *pFrame)
         : m_bVert(pFrame->IsVertical())
         , m_bVertL2R(pFrame->IsVertLR())
+        , m_bVertL2RB2T(pFrame->IsVertLRBT())
     {
-        m_fnRect = m_bVert ? (m_bVertL2R ? fnRectVertL2R : fnRectVert) : fnRectHori;
+        m_fnRect = m_bVert ? (m_bVertL2R ? (m_bVertL2RB2T ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert) : fnRectHori;
     }
 
     void Refresh(const SwFrame *pFrame)
     {
         m_bVert = pFrame->IsVertical();
         m_bVertL2R = pFrame->IsVertLR();
-        m_fnRect = m_bVert ? (m_bVertL2R ? fnRectVertL2R : fnRectVert) : fnRectHori;
+        m_bVertL2RB2T = pFrame->IsVertLRBT();
+        m_fnRect = m_bVert ? (m_bVertL2R ? (m_bVertL2RB2T ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert) : fnRectHori;
     }
 
     bool IsVert() const    { return m_bVert; }
@@ -1395,6 +1403,7 @@ public:
 private:
     bool m_bVert;
     bool m_bVertL2R;
+    bool m_bVertL2RB2T;
     SwRectFn m_fnRect;
 };
 
diff --git a/sw/source/core/inc/swfont.hxx b/sw/source/core/inc/swfont.hxx
index ff0e5d8a0b9d..cc299a1d3fba 100644
--- a/sw/source/core/inc/swfont.hxx
+++ b/sw/source/core/inc/swfont.hxx
@@ -215,7 +215,8 @@ public:
     void SetOverColor( const Color &rColor ) { m_aOverColor = rColor; }
     inline void SetStrikeout( const FontStrikeout eStrikeout );
     inline void SetOutline( const bool bOutline );
-           void SetVertical( sal_uInt16 nDir, const bool bVertLayout = false );
+    void SetVertical(sal_uInt16 nDir, const bool bVertLayout = false,
+                     const bool bVertLayoutLRBT = false);
     inline void SetShadow( const bool bShadow );
     inline void SetAutoKern( FontKerning nAutoKern );
     inline void SetTransparent( const bool bTrans );
diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx
index 871f77a2f96e..b670adf668ae 100644
--- a/sw/source/core/layout/calcmove.cxx
+++ b/sw/source/core/layout/calcmove.cxx
@@ -928,7 +928,7 @@ void SwLayoutFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
     const SwLayNotify aNotify( this );
     bool bVert = IsVertical();
 
-    SwRectFn fnRect = ( IsNeighbourFrame() == bVert )? fnRectHori : ( IsVertLR() ? fnRectVertL2R : fnRectVert );
+    SwRectFn fnRect = ( IsNeighbourFrame() == bVert )? fnRectHori : ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert );
 
     std::unique_ptr<SwBorderAttrAccess> pAccess;
     const SwBorderAttrs*pAttrs = nullptr;
diff --git a/sw/source/core/layout/colfrm.cxx b/sw/source/core/layout/colfrm.cxx
index efb776eaaef4..195bbc9535bd 100644
--- a/sw/source/core/layout/colfrm.cxx
+++ b/sw/source/core/layout/colfrm.cxx
@@ -300,7 +300,7 @@ void SwLayoutFrame::AdjustColumns( const SwFormatCol *pAttr, bool bAdjustAttribu
 
     const bool bVert = IsVertical();
 
-    SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
+    SwRectFn fnRect = bVert ? ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
 
     //If we have a pointer or we have to configure an attribute, we set the
     //column widths in any case. Otherwise we check if a configuration is needed.
diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx
index 5bdb1de12702..849457f2b3ea 100644
--- a/sw/source/core/layout/findfrm.cxx
+++ b/sw/source/core/layout/findfrm.cxx
@@ -1476,6 +1476,7 @@ void SwFrame::SetDirFlags( bool bVert )
             {
                 mbVertical = pAsk->IsVertical();
                 mbVertLR  = pAsk->IsVertLR();
+                mbVertLRBT = pAsk->IsVertLRBT();
 
                 if ( !pAsk->mbInvalidVert )
                     mbInvalidVert = false;
diff --git a/sw/source/core/layout/newfrm.cxx b/sw/source/core/layout/newfrm.cxx
index adc2909c38a5..0971c2d95a8e 100644
--- a/sw/source/core/layout/newfrm.cxx
+++ b/sw/source/core/layout/newfrm.cxx
@@ -224,9 +224,70 @@ static SwRectFnCollection aVerticalLeftToRight = {
     /*.fnSetTopAndHeight =*/&SwRect::SetLeftAndWidth
 };
 
+/**
+ * This is the same as horizontal, but rotated counter-clockwise by 90 degrees.
+ * This means logical top is physical right, bottom is left, left is top,
+ * finally right is bottom.
+ */
+static SwRectFnCollection aVerticalLeftToRightBottomToTop = {
+    /*.fnGetTop =*/&SwRect::Right_,
+    /*.fnGetBottom =*/&SwRect::Left_,
+    /*.fnGetLeft =*/&SwRect::Top_,
+    /*.fnGetRight =*/&SwRect::Bottom_,
+    /*.fnGetWidth =*/&SwRect::Height_,
+    /*.fnGetHeight =*/&SwRect::Width_,
+    /*.fnGetPos =*/&SwRect::TopRight,
+    /*.fnGetSize =*/&SwRect::SwappedSize,
+
+    /*.fnSetTop =*/&SwRect::Right_,
+    /*.fnSetBottom =*/&SwRect::Left_,
+    /*.fnSetLeft =*/&SwRect::Top_,
+    /*.fnSetRight =*/&SwRect::Bottom_,
+    /*.fnSetWidth =*/&SwRect::Height_,
+    /*.fnSetHeight =*/&SwRect::Width_,
+
+    /*.fnSubTop =*/&SwRect::AddRight,
+    /*.fnAddBottom =*/&SwRect::SubLeft,
+    /*.fnSubLeft =*/&SwRect::SubTop,
+    /*.fnAddRight =*/&SwRect::AddBottom,
+    /*.fnAddWidth =*/&SwRect::AddHeight,
+    /*.fnAddHeight =*/&SwRect::AddWidth,
+
+    /*.fnSetPosX =*/&SwRect::SetPosY,
+    /*.fnSetPosY =*/&SwRect::SetPosX,
+
+    /*.fnGetTopMargin =*/&SwFrame::GetRightMargin,
+    /*.fnGetBottomMargin =*/&SwFrame::GetLeftMargin,
+    /*.fnGetLeftMargin =*/&SwFrame::GetTopMargin,
+    /*.fnGetRightMargin =*/&SwFrame::GetBottomMargin,
+    /*.fnSetXMargins =*/&SwFrame::SetTopBottomMargins,
+    /*.fnSetYMargins =*/&SwFrame::SetLeftRightMargins,
+    /*.fnGetPrtTop =*/&SwFrame::GetPrtRight,
+    /*.fnGetPrtBottom =*/&SwFrame::GetPrtLeft,
+    /*.fnGetPrtLeft =*/&SwFrame::GetPrtTop,
+    /*.fnGetPrtRight =*/&SwFrame::GetPrtBottom,
+    /*.fnTopDist =*/&SwRect::GetRightDistance,
+    /*.fnBottomDist =*/&SwRect::GetLeftDistance,
+    /*.fnLeftDist =*/&SwRect::GetTopDistance,
+    /*.fnRightDist =*/&SwRect::GetBottomDistance,
+    /*.fnSetLimit =*/&SwFrame::SetMinLeft,
+    /*.fnOverStep =*/&SwRect::OverStepLeft,
+
+    /*.fnSetPos =*/&SwRect::SetUpperRightCorner,
+    /*.fnMakePos =*/&SwFrame::MakeLeftPos,
+    /*.fnXDiff =*/&FirstMinusSecond,
+    /*.fnYDiff =*/&FirstMinusSecond,
+    /*.fnXInc =*/&SwIncrement,
+    /*.fnYInc =*/&SwIncrement,
+
+    /*.fnSetLeftAndWidth =*/&SwRect::SetTopAndHeight,
+    /*.fnSetTopAndHeight =*/&SwRect::SetRightAndWidth
+};
+
 SwRectFn fnRectHori = &aHorizontal;
 SwRectFn fnRectVert = &aVertical;
 SwRectFn fnRectVertL2R = &aVerticalLeftToRight;
+SwRectFn fnRectVertL2RB2T = &aVerticalLeftToRightBottomToTop;
 
 // #i65250#
 sal_uInt32 SwFrameAreaDefinition::mnLastFrameId=0;
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index f116678d0b59..1ec4e721b3ea 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -1256,7 +1256,7 @@ static void lcl_CalcBorderRect( SwRect &rRect, const SwFrame *pFrame,
         rRect = pFrame->getFramePrintArea();
         rRect.Pos() += pFrame->getFrameArea().Pos();
 
-        SwRectFn fnRect = pFrame->IsVertical() ? ( pFrame->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
+        SwRectFn fnRect = pFrame->IsVertical() ? ( pFrame->IsVertLR() ? (pFrame->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
 
         const SvxBoxItem &rBox = rAttrs.GetBox();
         const bool bTop = 0 != (pFrame->*fnRect->fnGetTopMargin)();
@@ -5220,7 +5220,7 @@ void SwLayoutFrame::PaintColLines( const SwRect &rRect, const SwFormatCol &rForm
     if ( !pCol || !pCol->IsColumnFrame() )
         return;
 
-    SwRectFn fnRect = pCol->IsVertical() ? ( pCol->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
+    SwRectFn fnRect = pCol->IsVertical() ? ( pCol->IsVertLR() ? (pCol->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
 
     SwRect aLineRect = getFramePrintArea();
     aLineRect += getFrameArea().Pos();
diff --git a/sw/source/core/layout/ssfrm.cxx b/sw/source/core/layout/ssfrm.cxx
index f309693befc2..46cf019acbc4 100644
--- a/sw/source/core/layout/ssfrm.cxx
+++ b/sw/source/core/layout/ssfrm.cxx
@@ -584,7 +584,7 @@ const SwRect SwFrame::GetPaintArea() const
     // Cell frames may not leave their upper:
     SwRect aRect = IsRowFrame() ? GetUpper()->getFrameArea() : getFrameArea();
     const bool bVert = IsVertical();
-    SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
+    SwRectFn fnRect = bVert ? ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
     long nRight = (aRect.*fnRect->fnGetRight)();
     long nLeft  = (aRect.*fnRect->fnGetLeft)();
     const SwFrame* pTmp = this;
@@ -675,7 +675,7 @@ const SwRect SwFrame::GetPaintArea() const
 const SwRect SwFrame::UnionFrame( bool bBorder ) const
 {
     bool bVert = IsVertical();
-    SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
+    SwRectFn fnRect = bVert ? ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
     long nLeft = (getFrameArea().*fnRect->fnGetLeft)();
     long nWidth = (getFrameArea().*fnRect->fnGetWidth)();
     long nPrtLeft = (getFramePrintArea().*fnRect->fnGetLeft)();
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index a5a589bae4a0..c2d1bf5d62ae 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -300,6 +300,7 @@ SwFrame::SwFrame( SwModify *pMod, SwFrame* pSib )
     mbDerivedVert(false),
     mbVertical(false),
     mbVertLR(false),
+    mbVertLRBT(false),
     mbValidLineNum(false),
     mbFixSize(false),
     mbCompletePaint(true),
@@ -357,6 +358,11 @@ void SwFrame::CheckDir( SvxFrameDirection nDir, bool bVert, bool bOnlyBiDi, bool
                 mbVertLR = false;
             else if(SvxFrameDirection::Vertical_LR_TB==nDir)
                 mbVertLR = true;
+            else if (nDir == SvxFrameDirection::Vertical_LR_BT)
+            {
+                mbVertLR = true;
+                mbVertLRBT = true;
+            }
         }
     }
     else
@@ -712,7 +718,7 @@ Size SwFrame::ChgSize( const Size& aNewSize )
     if ( GetUpper() )
     {
         bool bNeighb = IsNeighbourFrame();
-        SwRectFn fnRect = IsVertical() == bNeighb ? fnRectHori : ( IsVertLR() ? fnRectVertL2R : fnRectVert );
+        SwRectFn fnRect = IsVertical() == bNeighb ? fnRectHori : ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert );
         SwRect aNew( Point(0,0), aNewSize );
 
         {
@@ -1319,9 +1325,9 @@ void SwLayoutFrame::Paste( SwFrame* pParent, SwFrame* pSibling)
     if ( IsHeaderFrame() || IsFooterFrame() )
         fnRect = fnRectHori;
     else if ( IsCellFrame() || IsColumnFrame() )
-        fnRect = GetUpper()->IsVertical() ? fnRectHori : ( GetUpper()->IsVertLR() ? fnRectVertL2R : fnRectVert );
+        fnRect = GetUpper()->IsVertical() ? fnRectHori : ( GetUpper()->IsVertLR() ? (GetUpper()->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert );
     else
-        fnRect = GetUpper()->IsVertical() ? ( GetUpper()->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
+        fnRect = GetUpper()->IsVertical() ? ( GetUpper()->IsVertLR() ? (GetUpper()->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
 
     if( (getFrameArea().*fnRect->fnGetWidth)() != (pParent->getFramePrintArea().*fnRect->fnGetWidth)())
         InvalidateSize_();
@@ -3364,7 +3370,7 @@ void SwLayoutFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBord
     const sal_uInt16 nLower = bHideWhitespace ? 0 : pAttrs->CalcBottom();
 
     const bool bVert = IsVertical() && !IsPageFrame();
-    SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
+    SwRectFn fnRect = bVert ? ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
     if ( !isFramePrintAreaValid() )
     {
         setFramePrintAreaValid(true);
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index f964a13f858f..964d42e75eda 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -205,7 +205,8 @@ bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFo
     {
         assert(m_pMergedPara);
         m_pTextNode = m_pMergedPara->pFirstNode;
-        InitFontAndAttrHandler(*m_pMergedPara->pParaPropsNode, *m_pTextNode, m_pMergedPara->mergedText, nullptr);
+        InitFontAndAttrHandler(*m_pMergedPara->pParaPropsNode, *m_pTextNode,
+                               m_pMergedPara->mergedText, nullptr, nullptr);
     }
 
     // reset font to its original state
@@ -339,7 +340,8 @@ bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
         // items at all; it can only apply a previously effective item.
         // So do this by recreating the font from scratch.
         // Apply new para items:
-        InitFontAndAttrHandler(*m_pMergedPara->pParaPropsNode, *newPos.first, m_pMergedPara->mergedText, nullptr);
+        InitFontAndAttrHandler(*m_pMergedPara->pParaPropsNode, *newPos.first,
+                               m_pMergedPara->mergedText, nullptr, nullptr);
         // reset to next
         m_pTextNode = newPos.first;
         m_nStartIndex = 0;
@@ -361,7 +363,8 @@ bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
                 m_pTextNode = newPos.first;
                 // sw_redlinehide: hope it's okay to use the current text node
                 // here; the AttrHandler shouldn't care about non-char items
-                InitFontAndAttrHandler(*m_pMergedPara->pParaPropsNode, *m_pTextNode, m_pMergedPara->mergedText, nullptr);
+                InitFontAndAttrHandler(*m_pMergedPara->pParaPropsNode, *m_pTextNode,
+                                       m_pMergedPara->mergedText, nullptr, nullptr);
             }
         }
         if (m_pMergedPara || m_pTextNode->GetpSwpHints())
diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index 2dddd1265d8c..dd3a755c7bfd 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -67,7 +67,8 @@ private:
     void SetFnt( SwFont* pNew ) { m_pFont = pNew; }
     void InitFontAndAttrHandler(
         SwTextNode const& rPropsNode, SwTextNode const& rTextNode,
-        OUString const& rText, bool const* pbVertLayout);
+        OUString const& rText, bool const* pbVertLayout,
+        bool const* pbVertLayoutLRBT);
 
 protected:
     void Chg( SwTextAttr const *pHt );
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index b2ef40409422..f26f3c67ab42 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -305,7 +305,8 @@ void SwAttrIter::InitFontAndAttrHandler(
         SwTextNode const& rPropsNode,
         SwTextNode const& rTextNode,
         OUString const& rText,
-        bool const*const pbVertLayout)
+        bool const*const pbVertLayout,
+        bool const*const pbVertLayoutLRBT)
 {
     // Build a font matching the default paragraph style:
     SwFontAccess aFontAccess( &rPropsNode.GetAnyFormatColl(), m_pViewShell );
@@ -326,7 +327,10 @@ void SwAttrIter::InitFontAndAttrHandler(
     // if it's a re-init, the vert flag never changes
     if (pbVertLayout ? *pbVertLayout : m_aAttrHandler.IsVertLayout())
     {
-        m_pFont->SetVertical( m_pFont->GetOrientation(), true );
+        bool bVertLayoutLRBT = false;
+        if (pbVertLayoutLRBT)
+            bVertLayoutLRBT = *pbVertLayoutLRBT;
+        m_pFont->SetVertical(m_pFont->GetOrientation(), true, bVertLayoutLRBT);
     }
 
     // Initialize the default attribute of the attribute handler
@@ -383,6 +387,7 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
 
     // set font to vertical if frame layout is vertical
     bool bVertLayout = false;
+    bool bVertLayoutLRBT = false;
     bool bRTL = false;
     if ( pFrame )
     {
@@ -390,6 +395,10 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
         {
             bVertLayout = true;
         }
+        if (pFrame->IsVertLRBT())
+        {
+            bVertLayoutLRBT = true;
+        }
         bRTL = pFrame->IsRightToLeft();
         m_pMergedPara = pFrame->GetMergedPara();
     }
@@ -403,7 +412,8 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
             m_pMergedPara ? *m_pMergedPara->pParaPropsNode : rTextNode,
             rTextNode,
             m_pMergedPara ? m_pMergedPara->mergedText : rTextNode.GetText(),
-            & bVertLayout);
+            & bVertLayout,
+            & bVertLayoutLRBT);
 
     m_nStartIndex = m_nEndIndex = m_nPosition = m_nChgCnt = 0;
     m_nPropFont = 0;
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index e7f221c705e9..f02eed653ba5 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -512,6 +512,21 @@ void SwTextFrame::SwitchHorizontalToVertical( SwRect& rRect ) const
  */
 void SwTextFrame::SwitchHorizontalToVertical( Point& rPoint ) const
 {
+    if (IsVertLRBT())
+    {
+        // The horizontal origo is the top left corner, the LRBT origo is the
+        // bottom left corner. Finally x and y has to be swapped.
+        SAL_WARN_IF(!mbIsSwapped, "sw.core",
+                    "SwTextFrame::SwitchHorizontalToVertical, IsVertLRBT, not swapped");
+        Point aPoint(rPoint);
+        rPoint.setX(getFrameArea().Left() + (aPoint.Y() - getFrameArea().Top()));
+        // This would be bottom - x delta, but bottom is top + height, finally
+        // width (and not height), as it's swapped.
+        rPoint.setY(getFrameArea().Top() + getFrameArea().Width()
+                    - (aPoint.X() - getFrameArea().Left()));
+        return;
+    }
+
     // calc offset inside frame
     const long nOfstX = rPoint.X() - getFrameArea().Left();
     const long nOfstY = rPoint.Y() - getFrameArea().Top();
diff --git a/sw/source/core/txtnode/swfont.cxx b/sw/source/core/txtnode/swfont.cxx
index 5e8ea0651c38..a7797412e484 100644
--- a/sw/source/core/txtnode/swfont.cxx
+++ b/sw/source/core/txtnode/swfont.cxx
@@ -364,14 +364,17 @@ sal_uInt16 SwFont::CalcShadowSpace(
 }
 
 // maps directions for vertical layout
-static sal_uInt16 MapDirection( sal_uInt16 nDir, const bool bVertFormat )
+static sal_uInt16 MapDirection(sal_uInt16 nDir, const bool bVertFormat, const bool bVertFormatLRBT)
 {
     if ( bVertFormat )
     {
         switch ( nDir )
         {
         case 0 :
-            nDir = 2700;
+            if (bVertFormatLRBT)
+                nDir = 900;
+            else
+                nDir = 2700;
             break;
         case 900 :
             nDir = 0;
@@ -421,10 +424,10 @@ sal_uInt16 SwFont::GetOrientation( const bool bVertFormat ) const
     return UnMapDirection( m_aSub[m_nActual].GetOrientation(), bVertFormat );
 }
 
-void SwFont::SetVertical( sal_uInt16 nDir, const bool bVertFormat )
+void SwFont::SetVertical(sal_uInt16 nDir, const bool bVertFormat, const bool bVertLayoutLRBT)
 {
     // map direction if frame has vertical layout
-    nDir = MapDirection( nDir, bVertFormat );
+    nDir = MapDirection(nDir, bVertFormat, bVertLayoutLRBT);
 
     if( nDir != m_aSub[SwFontScript::Latin].GetOrientation() )
     {
commit 5cccc917a1163f924cbc9d109a777803dd270aa9
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Tue Feb 12 14:36:43 2019 +0100
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Mon Jul 1 16:55:57 2019 +0200

    sw btlr writing mode: implement UNO API
    
    The custom code in SwXCell::setPropertyValue() was added in commit
    5a5597655a4bf12e4ca07c9c2b6f6221e217f080 (tentative fix for fdo#30474#,
    2010-11-26), which suggests that not handling all constants from
    text::WritingMode2 was not intentional.
    
    Later the writerfilter side (which is the only client of this hidden
    property) was adapted to use text::WritingMode2, so do the same here.
    This implicitly adds support for the new text::WritingMode2::BT_LR as
    well.
    
    Change-Id: I37d8eaa844847cb19e7503b2d973069f9895e6bc
    Reviewed-on: https://gerrit.libreoffice.org/67730
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 052b5d375307245223e694bb835d86966c370d3b)

diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx
index cc2950a4b875..57c462d7d122 100644
--- a/editeng/source/items/frmitems.cxx
+++ b/editeng/source/items/frmitems.cxx
@@ -3867,6 +3867,9 @@ bool SvxFrameDirectionItem::PutValue( const css::uno::Any& rVal,
             case text::WritingMode2::TB_LR:
                 SetValue( SvxFrameDirection::Vertical_LR_TB );
                 break;
+            case text::WritingMode2::BT_LR:
+                SetValue( SvxFrameDirection::Vertical_LR_BT );
+                break;
             case text::WritingMode2::PAGE:
                 SetValue( SvxFrameDirection::Environment );
                 break;
@@ -3900,6 +3903,9 @@ bool SvxFrameDirectionItem::QueryValue( css::uno::Any& rVal,
         case SvxFrameDirection::Vertical_LR_TB:
             nVal = text::WritingMode2::TB_LR;
             break;
+        case SvxFrameDirection::Vertical_LR_BT:
+            nVal = text::WritingMode2::BT_LR;
+            break;
         case SvxFrameDirection::Environment:
             nVal = text::WritingMode2::PAGE;
             break;
diff --git a/sw/source/core/unocore/unotbl.cxx b/sw/source/core/unocore/unotbl.cxx
index 44b4282c99a6..986869e29e0d 100644
--- a/sw/source/core/unocore/unotbl.cxx
+++ b/sw/source/core/unocore/unotbl.cxx
@@ -1020,14 +1020,8 @@ void SwXCell::setPropertyValue(const OUString& rPropertyName, const uno::Any& aV
     if(rPropertyName == "FRMDirection")
     {
         SvxFrameDirection eDir = SvxFrameDirection::Environment;
-        try
-        {
-            const std::array<SvxFrameDirection, 3> vDirs = { SvxFrameDirection::Horizontal_LR_TB,  SvxFrameDirection::Horizontal_RL_TB, SvxFrameDirection::Vertical_RL_TB };
-            eDir = vDirs.at(aValue.get<sal_Int32>());
-        } catch(std::out_of_range &) {
-            SAL_WARN("sw.uno", "unknown direction code, maybe it's a bitfield");
-        }
         SvxFrameDirectionItem aItem(eDir, RES_FRAMEDIR);
+        aItem.PutValue(aValue, 0);
         pBox->GetFrameFormat()->SetFormatAttr(aItem);
     }
     else if(rPropertyName == "TableRedlineParams")
commit 512dcf886d7cdc067d7c91fa2e38b54eba099732
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Tue Feb 12 12:04:19 2019 +0100
Commit:     Miklos Vajna <vmiklos at collabora.com>
CommitDate: Mon Jul 1 16:55:51 2019 +0200

    sw btlr wrting mode: implement document model
    
    btLr is not a writing mode that would be used by any natural language,
    the reason it makes sense to support this is that the Word UI makes it
    easy to rotate text 90 degrees counter-clockwise for Latin (lrtb) text,
    which then triggers this feature. This is common in the first column of
    tables to create text that looks like a row header.
    
    An import-time workaround to handle <w:textDirection w:val="btLr"/> was
    added in commit c2d1ab73165d5fa19037e6244b1d634c6c455efc (tentative fix
    for fdo#30474#, 2010-11-26), but rotating text at a text portion level
    has various unwanted side effects, just counting my own fixes, I had 7
    workarounds on top of that workaround to hide problems where the root
    cause is this missing writing direction in sw core.
    
    This commit just extends the sw core doc model, everything else is to be
    done in follow-up commits.
    
    Change-Id: I89e02cd4b40de78699dbf14885fc128e870de3b8
    Reviewed-on: https://gerrit.libreoffice.org/67717
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit db346dde6179e7414289681d91b153a6ed259d05)

diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx
index f21950827dd7..cc2950a4b875 100644
--- a/editeng/source/items/frmitems.cxx
+++ b/editeng/source/items/frmitems.cxx
@@ -3917,4 +3917,15 @@ bool SvxFrameDirectionItem::QueryValue( css::uno::Any& rVal,
     return bRet;
 }
 
+void SvxFrameDirectionItem::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+    xmlTextWriterStartElement(pWriter, BAD_CAST("SvxFrameDirectionItem"));
+    xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nWhich"),
+                                BAD_CAST(OString::number(Which()).getStr()));
+    xmlTextWriterWriteAttribute(
+        pWriter, BAD_CAST("m_nValue"),
+        BAD_CAST(OString::number(static_cast<sal_Int16>(GetValue())).getStr()));
+    xmlTextWriterEndElement(pWriter);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/editeng/frmdir.hxx b/include/editeng/frmdir.hxx
index b0ada2cce30a..f8801cc77020 100644
--- a/include/editeng/frmdir.hxx
+++ b/include/editeng/frmdir.hxx
@@ -48,7 +48,10 @@ enum class SvxFrameDirection
     Vertical_LR_TB = css::text::WritingMode2::TB_LR,
 
     /** Use the value from the environment, can only be used in frames. */
-    Environment = css::text::WritingMode2::CONTEXT
+    Environment = css::text::WritingMode2::CONTEXT,
+
+    /** Vertical, from bottom to top, from left to right. */
+    Vertical_LR_BT = css::text::WritingMode2::BT_LR,
 };
 
 const char* getFrmDirResId(size_t nIndex);
diff --git a/include/editeng/frmdiritem.hxx b/include/editeng/frmdiritem.hxx
index 929cbc5b0b3e..1ec32483077d 100644
--- a/include/editeng/frmdiritem.hxx
+++ b/include/editeng/frmdiritem.hxx
@@ -58,6 +58,7 @@ public:
     }
     SvxFrameDirectionItem(SvxFrameDirectionItem const &) = default;
         // SfxPoolItem copy function dichotomy
+    void dumpAsXml(struct _xmlTextWriter* pWriter) const override;
 };
 
 #endif // INCLUDED_EDITENG_FRMDIRITEM_HXX
diff --git a/offapi/com/sun/star/text/WritingMode2.idl b/offapi/com/sun/star/text/WritingMode2.idl
index 4f1800b06a0d..1edc467e7a0f 100644
--- a/offapi/com/sun/star/text/WritingMode2.idl
+++ b/offapi/com/sun/star/text/WritingMode2.idl
@@ -76,6 +76,13 @@ published constants WritingMode2
     /** obtain actual writing mode from the context of the object.
     */
     const short CONTEXT = 4;
+
+    /** text within a line is written bottom-to-top. Lines and blocks are
+        placed left-to-right.
+
+        @since LibreOffice 6.3
+     */
+    const short BT_LR = 5;
 };
 
 


More information about the Libreoffice-commits mailing list