File bsc1182969.patch of Package libreoffice.20342

From 0fa895203fc42b506ea0c5e230821cf8f4804c29 Mon Sep 17 00:00:00 2001
From: Mike Kaganski <mike.kaganski@collabora.com>
Date: Sun, 6 Jun 2021 21:50:53 +0300
Subject: [PATCH] Fix and unify the two methods that get scaled text size

GetTextFitToSizeScale and SdrTextObj::GetFontScaleY both didn't
initialize outliners properly, and thus returned wrong results.

Change-Id: I6fe63c51ed838a0d0fafdfa03597cac97ce29831
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116765
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit a1ae30166e92a0a40dff06740f0bb8e9ee63f70a)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116704
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>

Unify some code managing coordinates depending on text direction

Change-Id: I12163e83a6a4d4e7cb85eed690b787c47ee2e7e5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115107
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116861
Tested-by: Mike Kaganski <mike.kaganski@collabora.com>

UITest: introduce guarded context managers

They should be used wherever we need to make sure to execute
some action in tests regardless of the assertion success. They
follow their plain counterparts, and execute finalizing code
at all outcomes. This e.g. allows to assert when a dialog is
open, and have it properly closed on failure, so that the test
is not left in hung state.

Only two wrappers are implemented now: load_file and
execute_dialog_through_action.

sc/qa/uitest/chart/chartLegend.py is updated to use them.

Change-Id: Ib9cf44304f0d3ab8fa3377922ed36d2d866031b0
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116692
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116867
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>

editengine-columns: Create document model and dialog page

Change-Id: I056aad9474ca18134d1f1686a53618cc9ab3d525
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116038
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116868
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>

editengine-columns: ODF support [API CHANGE]

This uses existing ODF markup, as used by Writer's text frame:
style::columns child element of style:graphic-properties, its
fo:column-count and fo:column-gap attributes. No ODF extension
is required.

Since currently only columns with same width and spacing are
implemented, without additional settings, style:column child
elements are exported, but ignored on import.

This adds new property to css::drawing::TextProperties service:
TextColumns (of type css::text::XTextColumns).

Change-Id: I7e63293e5814b281ceec8a9632e696322d3629e8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116035
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116871
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>

editengine-columns: Implement layout

This changes the way how different parts access positions of lines and
paragraphs. Now there is ImpEditEngine::IterateLineAreas, which performs
uniform iteration over all ParaPortions and lines in order, calling a
user-provided callback function for each portion and line; it passes
all information about current portion, line, area, and column to the
callback, and checks the return from the callback, to decide if it needs
to continue iteration (in case when callback indicated that if doesn't
need further data), and if it needs calling the callback for the rest of
current portion's lines.

This allows to have the code that calculates and iterates dimensions of
lines in one central place, without the need to have duplicating logic
in several places.

One important exception is ImpEditEngine::Paint, which iterates without
ImpEditEngine::IterateLineAreas, because it does many atomic paint
operations in different points of iteration process, and implementing
ImpEditEngine::IterateLineAreas to call callback in the required places
would require increased complexity, which is left for a future change.
To make that possible, ImpEditEngine::IterFlag should be extended to
indicate additional requirements.

Note that in fact, ImpEditEngine::Paint was taken as the model for
implementation of ImpEditEngine::IterateLineAreas, with its detailed
handling of all the vertical offsets like additional line spacing and
interparagraph spacings that depend on context.

The notable result of the centralization of the iteration code is slight
change of heights reported by ImpEditEngine::CalcTextHeight. Previously
it simply added all pre-calculated heights of portions, and not taking
into account all the spacing handling that ImpEditEngine::Paint did,
which was inconsistent (calculated height was different from painted
height). Now ImpEditEngine::CalcTextHeight should provide more accurate
results, which required small changes in the unit tests.

Change-Id: I33cbb978deb974b314d36fda8674186a03991107
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116034
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116876
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>

editengine-columns: PPTX support (tdf#118458)

The unit tests that used to check the workaround using tables to
emulate columns (implemented in tdf#120028) are changed to test
import of the columns.

This reverts some commits related to the mentioned workaround,
namely aef569ed83a3ccc02639e5b2a1c7cc131ba262fc,
       c50ae6a282ed83762bf634fed5c91033eb305c88,
       7b64bd90637a6722438bf873b1ded74ab3424c46,
       33696b2820ce3c8b21b753d2c2bf92345ecb9276,
       99dff69b561a8fe2d9437e6aa67a9581a6666f41.

Change-Id: I97693ad4a981780e822070938992f274920df5a8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116738
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116881
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>

This API change is since 7-2.

Change-Id: I5ca672a9c67f9a7082ef72c63b388c953d77c22c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116843
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 25bd0c7ddf0b45c8628f0c7b1b57d3eb428bf1e5)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116710
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>

svxcore: provide UNO constructor for com.sun.star.text.TextColumns

This allows to create it e.g. in Basic macros using CreateUnoService

Change-Id: I949d3b92c83cd9e763244f70b22f0f367b93cb48
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116970
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 01379acedcdad4fc08c61b73b8500e758b88d5ae)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116903
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
---
 .../xshape/data/reference/tdf90839-1.xml      |  74 +--
 .../xshape/data/reference/tdf90839-2.xml      |  64 +-
 .../xshape/data/reference/tdf90839-3.xml      |  64 +-
 .../xshape/data/reference/tdf90839-4.xml      |  64 +-
 cui/Library_cui.mk                            |   1 +
 cui/UIConfig_cui.mk                           |   1 +
 cui/source/factory/dlgfact.cxx                |   5 +
 cui/source/inc/TextColumnsPage.hxx            |  40 ++
 cui/source/tabpages/TextColumnsPage.cxx       |  82 +++
 cui/source/tabpages/textanim.cxx              |   2 +
 cui/uiconfig/ui/textcolumnstabpage.ui         | 111 ++++
 cui/uiconfig/ui/textdialog.ui                 |  48 ++
 editeng/source/editeng/editeng.cxx            |  31 +-
 editeng/source/editeng/impedit.cxx            | 131 ++--
 editeng/source/editeng/impedit.hxx            |  72 ++-
 editeng/source/editeng/impedit2.cxx           | 573 +++++++++++-------
 editeng/source/editeng/impedit3.cxx           | 516 ++++++++--------
 editeng/source/editeng/impedit4.cxx           |   4 +-
 editeng/source/outliner/outlin2.cxx           |  10 +
 include/editeng/editeng.hxx                   |   4 +
 include/editeng/outliner.hxx                  |   4 +
 include/oox/ppt/pptimport.hxx                 |   2 -
 include/oox/ppt/pptshape.hxx                  |   3 +-
 include/svl/solar.hrc                         |   2 +-
 include/svx/SvxXTextColumns.hxx               |  22 +
 include/svx/dialogs.hrc                       |   1 +
 include/svx/strings.hrc                       |   2 +
 include/svx/svddef.hxx                        |   8 +-
 include/svx/svdotext.hxx                      |   9 +-
 include/svx/unoshprp.hxx                      |   6 +-
 .../com/sun/star/drawing/TextProperties.idl   |   8 +
 oox/inc/drawingml/table/tableproperties.hxx   |   3 -
 oox/inc/drawingml/textbodyproperties.hxx      |   2 -
 .../drawingml/table/tableproperties.cxx       |  61 +-
 .../drawingml/textbodypropertiescontext.cxx   |  14 +-
 oox/source/export/drawingml.cxx               |  24 +-
 oox/source/ppt/pptimport.cxx                  |   1 -
 oox/source/ppt/pptshape.cxx                   |  33 +-
 oox/source/ppt/slidepersist.cxx               |  33 +-
 oox/source/token/properties.txt               |   1 +
 sc/qa/uitest/chart/chartLegend.py             | 183 +++---
 sc/qa/unit/filters-test.cxx                   |   2 +-
 sd/qa/uitest/impress_tests/tdf91762.py        |   8 +-
 .../uitest/impress_tests/textColumnsDialog.py |  53 ++
 sd/qa/unit/data/pptx/tdf120028b.pptx          | Bin 29838 -> 0 bytes
 sd/qa/unit/data/xml/n593612_0.xml             |   4 +-
 sd/qa/unit/data/xml/n758621_1.xml             |   4 +-
 sd/qa/unit/export-tests-ooxml2.cxx            | 125 +++-
 sd/qa/unit/export-tests.cxx                   |  69 +++
 sd/qa/unit/import-tests.cxx                   |  96 +--
 sd/qa/unit/layout-tests.cxx                   | 107 +++-
 sd/qa/unit/misc-tests.cxx                     |  49 ++
 sd/qa/unit/tiledrendering/LOKitSearchTest.cxx |   4 +-
 sd/source/core/stlsheet.cxx                   |  13 +
 svx/Library_svxcore.mk                        |   1 +
 .../sdr/properties/attributeproperties.cxx    |   3 +-
 .../sdr/properties/captionproperties.cxx      |   1 +
 .../sdr/properties/circleproperties.cxx       |   1 +
 .../sdr/properties/connectorproperties.cxx    |   1 +
 .../sdr/properties/customshapeproperties.cxx  |   2 +-
 .../sdr/properties/graphicproperties.cxx      |   2 +-
 .../sdr/properties/measureproperties.cxx      |   1 +
 svx/source/sdr/properties/textproperties.cxx  |   7 +
 svx/source/svdraw/svdattr.cxx                 |   9 +
 svx/source/svdraw/svdotext.cxx                |  97 ++-
 svx/source/svdraw/svdotextdecomposition.cxx   |   4 +
 svx/source/svdraw/svdotxed.cxx                |   1 +
 svx/source/svdraw/svdoutl.cxx                 |   1 +
 svx/source/unodraw/SvxXTextColumns.cxx        | 334 ++++++++++
 svx/source/unodraw/unomod.cxx                 |   5 +
 svx/source/unodraw/unopool.cxx                |   7 +
 svx/source/unodraw/unoshape.cxx               |  48 +-
 svx/util/svxcore.component                    |   4 +
 sw/inc/unomap.hxx                             |  11 -
 sw/inc/unosett.hxx                            |  65 --
 sw/source/core/layout/atrfrm.cxx              | 116 +++-
 sw/source/core/unocore/unocoll.cxx            |   3 +-
 sw/source/core/unocore/unomap.cxx             |  17 -
 sw/source/core/unocore/unomap1.cxx            |   6 -
 sw/source/core/unocore/unosett.cxx            | 291 ---------
 .../sheet/xsheetannotationshapesupplier.cxx   |   2 +-
 uitest/uitest/uihelper/guarded.py             |  51 ++
 .../draw/XMLShapePropertySetContext.cxx       |   3 +
 xmloff/source/draw/sdpropls.cxx               |   6 +
 xmloff/source/text/XMLTextColumnsExport.cxx   |   2 +
 xmloff/source/text/txtprhdl.cxx               |   3 +
 89 files changed, 2462 insertions(+), 1496 deletions(-)
 create mode 100644 cui/source/inc/TextColumnsPage.hxx
 create mode 100644 cui/source/tabpages/TextColumnsPage.cxx
 create mode 100644 cui/uiconfig/ui/textcolumnstabpage.ui
 create mode 100644 include/svx/SvxXTextColumns.hxx
 create mode 100644 sd/qa/uitest/impress_tests/textColumnsDialog.py
 create mode 100644 svx/source/unodraw/SvxXTextColumns.cxx
 create mode 100644 uitest/uitest/uihelper/guarded.py

diff --git a/chart2/qa/extras/xshape/data/reference/tdf90839-1.xml b/chart2/qa/extras/xshape/data/reference/tdf90839-1.xml
index 2af62c344940..3586969602c1 100644
--- a/chart2/qa/extras/xshape/data/reference/tdf90839-1.xml
+++ b/chart2/qa/extras/xshape/data/reference/tdf90839-1.xml
@@ -175,15 +175,15 @@
        <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
       </Transformation>
      </XShape>
-     <XShape positionX="8394" positionY="4386" sizeX="9180" sizeY="8065" type="com.sun.star.drawing.GroupShape">
+     <XShape positionX="8395" positionY="4386" sizeX="9178" sizeY="8066" type="com.sun.star.drawing.GroupShape">
       <XShapes>
-       <XShape positionX="8394" positionY="4386" sizeX="9180" sizeY="8065" type="com.sun.star.drawing.GroupShape">
+       <XShape positionX="8395" positionY="4386" sizeX="9178" sizeY="8066" type="com.sun.star.drawing.GroupShape">
         <XShapes>
-         <XShape positionX="8394" positionY="4386" sizeX="9180" sizeY="8065" type="com.sun.star.drawing.GroupShape" name="CID/D=0:CS=0:CT=0:Series=0:DataLabels=">
+         <XShape positionX="8395" positionY="4386" sizeX="9178" sizeY="8066" type="com.sun.star.drawing.GroupShape" name="CID/D=0:CS=0:CT=0:Series=0:DataLabels=">
           <XShapes>
-           <XShape positionX="16434" positionY="9300" sizeX="1140" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=0">
+           <XShape positionX="16433" positionY="9300" sizeX="1140" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=0">
             <XShapes>
-             <XShape positionX="16434" positionY="9300" sizeX="1140" sizeY="849" type="com.sun.star.drawing.TextShape" text="Yellow&#10;33%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="16433" positionY="9300" sizeX="1140" sizeY="850" type="com.sun.star.drawing.TextShape" text="Yellow&#10;33%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -192,21 +192,21 @@
               <LineStart/>
               <LineEnd/>
               <Transformation>
-               <Line1 column1="1141.000000" column2="0.000000" column3="16434.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="9300.000000"/>
+               <Line1 column1="1141.000000" column2="0.000000" column3="16433.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="9300.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
-             <Line1 column1="1141.000000" column2="0.000000" column3="16434.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="9300.000000"/>
+             <Line1 column1="1141.000000" column2="0.000000" column3="16433.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="9300.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="10197" positionY="11602" sizeX="928" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=1">
+           <XShape positionX="10198" positionY="11602" sizeX="928" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=1">
             <XShapes>
-             <XShape positionX="10197" positionY="11602" sizeX="928" sizeY="849" type="com.sun.star.drawing.TextShape" text="Black&#10;28%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="10198" positionY="11602" sizeX="928" sizeY="850" type="com.sun.star.drawing.TextShape" text="Black&#10;28%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -215,21 +215,21 @@
               <LineStart/>
               <LineEnd/>
               <Transformation>
-               <Line1 column1="929.000000" column2="0.000000" column3="10197.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="11602.000000"/>
+               <Line1 column1="929.000000" column2="0.000000" column3="10198.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="11602.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
-             <Line1 column1="929.000000" column2="0.000000" column3="10197.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="11602.000000"/>
+             <Line1 column1="929.000000" column2="0.000000" column3="10198.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="11602.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="8394" positionY="7893" sizeX="1060" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=2">
+           <XShape positionX="8395" positionY="7893" sizeX="1060" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=2">
             <XShapes>
-             <XShape positionX="8394" positionY="7893" sizeX="1060" sizeY="849" type="com.sun.star.drawing.TextShape" text="Green&#10;6%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="8395" positionY="7893" sizeX="1060" sizeY="850" type="com.sun.star.drawing.TextShape" text="Green&#10;6%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -238,21 +238,21 @@
               <LineStart/>
               <LineEnd/>
               <Transformation>
-               <Line1 column1="1061.000000" column2="0.000000" column3="8394.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="7893.000000"/>
+               <Line1 column1="1061.000000" column2="0.000000" column3="8395.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="7893.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
-             <Line1 column1="1061.000000" column2="0.000000" column3="8394.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="7893.000000"/>
+             <Line1 column1="1061.000000" column2="0.000000" column3="8395.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="7893.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="10043" positionY="5033" sizeX="716" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=3">
+           <XShape positionX="10043" positionY="5033" sizeX="716" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=3">
             <XShapes>
-             <XShape positionX="10043" positionY="5033" sizeX="716" sizeY="849" type="com.sun.star.drawing.TextShape" text="Red&#10;19%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="10043" positionY="5033" sizeX="716" sizeY="850" type="com.sun.star.drawing.TextShape" text="Red&#10;19%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -262,20 +262,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="717.000000" column2="0.000000" column3="10043.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="5033.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="5033.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="717.000000" column2="0.000000" column3="10043.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="5033.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="5033.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="14035" positionY="4386" sizeX="1034" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=4">
+           <XShape positionX="14034" positionY="4386" sizeX="1034" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=4">
             <XShapes>
-             <XShape positionX="14035" positionY="4386" sizeX="1034" sizeY="849" type="com.sun.star.drawing.TextShape" text="White&#10;14%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="14034" positionY="4386" sizeX="1034" sizeY="850" type="com.sun.star.drawing.TextShape" text="White&#10;14%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="3889" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -284,36 +284,36 @@
               <LineStart/>
               <LineEnd/>
               <Transformation>
-               <Line1 column1="1035.000000" column2="0.000000" column3="14035.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="4386.000000"/>
+               <Line1 column1="1035.000000" column2="0.000000" column3="14034.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="4386.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
-             <Line1 column1="1035.000000" column2="0.000000" column3="14035.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="4386.000000"/>
+             <Line1 column1="1035.000000" column2="0.000000" column3="14034.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="4386.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
           </XShapes>
           <Transformation>
-           <Line1 column1="9181.000000" column2="0.000000" column3="8394.000000"/>
-           <Line2 column1="0.000000" column2="8066.000000" column3="4386.000000"/>
+           <Line1 column1="9179.000000" column2="0.000000" column3="8395.000000"/>
+           <Line2 column1="0.000000" column2="8067.000000" column3="4386.000000"/>
            <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
           </Transformation>
          </XShape>
         </XShapes>
         <Transformation>
-         <Line1 column1="9181.000000" column2="0.000000" column3="8394.000000"/>
-         <Line2 column1="0.000000" column2="8066.000000" column3="4386.000000"/>
+         <Line1 column1="9179.000000" column2="0.000000" column3="8395.000000"/>
+         <Line2 column1="0.000000" column2="8067.000000" column3="4386.000000"/>
          <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
         </Transformation>
        </XShape>
       </XShapes>
       <Transformation>
-       <Line1 column1="9181.000000" column2="0.000000" column3="8394.000000"/>
-       <Line2 column1="0.000000" column2="8066.000000" column3="4386.000000"/>
+       <Line1 column1="9179.000000" column2="0.000000" column3="8395.000000"/>
+       <Line2 column1="0.000000" column2="8067.000000" column3="4386.000000"/>
        <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
       </Transformation>
      </XShape>
diff --git a/chart2/qa/extras/xshape/data/reference/tdf90839-2.xml b/chart2/qa/extras/xshape/data/reference/tdf90839-2.xml
index c8afb487a4ae..0c1c1eba61b1 100644
--- a/chart2/qa/extras/xshape/data/reference/tdf90839-2.xml
+++ b/chart2/qa/extras/xshape/data/reference/tdf90839-2.xml
@@ -14,7 +14,7 @@
    <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
   </Transformation>
  </XShape>
- <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape" name="CID/D=0">
+ <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape" name="CID/D=0">
   <XShapes>
    <XShape positionX="8207" positionY="3821" sizeX="9721" sizeY="9721" type="com.sun.star.drawing.RectangleShape" name="MarkHandles" fontHeight="12.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
     <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
@@ -30,7 +30,7 @@
      <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
     </Transformation>
    </XShape>
-   <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.RectangleShape" name="PlotAreaIncludingAxes" fontHeight="12.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
+   <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.RectangleShape" name="PlotAreaIncludingAxes" fontHeight="12.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
     <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
     <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
     <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -40,11 +40,11 @@
     <LineEnd/>
     <Transformation>
      <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-     <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+     <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
      <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
     </Transformation>
    </XShape>
-   <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape">
+   <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape">
     <XShapes>
      <XShape positionX="8207" positionY="3819" sizeX="9721" sizeY="9723" type="com.sun.star.drawing.GroupShape">
       <XShapes>
@@ -175,15 +175,15 @@
        <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
       </Transformation>
      </XShape>
-     <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape">
+     <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape">
       <XShapes>
-       <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape">
+       <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape">
         <XShapes>
-         <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape" name="CID/D=0:CS=0:CT=0:Series=0:DataLabels=">
+         <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape" name="CID/D=0:CS=0:CT=0:Series=0:DataLabels=">
           <XShapes>
-           <XShape positionX="17907" positionY="9977" sizeX="6114" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=0">
+           <XShape positionX="17907" positionY="9977" sizeX="6114" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=0">
             <XShapes>
-             <XShape positionX="17907" positionY="9977" sizeX="6114" sizeY="849" type="com.sun.star.drawing.TextShape" text="Yellow - The color of sun and honey&#10;33%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="17907" positionY="9977" sizeX="6114" sizeY="850" type="com.sun.star.drawing.TextShape" text="Yellow - The color of sun and honey&#10;33%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -193,20 +193,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6115.000000" column2="0.000000" column3="17907.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="9977.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="9977.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6115.000000" column2="0.000000" column3="17907.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="9977.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="9977.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="3974" positionY="12784" sizeX="6220" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=1">
+           <XShape positionX="3974" positionY="12784" sizeX="6220" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=1">
             <XShapes>
-             <XShape positionX="3974" positionY="12784" sizeX="6220" sizeY="849" type="com.sun.star.drawing.TextShape" text="Black - The color of night and coffee&#10;28%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="10279" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="3974" positionY="12784" sizeX="6220" sizeY="850" type="com.sun.star.drawing.TextShape" text="Black - The color of night and coffee&#10;28%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="10279" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -216,20 +216,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6221.000000" column2="0.000000" column3="3974.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="12784.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="12784.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6221.000000" column2="0.000000" column3="3974.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="12784.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="12784.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="1910" positionY="7819" sizeX="6167" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=2">
+           <XShape positionX="1910" positionY="7819" sizeX="6167" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=2">
             <XShapes>
-             <XShape positionX="1910" positionY="7819" sizeX="6167" sizeY="849" type="com.sun.star.drawing.TextShape" text="Green - The color of grass and hope&#10;6%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="8225" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="1910" positionY="7819" sizeX="6167" sizeY="850" type="com.sun.star.drawing.TextShape" text="Green - The color of grass and hope&#10;6%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="8225" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -239,20 +239,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6168.000000" column2="0.000000" column3="1910.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="7819.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="7819.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6168.000000" column2="0.000000" column3="1910.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="7819.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="7819.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="3813" positionY="3994" sizeX="6035" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=3">
+           <XShape positionX="3813" positionY="3993" sizeX="6035" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=3">
             <XShapes>
-             <XShape positionX="3813" positionY="3994" sizeX="6035" sizeY="849" type="com.sun.star.drawing.TextShape" text="Red - The color of rose and passion&#10;19%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="9943" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="3813" positionY="3993" sizeX="6035" sizeY="850" type="com.sun.star.drawing.TextShape" text="Red - The color of rose and passion&#10;19%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="9943" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -262,20 +262,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6036.000000" column2="0.000000" column3="3813.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="3994.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="3993.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6036.000000" column2="0.000000" column3="3813.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="3994.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="3993.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="14780" positionY="3124" sizeX="6140" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=4">
+           <XShape positionX="14780" positionY="3123" sizeX="6140" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=4">
             <XShapes>
-             <XShape positionX="14780" positionY="3124" sizeX="6140" sizeY="849" type="com.sun.star.drawing.TextShape" text="White - The color of milk and purity&#10;14%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="26494" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="14780" positionY="3123" sizeX="6140" sizeY="850" type="com.sun.star.drawing.TextShape" text="White - The color of milk and purity&#10;14%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="26494" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -285,49 +285,49 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6141.000000" column2="0.000000" column3="14780.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="3124.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="3123.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6141.000000" column2="0.000000" column3="14780.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="3124.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="3123.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
           </XShapes>
           <Transformation>
            <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-           <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+           <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
            <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
           </Transformation>
          </XShape>
         </XShapes>
         <Transformation>
          <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-         <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+         <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
          <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
         </Transformation>
        </XShape>
       </XShapes>
       <Transformation>
        <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-       <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+       <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
        <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
       </Transformation>
      </XShape>
     </XShapes>
     <Transformation>
      <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-     <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+     <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
      <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
     </Transformation>
    </XShape>
   </XShapes>
   <Transformation>
    <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-   <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+   <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
    <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
   </Transformation>
  </XShape>
diff --git a/chart2/qa/extras/xshape/data/reference/tdf90839-3.xml b/chart2/qa/extras/xshape/data/reference/tdf90839-3.xml
index 7b67bd226da6..390d3e1615b8 100644
--- a/chart2/qa/extras/xshape/data/reference/tdf90839-3.xml
+++ b/chart2/qa/extras/xshape/data/reference/tdf90839-3.xml
@@ -14,7 +14,7 @@
    <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
   </Transformation>
  </XShape>
- <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape" name="CID/D=0">
+ <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape" name="CID/D=0">
   <XShapes>
    <XShape positionX="8207" positionY="3821" sizeX="9721" sizeY="9721" type="com.sun.star.drawing.RectangleShape" name="MarkHandles" fontHeight="12.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
     <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
@@ -30,7 +30,7 @@
      <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
     </Transformation>
    </XShape>
-   <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.RectangleShape" name="PlotAreaIncludingAxes" fontHeight="12.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
+   <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.RectangleShape" name="PlotAreaIncludingAxes" fontHeight="12.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
     <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
     <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
     <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -40,11 +40,11 @@
     <LineEnd/>
     <Transformation>
      <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-     <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+     <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
      <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
     </Transformation>
    </XShape>
-   <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape">
+   <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape">
     <XShapes>
      <XShape positionX="8207" positionY="3819" sizeX="9721" sizeY="9723" type="com.sun.star.drawing.GroupShape">
       <XShapes>
@@ -175,15 +175,15 @@
        <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
       </Transformation>
      </XShape>
-     <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape">
+     <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape">
       <XShapes>
-       <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape">
+       <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape">
         <XShapes>
-         <XShape positionX="1910" positionY="3124" sizeX="22111" sizeY="10509" type="com.sun.star.drawing.GroupShape" name="CID/D=0:CS=0:CT=0:Series=0:DataLabels=">
+         <XShape positionX="1910" positionY="3123" sizeX="22111" sizeY="10511" type="com.sun.star.drawing.GroupShape" name="CID/D=0:CS=0:CT=0:Series=0:DataLabels=">
           <XShapes>
-           <XShape positionX="17907" positionY="9977" sizeX="6114" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=0">
+           <XShape positionX="17907" positionY="9977" sizeX="6114" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=0">
             <XShapes>
-             <XShape positionX="17907" positionY="9977" sizeX="6114" sizeY="849" type="com.sun.star.drawing.TextShape" text="Yellow - The color of sun and honey&#10;33%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="8732" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="17907" positionY="9977" sizeX="6114" sizeY="850" type="com.sun.star.drawing.TextShape" text="Yellow - The color of sun and honey&#10;33%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="8732" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -193,20 +193,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6115.000000" column2="0.000000" column3="17907.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="9977.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="9977.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6115.000000" column2="0.000000" column3="17907.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="9977.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="9977.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="3974" positionY="12784" sizeX="6220" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=1">
+           <XShape positionX="3974" positionY="12784" sizeX="6220" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=1">
             <XShapes>
-             <XShape positionX="3974" positionY="12784" sizeX="6220" sizeY="849" type="com.sun.star.drawing.TextShape" text="Black - The color of night and coffee&#10;28%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="3974" positionY="12784" sizeX="6220" sizeY="850" type="com.sun.star.drawing.TextShape" text="Black - The color of night and coffee&#10;28%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -216,20 +216,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6221.000000" column2="0.000000" column3="3974.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="12784.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="12784.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6221.000000" column2="0.000000" column3="3974.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="12784.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="12784.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="1910" positionY="7819" sizeX="6167" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=2">
+           <XShape positionX="1910" positionY="7819" sizeX="6167" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=2">
             <XShapes>
-             <XShape positionX="1910" positionY="7819" sizeX="6167" sizeY="849" type="com.sun.star.drawing.TextShape" text="Green - The color of grass and hope&#10;6%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="1910" positionY="7819" sizeX="6167" sizeY="850" type="com.sun.star.drawing.TextShape" text="Green - The color of grass and hope&#10;6%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -239,20 +239,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6168.000000" column2="0.000000" column3="1910.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="7819.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="7819.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6168.000000" column2="0.000000" column3="1910.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="7819.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="7819.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="3813" positionY="3994" sizeX="6035" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=3">
+           <XShape positionX="3813" positionY="3993" sizeX="6035" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=3">
             <XShapes>
-             <XShape positionX="3813" positionY="3994" sizeX="6035" sizeY="849" type="com.sun.star.drawing.TextShape" text="Red - The color of rose and passion&#10;19%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="3813" positionY="3993" sizeX="6035" sizeY="850" type="com.sun.star.drawing.TextShape" text="Red - The color of rose and passion&#10;19%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -262,20 +262,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6036.000000" column2="0.000000" column3="3813.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="3994.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="3993.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6036.000000" column2="0.000000" column3="3813.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="3994.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="3993.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="14780" positionY="3124" sizeX="6140" sizeY="849" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=4">
+           <XShape positionX="14780" positionY="3123" sizeX="6140" sizeY="850" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=4">
             <XShapes>
-             <XShape positionX="14780" positionY="3124" sizeX="6140" sizeY="849" type="com.sun.star.drawing.TextShape" text="White - The color of milk and purity&#10;14%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="14780" positionY="3123" sizeX="6140" sizeY="850" type="com.sun.star.drawing.TextShape" text="White - The color of milk and purity&#10;14%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -285,49 +285,49 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6141.000000" column2="0.000000" column3="14780.000000"/>
-               <Line2 column1="0.000000" column2="850.000000" column3="3124.000000"/>
+               <Line2 column1="0.000000" column2="851.000000" column3="3123.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6141.000000" column2="0.000000" column3="14780.000000"/>
-             <Line2 column1="0.000000" column2="850.000000" column3="3124.000000"/>
+             <Line2 column1="0.000000" column2="851.000000" column3="3123.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
           </XShapes>
           <Transformation>
            <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-           <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+           <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
            <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
           </Transformation>
          </XShape>
         </XShapes>
         <Transformation>
          <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-         <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+         <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
          <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
         </Transformation>
        </XShape>
       </XShapes>
       <Transformation>
        <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-       <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+       <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
        <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
       </Transformation>
      </XShape>
     </XShapes>
     <Transformation>
      <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-     <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+     <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
      <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
     </Transformation>
    </XShape>
   </XShapes>
   <Transformation>
    <Line1 column1="22112.000000" column2="0.000000" column3="1910.000000"/>
-   <Line2 column1="0.000000" column2="10510.000000" column3="3124.000000"/>
+   <Line2 column1="0.000000" column2="10512.000000" column3="3123.000000"/>
    <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
   </Transformation>
  </XShape>
diff --git a/chart2/qa/extras/xshape/data/reference/tdf90839-4.xml b/chart2/qa/extras/xshape/data/reference/tdf90839-4.xml
index 7fabc697c751..2b107e9f81cc 100644
--- a/chart2/qa/extras/xshape/data/reference/tdf90839-4.xml
+++ b/chart2/qa/extras/xshape/data/reference/tdf90839-4.xml
@@ -14,7 +14,7 @@
    <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
   </Transformation>
  </XShape>
- <XShape positionX="1737" positionY="2768" sizeX="21967" sizeY="11230" type="com.sun.star.drawing.GroupShape" name="CID/D=0">
+ <XShape positionX="1737" positionY="2767" sizeX="21967" sizeY="11232" type="com.sun.star.drawing.GroupShape" name="CID/D=0">
   <XShapes>
    <XShape positionX="8034" positionY="3894" sizeX="9575" sizeY="9575" type="com.sun.star.drawing.RectangleShape" name="MarkHandles" fontHeight="12.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
     <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
@@ -30,7 +30,7 @@
      <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
     </Transformation>
    </XShape>
-   <XShape positionX="1737" positionY="2768" sizeX="21967" sizeY="11230" type="com.sun.star.drawing.RectangleShape" name="PlotAreaIncludingAxes" fontHeight="12.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
+   <XShape positionX="1737" positionY="2767" sizeX="21967" sizeY="11232" type="com.sun.star.drawing.RectangleShape" name="PlotAreaIncludingAxes" fontHeight="12.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="729fcf" fillTransparence="0" fillTransparenceGradientName="">
     <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
     <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
     <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -40,11 +40,11 @@
     <LineEnd/>
     <Transformation>
      <Line1 column1="21968.000000" column2="0.000000" column3="1737.000000"/>
-     <Line2 column1="0.000000" column2="11231.000000" column3="2768.000000"/>
+     <Line2 column1="0.000000" column2="11233.000000" column3="2767.000000"/>
      <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
     </Transformation>
    </XShape>
-   <XShape positionX="1737" positionY="2768" sizeX="21967" sizeY="11230" type="com.sun.star.drawing.GroupShape">
+   <XShape positionX="1737" positionY="2767" sizeX="21967" sizeY="11232" type="com.sun.star.drawing.GroupShape">
     <XShapes>
      <XShape positionX="8034" positionY="3892" sizeX="9575" sizeY="9577" type="com.sun.star.drawing.GroupShape">
       <XShapes>
@@ -175,15 +175,15 @@
        <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
       </Transformation>
      </XShape>
-     <XShape positionX="1737" positionY="2768" sizeX="21967" sizeY="11230" type="com.sun.star.drawing.GroupShape">
+     <XShape positionX="1737" positionY="2767" sizeX="21967" sizeY="11232" type="com.sun.star.drawing.GroupShape">
       <XShapes>
-       <XShape positionX="1737" positionY="2768" sizeX="21967" sizeY="11230" type="com.sun.star.drawing.GroupShape">
+       <XShape positionX="1737" positionY="2767" sizeX="21967" sizeY="11232" type="com.sun.star.drawing.GroupShape">
         <XShapes>
-         <XShape positionX="1737" positionY="2768" sizeX="21967" sizeY="11230" type="com.sun.star.drawing.GroupShape" name="CID/D=0:CS=0:CT=0:Series=0:DataLabels=">
+         <XShape positionX="1737" positionY="2767" sizeX="21967" sizeY="11232" type="com.sun.star.drawing.GroupShape" name="CID/D=0:CS=0:CT=0:Series=0:DataLabels=">
           <XShapes>
-           <XShape positionX="17590" positionY="9958" sizeX="6114" sizeY="1273" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=0">
+           <XShape positionX="17590" positionY="9958" sizeX="6114" sizeY="1274" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=0">
             <XShapes>
-             <XShape positionX="17590" positionY="9958" sizeX="6114" sizeY="1273" type="com.sun.star.drawing.TextShape" text="Yellow - The color of sun and honey&#10;120&#10;33%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="8546" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="17590" positionY="9958" sizeX="6114" sizeY="1274" type="com.sun.star.drawing.TextShape" text="Yellow - The color of sun and honey&#10;120&#10;33%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="8546" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -193,20 +193,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6115.000000" column2="0.000000" column3="17590.000000"/>
-               <Line2 column1="0.000000" column2="1274.000000" column3="9958.000000"/>
+               <Line2 column1="0.000000" column2="1275.000000" column3="9958.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6115.000000" column2="0.000000" column3="17590.000000"/>
-             <Line2 column1="0.000000" column2="1274.000000" column3="9958.000000"/>
+             <Line2 column1="0.000000" column2="1275.000000" column3="9958.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="3770" positionY="12725" sizeX="6220" sizeY="1273" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=1">
+           <XShape positionX="3770" positionY="12725" sizeX="6220" sizeY="1274" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=1">
             <XShapes>
-             <XShape positionX="3770" positionY="12725" sizeX="6220" sizeY="1273" type="com.sun.star.drawing.TextShape" text="Black - The color of night and coffee&#10;100&#10;28%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="10075" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="3770" positionY="12725" sizeX="6220" sizeY="1274" type="com.sun.star.drawing.TextShape" text="Black - The color of night and coffee&#10;100&#10;28%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="TOP" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="10075" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -216,20 +216,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6221.000000" column2="0.000000" column3="3770.000000"/>
-               <Line2 column1="0.000000" column2="1274.000000" column3="12725.000000"/>
+               <Line2 column1="0.000000" column2="1275.000000" column3="12725.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6221.000000" column2="0.000000" column3="3770.000000"/>
-             <Line2 column1="0.000000" column2="1274.000000" column3="12725.000000"/>
+             <Line2 column1="0.000000" column2="1275.000000" column3="12725.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="1737" positionY="7614" sizeX="6167" sizeY="1273" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=2">
+           <XShape positionX="1737" positionY="7614" sizeX="6167" sizeY="1274" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=2">
             <XShapes>
-             <XShape positionX="1737" positionY="7614" sizeX="6167" sizeY="1273" type="com.sun.star.drawing.TextShape" text="Green - The color of grass and hope&#10;20&#10;6%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="8052" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="1737" positionY="7614" sizeX="6167" sizeY="1274" type="com.sun.star.drawing.TextShape" text="Green - The color of grass and hope&#10;20&#10;6%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="CENTER" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="8052" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -239,20 +239,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6168.000000" column2="0.000000" column3="1737.000000"/>
-               <Line2 column1="0.000000" column2="1274.000000" column3="7614.000000"/>
+               <Line2 column1="0.000000" column2="1275.000000" column3="7614.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6168.000000" column2="0.000000" column3="1737.000000"/>
-             <Line2 column1="0.000000" column2="1274.000000" column3="7614.000000"/>
+             <Line2 column1="0.000000" column2="1275.000000" column3="7614.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="3614" positionY="3626" sizeX="6035" sizeY="1273" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=3">
+           <XShape positionX="3614" positionY="3625" sizeX="6035" sizeY="1274" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=3">
             <XShapes>
-             <XShape positionX="3614" positionY="3626" sizeX="6035" sizeY="1273" type="com.sun.star.drawing.TextShape" text="Red - The color of rose and passion&#10;70&#10;19%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="9744" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="3614" positionY="3625" sizeX="6035" sizeY="1274" type="com.sun.star.drawing.TextShape" text="Red - The color of rose and passion&#10;70&#10;19%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="RIGHT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="9744" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -262,20 +262,20 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6036.000000" column2="0.000000" column3="3614.000000"/>
-               <Line2 column1="0.000000" column2="1274.000000" column3="3626.000000"/>
+               <Line2 column1="0.000000" column2="1275.000000" column3="3625.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6036.000000" column2="0.000000" column3="3614.000000"/>
-             <Line2 column1="0.000000" column2="1274.000000" column3="3626.000000"/>
+             <Line2 column1="0.000000" column2="1275.000000" column3="3625.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
-           <XShape positionX="14509" positionY="2768" sizeX="6140" sizeY="1273" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=4">
+           <XShape positionX="14509" positionY="2767" sizeX="6140" sizeY="1274" type="com.sun.star.drawing.GroupShape" name="CID/MultiClick/CID/D=0:CS=0:CT=0:Series=0:DataLabels=:DataLabel=4">
             <XShapes>
-             <XShape positionX="14509" positionY="2768" sizeX="6140" sizeY="1273" type="com.sun.star.drawing.TextShape" text="White - The color of milk and purity&#10;50&#10;14%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="25991" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+             <XShape positionX="14509" positionY="2767" sizeX="6140" sizeY="1274" type="com.sun.star.drawing.TextShape" text="White - The color of milk and purity&#10;50&#10;14%" fontHeight="12.000000" fontColor="595959" textAutoGrowHeight="true" textAutoGrowWidth="true" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="BOTTOM" textLeftDistance="0" textRightDistance="0" textUpperDistance="0" textLowerDistance="0" textMaximumFrameHeight="0" textMaximumFrameWidth="25991" textMinimumFrameHeight="1" textMinimumFrameWidth="1" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
               <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
               <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -285,49 +285,49 @@
               <LineEnd/>
               <Transformation>
                <Line1 column1="6141.000000" column2="0.000000" column3="14509.000000"/>
-               <Line2 column1="0.000000" column2="1274.000000" column3="2768.000000"/>
+               <Line2 column1="0.000000" column2="1275.000000" column3="2767.000000"/>
                <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
               </Transformation>
              </XShape>
             </XShapes>
             <Transformation>
              <Line1 column1="6141.000000" column2="0.000000" column3="14509.000000"/>
-             <Line2 column1="0.000000" column2="1274.000000" column3="2768.000000"/>
+             <Line2 column1="0.000000" column2="1275.000000" column3="2767.000000"/>
              <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
             </Transformation>
            </XShape>
           </XShapes>
           <Transformation>
            <Line1 column1="21968.000000" column2="0.000000" column3="1737.000000"/>
-           <Line2 column1="0.000000" column2="11231.000000" column3="2768.000000"/>
+           <Line2 column1="0.000000" column2="11233.000000" column3="2767.000000"/>
            <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
           </Transformation>
          </XShape>
         </XShapes>
         <Transformation>
          <Line1 column1="21968.000000" column2="0.000000" column3="1737.000000"/>
-         <Line2 column1="0.000000" column2="11231.000000" column3="2768.000000"/>
+         <Line2 column1="0.000000" column2="11233.000000" column3="2767.000000"/>
          <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
         </Transformation>
        </XShape>
       </XShapes>
       <Transformation>
        <Line1 column1="21968.000000" column2="0.000000" column3="1737.000000"/>
-       <Line2 column1="0.000000" column2="11231.000000" column3="2768.000000"/>
+       <Line2 column1="0.000000" column2="11233.000000" column3="2767.000000"/>
        <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
       </Transformation>
      </XShape>
     </XShapes>
     <Transformation>
      <Line1 column1="21968.000000" column2="0.000000" column3="1737.000000"/>
-     <Line2 column1="0.000000" column2="11231.000000" column3="2768.000000"/>
+     <Line2 column1="0.000000" column2="11233.000000" column3="2767.000000"/>
      <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
     </Transformation>
    </XShape>
   </XShapes>
   <Transformation>
    <Line1 column1="21968.000000" column2="0.000000" column3="1737.000000"/>
-   <Line2 column1="0.000000" column2="11231.000000" column3="2768.000000"/>
+   <Line2 column1="0.000000" column2="11233.000000" column3="2767.000000"/>
    <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
   </Transformation>
  </XShape>
diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index ff221a9cc55a..e702d6ae94ff 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -212,6 +212,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
     cui/source/tabpages/tabstpge \
     cui/source/tabpages/textanim \
     cui/source/tabpages/textattr \
+    cui/source/tabpages/TextColumnsPage \
     cui/source/tabpages/tparea \
     cui/source/tabpages/tpbitmap \
     cui/source/tabpages/tpcolor \
diff --git a/cui/UIConfig_cui.mk b/cui/UIConfig_cui.mk
index 153d6fe98fda..58fd66525310 100644
--- a/cui/UIConfig_cui.mk
+++ b/cui/UIConfig_cui.mk
@@ -200,6 +200,7 @@ $(eval $(call gb_UIConfig_add_uifiles,cui,\
 	cui/uiconfig/ui/swpossizepage \
 	cui/uiconfig/ui/textattrtabpage \
 	cui/uiconfig/ui/textanimtabpage \
+	cui/uiconfig/ui/textcolumnstabpage \
 	cui/uiconfig/ui/textdialog \
 	cui/uiconfig/ui/textflowpage \
 	cui/uiconfig/ui/thesaurus \
diff --git a/cui/source/factory/dlgfact.cxx b/cui/source/factory/dlgfact.cxx
index e43b027602c4..3ed88fbe4995 100644
--- a/cui/source/factory/dlgfact.cxx
+++ b/cui/source/factory/dlgfact.cxx
@@ -90,6 +90,7 @@
 #include <tipofthedaydlg.hxx>
 #include <toolbarmodedlg.hxx>
 #include <DiagramDialog.hxx>
+#include <TextColumnsPage.hxx>

 using namespace ::com::sun::star;
 using namespace ::com::sun::star::frame;
@@ -1483,6 +1484,8 @@ CreateTabPage AbstractDialogFactory_Impl::GetTabPageCreatorFunc( sal_uInt16 nId
             return SvxGrfCropPage::Create;
         case RID_SVXPAGE_MACROASSIGN :
             return SfxMacroTabPage::Create;
+        case RID_SVXPAGE_TEXTCOLUMNS:
+            return SvxTextColumnsPage::Create;
         default:
             break;
     }
@@ -1546,6 +1549,8 @@ GetTabPageRanges AbstractDialogFactory_Impl::GetTabPageRangesFunc( sal_uInt16 nI
             return SvxPageDescPage::GetRanges;
         case RID_SVXPAGE_ASIAN_LAYOUT:
             return SvxAsianLayoutPage::GetRanges;
+        case RID_SVXPAGE_TEXTCOLUMNS:
+            return SvxTextColumnsPage::GetRanges;
         default:
             break;
     }
diff --git a/cui/source/inc/TextColumnsPage.hxx b/cui/source/inc/TextColumnsPage.hxx
new file mode 100644
index 000000000000..6153cd27a520
--- /dev/null
+++ b/cui/source/inc/TextColumnsPage.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <sfx2/tabdlg.hxx>
+
+#include <memory>
+
+/// Tab page for EditEngine columns properties
+class SvxTextColumnsPage : public SfxTabPage
+{
+private:
+    static const sal_uInt16 pRanges[];
+
+    std::unique_ptr<weld::SpinButton> m_xColumnsNumber;
+    std::unique_ptr<weld::MetricSpinButton> m_xColumnsSpacing;
+
+public:
+    SvxTextColumnsPage(weld::Container* pPage, weld::DialogController* pController,
+                       const SfxItemSet& rInAttrs);
+    virtual ~SvxTextColumnsPage() override;
+
+    static std::unique_ptr<SfxTabPage>
+    Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet*);
+    static const sal_uInt16* GetRanges() { return pRanges; }
+
+    virtual bool FillItemSet(SfxItemSet*) override;
+    virtual void Reset(const SfxItemSet*) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/cui/source/tabpages/TextColumnsPage.cxx b/cui/source/tabpages/TextColumnsPage.cxx
new file mode 100644
index 000000000000..db83722e6be1
--- /dev/null
+++ b/cui/source/tabpages/TextColumnsPage.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <svtools/unitconv.hxx>
+#include <svx/dlgutil.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/svddef.hxx>
+
+#include <TextColumnsPage.hxx>
+
+const sal_uInt16 SvxTextColumnsPage::pRanges[]
+    = { SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST, 0 };
+
+SvxTextColumnsPage::SvxTextColumnsPage(weld::Container* pPage, weld::DialogController* pController,
+                                       const SfxItemSet& rInAttrs)
+    : SfxTabPage(pPage, pController, "cui/ui/textcolumnstabpage.ui", "TextColumnsPage", &rInAttrs)
+    , m_xColumnsNumber(m_xBuilder->weld_spin_button("FLD_COL_NUMBER"))
+    , m_xColumnsSpacing(
+          m_xBuilder->weld_metric_spin_button("MTR_FLD_COL_SPACING", GetModuleFieldUnit(rInAttrs)))
+{
+}
+
+SvxTextColumnsPage::~SvxTextColumnsPage() = default;
+
+// read the passed item set
+void SvxTextColumnsPage::Reset(const SfxItemSet* rAttrs)
+{
+    SfxItemPool* pPool = rAttrs->GetPool();
+    assert(pPool);
+
+    {
+        auto pItem = GetItem(*rAttrs, SDRATTR_TEXTCOLUMNS_NUMBER);
+        if (!pItem)
+            pItem = &pPool->GetDefaultItem(SDRATTR_TEXTCOLUMNS_NUMBER);
+        m_xColumnsNumber->set_value(pItem->GetValue());
+        m_xColumnsNumber->save_value();
+    }
+
+    {
+        MapUnit eUnit = pPool->GetMetric(SDRATTR_TEXTCOLUMNS_SPACING);
+        auto pItem = GetItem(*rAttrs, SDRATTR_TEXTCOLUMNS_SPACING);
+        if (!pItem)
+            pItem = &pPool->GetDefaultItem(SDRATTR_TEXTCOLUMNS_SPACING);
+        SetMetricValue(*m_xColumnsSpacing, pItem->GetValue(), eUnit);
+        m_xColumnsSpacing->save_value();
+    }
+}
+
+// fill the passed item set with dialog box attributes
+bool SvxTextColumnsPage::FillItemSet(SfxItemSet* rAttrs)
+{
+    if (m_xColumnsNumber->get_value_changed_from_saved())
+        rAttrs->Put(SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER, m_xColumnsNumber->get_value()));
+
+    if (m_xColumnsSpacing->get_value_changed_from_saved())
+    {
+        SfxItemPool* pPool = rAttrs->GetPool();
+        assert(pPool);
+        MapUnit eUnit = pPool->GetMetric(SDRATTR_TEXTCOLUMNS_SPACING);
+        sal_Int32 nValue = GetCoreValue(*m_xColumnsSpacing, eUnit);
+        rAttrs->Put(SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING, nValue));
+    }
+
+    return true;
+}
+
+std::unique_ptr<SfxTabPage> SvxTextColumnsPage::Create(weld::Container* pPage,
+                                                       weld::DialogController* pController,
+                                                       const SfxItemSet* rAttrs)
+{
+    return std::make_unique<SvxTextColumnsPage>(pPage, pController, *rAttrs);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/cui/source/tabpages/textanim.cxx b/cui/source/tabpages/textanim.cxx
index a7ee4b3aade9..b4660fc19b8d 100644
--- a/cui/source/tabpages/textanim.cxx
+++ b/cui/source/tabpages/textanim.cxx
@@ -19,6 +19,7 @@

 #include <textanim.hxx>
 #include <textattr.hxx>
+#include <TextColumnsPage.hxx>
 #include <svx/dlgutil.hxx>
 #include <svx/svdmark.hxx>
 #include <svx/svdview.hxx>
@@ -47,6 +48,7 @@ SvxTextTabDialog::SvxTextTabDialog(weld::Window* pParent, const SfxItemSet* pAtt
 {
     AddTabPage("RID_SVXPAGE_TEXTATTR", SvxTextAttrPage::Create, nullptr);
     AddTabPage("RID_SVXPAGE_TEXTANIMATION", SvxTextAnimationPage::Create, nullptr);
+    AddTabPage("RID_SVXPAGE_TEXTCOLUMNS", SvxTextColumnsPage::Create, nullptr);
 }

 /*************************************************************************
diff --git a/cui/uiconfig/ui/textcolumnstabpage.ui b/cui/uiconfig/ui/textcolumnstabpage.ui
new file mode 100644
index 000000000000..596b155dbe1b
--- /dev/null
+++ b/cui/uiconfig/ui/textcolumnstabpage.ui
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2 -->
+<interface domain="cui">
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkAdjustment" id="adjustmentColNumber">
+    <property name="lower">1</property>
+    <property name="upper">16</property><!-- MSO has an upper limit of 16 in UI -->
+    <property name="step-increment">1</property>
+    <property name="page-increment">10</property>
+  </object>
+  <object class="GtkAdjustment" id="adjustmentColSpacing">
+    <property name="lower">0</property>
+    <property name="upper">2147483647</property>
+    <property name="step-increment">1</property>
+    <property name="page-increment">10</property>
+  </object>
+  <object class="GtkBox" id="TextColumnsPage">
+    <property name="visible">True</property>
+    <property name="can-focus">False</property>
+    <property name="border-width">6</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">12</property>
+    <child>
+      <!-- n-columns=2 n-rows=2 -->
+      <object class="GtkGrid" id="grid1">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="margin-start">12</property>
+        <property name="margin-top">6</property>
+        <property name="row-spacing">6</property>
+        <property name="column-spacing">12</property>
+        <child>
+          <object class="GtkLabel" id="labelColNumber">
+            <property name="visible">True</property>
+            <property name="can-focus">False</property>
+            <property name="label" translatable="yes" context="textcolumnstabpage|labelColNumber">_Number of columns:</property>
+            <property name="use-underline">True</property>
+            <property name="mnemonic-widget">FLD_COL_NUMBER</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="left-attach">0</property>
+            <property name="top-attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="labelColSpacing">
+            <property name="visible">True</property>
+            <property name="can-focus">False</property>
+            <property name="label" translatable="yes" context="textcolumnstabpage|labelColSpacing">_Spacing:</property>
+            <property name="use-underline">True</property>
+            <property name="mnemonic-widget">MTR_FLD_COL_SPACING</property>
+            <property name="xalign">0</property>
+          </object>
+          <packing>
+            <property name="left-attach">0</property>
+            <property name="top-attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="FLD_COL_NUMBER">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="activates-default">True</property>
+            <property name="truncate-multiline">True</property>
+            <property name="adjustment">adjustmentColNumber</property>
+            <property name="value">1</property>
+            <child internal-child="accessible">
+              <object class="AtkObject" id="FLD_COL_NUMBER-atkobject">
+                <property name="AtkObject::accessible-description" translatable="yes" context="textcolumnstabpage|extended_tip|FLD_COL_NUMBER">Enter the number of columns to use for the text.</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="left-attach">1</property>
+            <property name="top-attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="MTR_FLD_COL_SPACING">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="activates-default">True</property>
+            <property name="truncate-multiline">True</property>
+            <property name="adjustment">adjustmentColSpacing</property>
+            <property name="digits">2</property>
+            <child internal-child="accessible">
+              <object class="AtkObject" id="MTR_FLD_COL_SPACING-atkobject">
+                <property name="AtkObject::accessible-description" translatable="yes" context="textcolumnstabpage|extended_tip|MTR_FLD_COL_SPACING">Enter the amount of space to leave between the columns.</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="left-attach">1</property>
+            <property name="top-attach">1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child internal-child="accessible">
+      <object class="AtkObject" id="TextColumnsPage-atkobject">
+        <property name="AtkObject::accessible-description" translatable="yes" context="textcolumnstabpage|extended_tip|TextColumnsPage">Sets the columns layout properties for text in the selected drawing or text object.</property>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/cui/uiconfig/ui/textdialog.ui b/cui/uiconfig/ui/textdialog.ui
index a7cddf8500fd..4fcf813c71ba 100644
--- a/cui/uiconfig/ui/textdialog.ui
+++ b/cui/uiconfig/ui/textdialog.ui
@@ -187,6 +187,54 @@
                 <property name="tab_fill">False</property>
               </packing>
             </child>
+            <child>
+              <!-- n-columns=1 n-rows=1 -->
+              <object class="GtkGrid">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="RID_SVXPAGE_TEXTCOLUMNS">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes" context="textdialog|RID_SVXPAGE_TEXTCOLUMNS">Text Columns</property>
+              </object>
+              <packing>
+                <property name="position">2</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
           </object>
           <packing>
             <property name="expand">False</property>
diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx
index 3c06cbf96f51..7592a3f2b964 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -448,6 +448,11 @@ bool EditEngine::GetDirectVertical() const
     return pImpEditEngine->GetDirectVertical();
 }

+void EditEngine::SetTextColumns(sal_Int16 nColumns, sal_Int32 nSpacing)
+{
+    pImpEditEngine->SetTextColumns(nColumns, nSpacing);
+}
+
 void EditEngine::SetFixedCellHeight( bool bUseFixedCellHeight )
 {
     pImpEditEngine->SetFixedCellHeight( bUseFixedCellHeight );
@@ -555,6 +560,11 @@ void EditEngine::SetMaxAutoPaperSize( const Size& rSz )
     pImpEditEngine->SetMaxAutoPaperSize( rSz );
 }

+void EditEngine::SetMinColumnWrapHeight(tools::Long nVal)
+{
+    pImpEditEngine->SetMinColumnWrapHeight(nVal);
+}
+
 OUString EditEngine::GetText( LineEnd eEnd ) const
 {
     return pImpEditEngine->GetEditDoc().GetText( eEnd );
@@ -2013,29 +2023,12 @@ bool EditEngine::IsTextPos( const Point& rPaperPos, sal_uInt16 nBorder )
     if ( !pImpEditEngine->IsFormatted() )
         pImpEditEngine->FormatDoc();

-    bool bTextPos = false;
     // take unrotated positions for calculation here
     Point aDocPos = GetDocPos( rPaperPos );

     if ( ( aDocPos.Y() > 0  ) && ( aDocPos.Y() < static_cast<tools::Long>(pImpEditEngine->GetTextHeight()) ) )
-    {
-        EditPaM aPaM = pImpEditEngine->GetPaM( aDocPos, false );
-        if ( aPaM.GetNode() )
-        {
-            const ParaPortion* pParaPortion = pImpEditEngine->FindParaPortion( aPaM.GetNode() );
-            DBG_ASSERT( pParaPortion, "ParaPortion?" );
-
-            sal_Int32 nLine = pParaPortion->GetLineNumber( aPaM.GetIndex() );
-            const EditLine& rLine = pParaPortion->GetLines()[nLine];
-            Range aLineXPosStartEnd = pImpEditEngine->GetLineXPosStartEnd( pParaPortion, &rLine );
-            if ( ( aDocPos.X() >= aLineXPosStartEnd.Min() - nBorder ) &&
-                 ( aDocPos.X() <= aLineXPosStartEnd.Max() + nBorder ) )
-            {
-                 bTextPos = true;
-            }
-        }
-    }
-    return bTextPos;
+        return pImpEditEngine->IsTextPos(aDocPos, nBorder);
+    return false;
 }

 void EditEngine::SetEditTextObjectPool( SfxItemPool* pPool )
diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index f226f983f593..138d73825b55 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -518,107 +518,116 @@ void ImpEditView::DrawSelectionXOR( EditSelection aTmpSel, vcl::Region* pRegion,
     bool bStartHandleVisible = false;
     bool bEndHandleVisible = false;

-    for ( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ )
-    {
-        ParaPortion* pTmpPortion = pEditEngine->GetParaPortions().SafeGetObject( nPara );
-        if (!pTmpPortion)
+    auto DrawHighlight = [&, nStartLine = sal_Int32(0), nEndLine = sal_Int32(0)](
+                             const ImpEditEngine::LineAreaInfo& rInfo) mutable {
+        if (!rInfo.pLine) // Begin of ParaPortion
         {
-            SAL_WARN( "editeng", "Portion in Selection not found!" );
-            continue;
-        }
-
-        DBG_ASSERT( !pTmpPortion->IsInvalid(), "Portion in Selection not formatted!" );
-
-        if ( !pTmpPortion->IsVisible() || pTmpPortion->IsInvalid() )
-            continue;
-
-        tools::Long nParaStart = pEditEngine->GetParaPortions().GetYOffset( pTmpPortion );
-        if ( ( nParaStart + pTmpPortion->GetHeight() ) < GetVisDocTop() )
-            continue;
-        if ( nParaStart > GetVisDocBottom() )
-            break;
-
-        sal_uInt16 nStartLine = 0;
-        sal_uInt16 nEndLine = pTmpPortion->GetLines().Count() -1;
-        if ( nPara == nStartPara )
-            nStartLine = pTmpPortion->GetLines().FindLine( aTmpSel.Min().GetIndex(), false );
-        if ( nPara == nEndPara )
-            nEndLine = pTmpPortion->GetLines().FindLine( aTmpSel.Max().GetIndex(), true );
+            if (rInfo.nPortion < nStartPara)
+                return ImpEditEngine::CallbackResult::SkipThisPortion;
+            if (rInfo.nPortion > nEndPara)
+                return ImpEditEngine::CallbackResult::Stop;
+            DBG_ASSERT(!rInfo.rPortion.IsInvalid(), "Portion in Selection not formatted!");
+            if (rInfo.rPortion.IsInvalid())
+                return ImpEditEngine::CallbackResult::SkipThisPortion;
+
+            if (rInfo.nPortion == nStartPara)
+                nStartLine = rInfo.rPortion.GetLines().FindLine(aTmpSel.Min().GetIndex(), false);
+            else
+                nStartLine = 0;

-        for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ )
+            if (rInfo.nPortion == nEndPara)
+                nEndLine = rInfo.rPortion.GetLines().FindLine(aTmpSel.Max().GetIndex(), true);
+            else
+                nEndLine = rInfo.rPortion.GetLines().Count() - 1;
+        }
+        else // This is a correct ParaPortion
         {
-            const EditLine& rLine = pTmpPortion->GetLines()[nLine];
+            if (rInfo.nLine < nStartLine)
+                return ImpEditEngine::CallbackResult::Continue;
+            if (rInfo.nLine > nEndLine)
+                return ImpEditEngine::CallbackResult::SkipThisPortion;

             bool bPartOfLine = false;
-            sal_Int32 nStartIndex = rLine.GetStart();
-            sal_Int32 nEndIndex = rLine.GetEnd();
-            if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) && ( nStartIndex != aTmpSel.Min().GetIndex() ) )
+            sal_Int32 nStartIndex = rInfo.pLine->GetStart();
+            sal_Int32 nEndIndex = rInfo.pLine->GetEnd();
+            if ((rInfo.nPortion == nStartPara) && (rInfo.nLine == nStartLine)
+                && (nStartIndex != aTmpSel.Min().GetIndex()))
             {
                 nStartIndex = aTmpSel.Min().GetIndex();
                 bPartOfLine = true;
             }
-            if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) && ( nEndIndex != aTmpSel.Max().GetIndex() ) )
+            if ((rInfo.nPortion == nEndPara) && (rInfo.nLine == nEndLine)
+                && (nEndIndex != aTmpSel.Max().GetIndex()))
             {
                 nEndIndex = aTmpSel.Max().GetIndex();
                 bPartOfLine = true;
             }

             // Can happen if at the beginning of a wrapped line.
-            if ( nEndIndex < nStartIndex )
+            if (nEndIndex < nStartIndex)
                 nEndIndex = nStartIndex;

-            tools::Rectangle aTmpRect( pEditEngine->pImpEditEngine->GetEditCursor( pTmpPortion, nStartIndex ) );
-            Point aTopLeft( aTmpRect.TopLeft() );
-            Point aBottomRight( aTmpRect.BottomRight() );
-
-            aTopLeft.AdjustY(nParaStart );
-            aBottomRight.AdjustY(nParaStart );
+            tools::Rectangle aTmpRect(pEditEngine->pImpEditEngine->GetEditCursor(
+                &rInfo.rPortion, rInfo.pLine, nStartIndex, GetCursorFlags::NONE));
+            aTmpRect.Move(0, pEditEngine->pImpEditEngine->getTopDirectionAware(rInfo.aArea));

             // Only paint if in the visible range ...
-            if ( aTopLeft.Y() > GetVisDocBottom() )
-                break;
+            if (aTmpRect.Top() > GetVisDocBottom())
+                return ImpEditEngine::CallbackResult::Continue;

-            if ( aBottomRight.Y() < GetVisDocTop() )
-                continue;
+            if (aTmpRect.Bottom() < GetVisDocTop())
+                return ImpEditEngine::CallbackResult::Continue;

-            if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) )
+            if ((rInfo.nPortion == nStartPara) && (rInfo.nLine == nStartLine))
                 bStartHandleVisible = true;
-            if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) )
+            if ((rInfo.nPortion == nEndPara) && (rInfo.nLine == nEndLine))
                 bEndHandleVisible = true;

             // Now that we have Bidi, the first/last index doesn't have to be the 'most outside' position
-            if ( !bPartOfLine )
+            if (!bPartOfLine)
             {
-                Range aLineXPosStartEnd = pEditEngine->GetLineXPosStartEnd(pTmpPortion, &rLine);
-                aTopLeft.setX( aLineXPosStartEnd.Min() );
-                aBottomRight.setX( aLineXPosStartEnd.Max() );
-                ImplDrawHighlightRect( pTarget, aTopLeft, aBottomRight, pPolyPoly.get() );
+                Range aLineXPosStartEnd
+                    = pEditEngine->GetLineXPosStartEnd(&rInfo.rPortion, rInfo.pLine);
+                aTmpRect.SetLeft(aLineXPosStartEnd.Min());
+                aTmpRect.SetRight(aLineXPosStartEnd.Max());
+                aTmpRect.Move(pEditEngine->pImpEditEngine->getLeftDirectionAware(rInfo.aArea), 0);
+                ImplDrawHighlightRect(pTarget, aTmpRect.TopLeft(), aTmpRect.BottomRight(),
+                                      pPolyPoly.get());
             }
             else
             {
                 sal_Int32 nTmpStartIndex = nStartIndex;
                 sal_Int32 nWritingDirStart, nTmpEndIndex;
+                const sal_Int32 nLeftOffset
+                    = pEditEngine->pImpEditEngine->getLeftDirectionAware(rInfo.aArea);

-                while ( nTmpStartIndex < nEndIndex )
+                while (nTmpStartIndex < nEndIndex)
                 {
-                    pEditEngine->pImpEditEngine->GetRightToLeft( nPara, nTmpStartIndex+1, &nWritingDirStart, &nTmpEndIndex );
-                    if ( nTmpEndIndex > nEndIndex )
+                    pEditEngine->pImpEditEngine->GetRightToLeft(rInfo.nPortion, nTmpStartIndex + 1,
+                                                                &nWritingDirStart, &nTmpEndIndex);
+                    if (nTmpEndIndex > nEndIndex)
                         nTmpEndIndex = nEndIndex;

-                    DBG_ASSERT( nTmpEndIndex > nTmpStartIndex, "DrawSelectionXOR, Start >= End?" );
+                    DBG_ASSERT(nTmpEndIndex > nTmpStartIndex, "DrawSelectionXOR, Start >= End?");

-                    tools::Long nX1 = pEditEngine->GetXPos(pTmpPortion, &rLine, nTmpStartIndex, true);
-                    tools::Long nX2 = pEditEngine->GetXPos(pTmpPortion, &rLine, nTmpEndIndex);
+                    tools::Long nX1
+                        = pEditEngine->GetXPos(&rInfo.rPortion, rInfo.pLine, nTmpStartIndex, true);
+                    tools::Long nX2
+                        = pEditEngine->GetXPos(&rInfo.rPortion, rInfo.pLine, nTmpEndIndex);

-                    Point aPt1( std::min( nX1, nX2 ), aTopLeft.Y() );
-                    Point aPt2( std::max( nX1, nX2 ), aBottomRight.Y() );
+                    aTmpRect.SetLeft(std::min(nX1, nX2));
+                    aTmpRect.SetRight(std::max(nX1, nX2));
+                    aTmpRect.Move(nLeftOffset, 0);

-                    ImplDrawHighlightRect( pTarget, aPt1, aPt2, pPolyPoly.get() );
+                    ImplDrawHighlightRect(pTarget, aTmpRect.TopLeft(), aTmpRect.BottomRight(),
+                                          pPolyPoly.get());
                     nTmpStartIndex = nTmpEndIndex;
                 }
             }
         }
-    }
+        return ImpEditEngine::CallbackResult::Continue;
+    };
+    pEditEngine->pImpEditEngine->IterateLineAreas(DrawHighlight, ImpEditEngine::IterFlag::none);

     if (comphelper::LibreOfficeKit::isActive() && mpViewShell && pOutWin)
         lokSelectionCallback(pPolyPoly, bStartHandleVisible, bEndHandleVisible);
@@ -1791,6 +1800,8 @@ const SvxFieldItem* ImpEditView::GetField( const Point& rPos, sal_Int32* pPara,

     Point aDocPos( GetDocPos( rPos ) );
     EditPaM aPaM = pEditEngine->GetPaM(aDocPos, false);
+    if (!aPaM)
+        return nullptr;

     if ( aPaM.GetIndex() == aPaM.GetNode()->Len() )
     {
@@ -1829,6 +1840,8 @@ bool ImpEditView::IsBulletArea( const Point& rPos, sal_Int32* pPara )

     Point aDocPos( GetDocPos( rPos ) );
     EditPaM aPaM = pEditEngine->GetPaM(aDocPos, false);
+    if (!aPaM)
+        return false;

     if ( aPaM.GetIndex() == 0 )
     {
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index 3adffe49b1eb..dd797469a81f 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -54,8 +54,10 @@
 #include <o3tl/deleter.hxx>
 #include <o3tl/typed_flags_set.hxx>

+#include <functional>
 #include <optional>
 #include <memory>
+#include <tuple>
 #include <vector>

 class EditView;
@@ -490,6 +492,7 @@ private:
     Size                aPaperSize;             // Layout
     Size                aMinAutoPaperSize;      // Layout ?
     Size                aMaxAutoPaperSize;      // Layout ?
+    tools::Long mnMinColumnWrapHeight = 0; // Corresponds to graphic object height
     EditDoc             aEditDoc;               // Document content

     // Engine Specific data ...
@@ -549,8 +552,8 @@ private:
     // For Formatting / Update...
     std::vector<std::unique_ptr<DeletedNodeInfo> > aDeletedNodes;
     tools::Rectangle           aInvalidRect;
-    sal_uInt32          nCurTextHeight;
-    sal_uInt32          nCurTextHeightNTP;  // without trailing empty paragraphs
+    tools::Long         nCurTextHeight;
+    tools::Long         nCurTextHeightNTP;  // without trailing empty paragraphs
     sal_uInt16          nOnePixelInRef;

     IdleFormattter      aIdleFormatter;
@@ -562,6 +565,9 @@ private:
     sal_Int32 mnOverflowingLine = -1;
     bool mbNeedsChainingHandling = false;

+    sal_Int16 mnColumns = 1;
+    sal_Int32 mnColumnSpacing = 0;
+
     // If it is detected at one point that the StatusHdl has to be called, but
     // this should not happen immediately (critical section):
     Timer               aStatusTimer;
@@ -614,8 +620,9 @@ private:

     std::unique_ptr<EditTextObject> GetEmptyTextObject();

+    std::tuple<const ParaPortion*, const EditLine*, tools::Long> GetPortionAndLine(Point aDocPos);
     EditPaM             GetPaM( Point aDocPos, bool bSmart = true );
-    EditPaM             GetPaM( ParaPortion* pPortion, Point aPos, bool bSmart );
+    bool IsTextPos(const Point& rDocPos, sal_uInt16 nBorder);
     tools::Long GetXPos(const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nIndex, bool bPreferPortionStart = false) const;
     tools::Long GetPortionXOffset(const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nTextPortion) const;
     sal_Int32 GetChar(const ParaPortion* pParaPortion, const EditLine* pLine, tools::Long nX, bool bSmart = true);
@@ -765,8 +772,8 @@ private:
     css::uno::Reference < css::i18n::XBreakIterator > const & ImplGetBreakIterator() const;
     css::uno::Reference < css::i18n::XExtendedInputSequenceChecker > const & ImplGetInputSequenceChecker() const;

-    void ImplUpdateOverflowingParaNum( sal_uInt32 );
-    void ImplUpdateOverflowingLineNum( sal_uInt32, sal_uInt32, sal_uInt32 );
+    void ImplUpdateOverflowingParaNum(tools::Long);
+    void ImplUpdateOverflowingLineNum(tools::Long, sal_uInt32, tools::Long);

     void CreateSpellInfo( bool bMultipleDocs );
     /// Obtains a view shell ID from the active EditView.
@@ -780,6 +787,8 @@ private:
     const ParaPortionList&  GetParaPortions() const { return aParaPortionList; }
     ParaPortionList&        GetParaPortions()       { return aParaPortionList; }

+    tools::Long Calc1ColumnTextHeight(tools::Long* pHeightNTP);
+
 protected:
     virtual void            Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;

@@ -807,6 +816,8 @@ public:
     void                    SetRotation( TextRotation nRotation);
     TextRotation            GetRotation() const                     { return GetEditDoc().GetRotation(); }

+    void SetTextColumns(sal_Int16 nColumns, sal_Int32 nSpacing);
+
     bool IsPageOverflow( ) const;

     void                    SetFixedCellHeight( bool bUseFixedCellHeight );
@@ -830,6 +841,8 @@ public:
     const Size&             GetMaxAutoPaperSize() const             { return aMaxAutoPaperSize; }
     void                    SetMaxAutoPaperSize( const Size& rSz )  { aMaxAutoPaperSize = rSz; }

+    void SetMinColumnWrapHeight(tools::Long nVal) { mnMinColumnWrapHeight = nVal; }
+
     void                    FormatDoc();
     void                    FormatFullDoc();
     void                    UpdateViews( EditView* pCurView = nullptr );
@@ -884,7 +897,7 @@ public:

     EditSelection   MoveParagraphs( Range aParagraphs, sal_Int32 nNewPos, EditView* pCurView );

-    sal_uInt32      CalcTextHeight( sal_uInt32* pHeightNTP );
+    tools::Long     CalcTextHeight( tools::Long* pHeightNTP );
     sal_uInt32      GetTextHeight() const;
     sal_uInt32      GetTextHeightNTP() const;
     sal_uInt32      CalcTextWidth( bool bIgnoreExtraSpace);
@@ -916,7 +929,8 @@ public:
     }

     tools::Rectangle       PaMtoEditCursor( EditPaM aPaM, GetCursorFlags nFlags = GetCursorFlags::NONE );
-    tools::Rectangle       GetEditCursor( ParaPortion* pPortion, sal_Int32 nIndex, GetCursorFlags nFlags = GetCursorFlags::NONE );
+    tools::Rectangle GetEditCursor(const ParaPortion* pPortion, const EditLine* pLine,
+                                   sal_Int32 nIndex, GetCursorFlags nFlags);

     bool            IsModified() const      { return aEditDoc.IsModified(); }
     void            SetModifyFlag( bool b ) { aEditDoc.SetModified( b ); }
@@ -1116,6 +1130,50 @@ public:
     void Dispose();
     void SetLOKSpecialPaperSize(const Size& rSize) { aLOKSpecialPaperSize = rSize; }
     const Size& GetLOKSpecialPaperSize() const { return aLOKSpecialPaperSize; }
+
+    enum class CallbackResult
+    {
+        Continue,
+        SkipThisPortion, // Do not call callback until next portion
+        Stop, // Stop iteration
+    };
+    struct LineAreaInfo
+    {
+        sal_Int32 nColumn; // Column number; when overflowing, equal to total number of columns
+        ParaPortion& rPortion; // Current ParaPortion
+        sal_Int32 nPortion;
+        EditLine* pLine; // Current line, or nullptr for paragraph start
+        sal_Int32 nLine;
+        tools::Rectangle aArea; // The area for the line (or for rPortion's first line offset)
+        tools::Long nHeightNeededToNotWrap;
+    };
+    using IterateLinesAreasFunc = std::function<CallbackResult(const LineAreaInfo&)>;
+    enum IterFlag // bitmask
+    {
+        none = 0,
+        inclILS = 1, // rArea includes interline space
+    };
+
+    void IterateLineAreas(const IterateLinesAreasFunc& f, IterFlag eOptions);
+
+    tools::Long GetColumnWidth(const Size& rPaperSize) const;
+    Point MoveToNextLine(Point& rMovePos, tools::Long nLineHeight, sal_Int32& nColumn,
+                         Point aOrigin, tools::Long* pnHeightNeededToNotWrap = nullptr) const;
+
+    tools::Long getXDirectionAware(const Point& pt) const;
+    tools::Long getYDirectionAware(const Point& pt) const;
+    tools::Long getWidthDirectionAware(const Size& sz) const;
+    tools::Long getHeightDirectionAware(const Size& sz) const;
+    void adjustXDirectionAware(Point& pt, tools::Long x) const;
+    void adjustYDirectionAware(Point& pt, tools::Long y) const;
+    void setXDirectionAware(Point& pt, tools::Long x) const;
+    void setYDirectionAware(Point& pt, tools::Long y) const;
+    tools::Long getYOverflowDirectionAware(const Point& pt, const tools::Rectangle& rectMax) const;
+    bool isXOverflowDirectionAware(const Point& pt, const tools::Rectangle& rectMax) const;
+    tools::Long getLeftDirectionAware(const tools::Rectangle& rect) const;
+    tools::Long getRightDirectionAware(const tools::Rectangle& rect) const;
+    tools::Long getTopDirectionAware(const tools::Rectangle& rect) const;
+    tools::Long getBottomDirectionAware(const tools::Rectangle& rect) const;
 };

 inline EPaM ImpEditEngine::CreateEPaM( const EditPaM& rPaM )
diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx
index 2c83c1165856..4980c5730de8 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -59,12 +59,14 @@
 #include <svl/asiancfg.hxx>
 #include <i18nutil/unicode.hxx>
 #include <tools/diagnose_ex.h>
+#include <comphelper/flagguard.hxx>
 #include <comphelper/lok.hxx>
 #include <comphelper/processfactory.hxx>
 #include <unotools/configmgr.hxx>

 #include <unicode/ubidi.h>
 #include <algorithm>
+#include <limits>
 #include <memory>
 #include <string_view>
 #include <fstream>
@@ -536,22 +538,47 @@ void ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
             if ( !IsFormatted() )
                 FormatDoc();

-            ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( GetEditDoc().GetPos( aPaM.GetNode() ) );
+            sal_Int32 nPortionPos = GetEditDoc().GetPos(aPaM.GetNode());
+            ParaPortion* pParaPortion = GetParaPortions().SafeGetObject(nPortionPos);
             if (pParaPortion)
             {
-                sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), true );
-                const EditLine& rLine = pParaPortion->GetLines()[nLine];
-                std::unique_ptr<tools::Rectangle[]> aRects(new tools::Rectangle[ mpIMEInfos->nLen ]);
-                for (sal_Int32 i = 0; i < mpIMEInfos->nLen; ++i)
-                {
-                    sal_Int32 nInputPos = mpIMEInfos->aPos.GetIndex() + i;
-                    if ( nInputPos > rLine.GetEnd() )
-                        nInputPos = rLine.GetEnd();
-                    tools::Rectangle aR2 = GetEditCursor( pParaPortion, nInputPos );
-                    aRects[ i ] = pView->GetImpEditView()->GetWindowPos( aR2 );
-                }
+                const sal_Int32 nMinPos = mpIMEInfos->aPos.GetIndex();
+                const sal_Int32 nMaxPos = nMinPos + mpIMEInfos->nLen - 1;
+                std::vector<tools::Rectangle> aRects(mpIMEInfos->nLen);
+
+                auto CollectCharPositions = [&](const LineAreaInfo& rInfo) {
+                    if (!rInfo.pLine) // Start of ParaPortion
+                    {
+                        if (rInfo.nPortion < nPortionPos)
+                            return CallbackResult::SkipThisPortion;
+                        if (rInfo.nPortion > nPortionPos)
+                            return CallbackResult::Stop;
+                        assert(&rInfo.rPortion == pParaPortion);
+                    }
+                    else // This is the needed ParaPortion
+                    {
+                        if (rInfo.pLine->GetStart() > nMaxPos)
+                            return CallbackResult::Stop;
+                        if (rInfo.pLine->GetEnd() < nMinPos)
+                            return CallbackResult::Continue;
+                        for (sal_Int32 n = nMinPos; n <= nMaxPos; ++n)
+                        {
+                            if (rInfo.pLine->IsIn(n))
+                            {
+                                tools::Rectangle aR = GetEditCursor(pParaPortion, rInfo.pLine, n,
+                                                                    GetCursorFlags::NONE);
+                                aR.Move(getLeftDirectionAware(rInfo.aArea),
+                                        getTopDirectionAware(rInfo.aArea));
+                                aRects[n - nMinPos] = pView->GetImpEditView()->GetWindowPos(aR);
+                            }
+                        }
+                    }
+                    return CallbackResult::Continue;
+                };
+                IterateLineAreas(CollectCharPositions, IterFlag::none);
+
                 if (vcl::Window* pWindow = pView->GetWindow())
-                    pWindow->SetCompositionCharRect( aRects.get(), mpIMEInfos->nLen );
+                    pWindow->SetCompositionCharRect(aRects.data(), aRects.size());
             }
         }
     }
@@ -3027,71 +3054,242 @@ EditPaM ImpEditEngine::InsertLineBreak(const EditSelection& aCurSel)

 //  Helper functions

+tools::Rectangle ImpEditEngine::GetEditCursor(const ParaPortion* pPortion, const EditLine* pLine,
+                                              sal_Int32 nIndex, GetCursorFlags nFlags)
+{
+    assert(pPortion && pLine);
+    // nIndex might be not in the line
+    // Search within the line...
+    tools::Long nX;
+
+    if ((nIndex == pLine->GetStart()) && (nFlags & GetCursorFlags::StartOfLine))
+    {
+        Range aXRange = GetLineXPosStartEnd(pPortion, pLine);
+        nX = !IsRightToLeft(GetEditDoc().GetPos(pPortion->GetNode())) ? aXRange.Min()
+                                                                      : aXRange.Max();
+    }
+    else if ((nIndex == pLine->GetEnd()) && (nFlags & GetCursorFlags::EndOfLine))
+    {
+        Range aXRange = GetLineXPosStartEnd(pPortion, pLine);
+        nX = !IsRightToLeft(GetEditDoc().GetPos(pPortion->GetNode())) ? aXRange.Max()
+                                                                      : aXRange.Min();
+    }
+    else
+    {
+        nX = GetXPos(pPortion, pLine, nIndex, bool(nFlags & GetCursorFlags::PreferPortionStart));
+    }
+
+    tools::Rectangle aEditCursor;
+    aEditCursor.SetLeft(nX);
+    aEditCursor.SetRight(nX);
+
+    aEditCursor.SetBottom(pLine->GetHeight() - 1);
+    if (nFlags & GetCursorFlags::TextOnly)
+        aEditCursor.SetTop(aEditCursor.Bottom() - pLine->GetTxtHeight() + 1);
+    else
+        aEditCursor.SetTop(aEditCursor.Bottom()
+                           - std::min(pLine->GetTxtHeight(), pLine->GetHeight()) + 1);
+    return aEditCursor;
+}
+
 tools::Rectangle ImpEditEngine::PaMtoEditCursor( EditPaM aPaM, GetCursorFlags nFlags )
 {
     OSL_ENSURE( GetUpdateMode(), "Must not be reached when Update=FALSE: PaMtoEditCursor" );

     tools::Rectangle aEditCursor;
-    tools::Long nY = 0;
-    for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
-    {
-        ParaPortion* pPortion = GetParaPortions()[nPortion];
-        ContentNode* pNode = pPortion->GetNode();
-        OSL_ENSURE( pNode, "Invalid Node in Portion!" );
-        if ( pNode != aPaM.GetNode() )
+    const sal_Int32 nIndex = aPaM.GetIndex();
+    const ParaPortion* pPortion = nullptr;
+    const EditLine* pLastLine = nullptr;
+    tools::Rectangle aLineArea;
+
+    auto FindPortionLineAndArea
+        = [&, bEOL(bool(nFlags & GetCursorFlags::EndOfLine))](const LineAreaInfo& rInfo) {
+        if (!rInfo.pLine) // start of ParaPortion
         {
-            nY += pPortion->GetHeight();
+            ContentNode* pNode = rInfo.rPortion.GetNode();
+            OSL_ENSURE(pNode, "Invalid Node in Portion!");
+            if (pNode != aPaM.GetNode())
+                return CallbackResult::SkipThisPortion;
+            pPortion = &rInfo.rPortion;
         }
-        else
+        else // guaranteed that this is the correct ParaPortion
         {
-            aEditCursor = GetEditCursor( pPortion, aPaM.GetIndex(), nFlags );
-            aEditCursor.AdjustTop(nY );
-            aEditCursor.AdjustBottom(nY );
-            return aEditCursor;
+            pLastLine = rInfo.pLine;
+            aLineArea = rInfo.aArea;
+            if ((rInfo.pLine->GetStart() == nIndex) || (rInfo.pLine->IsIn(nIndex, bEOL)))
+                return CallbackResult::Stop;
         }
+        return CallbackResult::Continue;
+    };
+    IterateLineAreas(FindPortionLineAndArea, IterFlag::none);
+
+    if (pLastLine)
+    {
+        aEditCursor = GetEditCursor(pPortion, pLastLine, nIndex, nFlags);
+        aEditCursor.Move(getLeftDirectionAware(aLineArea), getTopDirectionAware(aLineArea));
     }
-    OSL_FAIL( "Portion not found!" );
+    else
+        OSL_FAIL("Line not found!");
+
     return aEditCursor;
 }

+void ImpEditEngine::IterateLineAreas(const IterateLinesAreasFunc& f, IterFlag eOptions)
+{
+    const Point aOrigin(0, 0);
+    Point aLineStart(aOrigin);
+    const tools::Long nVertLineSpacing = CalcVertLineSpacing(aLineStart);
+    const tools::Long nColumnWidth = GetColumnWidth(aPaperSize);
+    sal_Int32 nColumn = 0;
+    for (sal_Int32 n = 0, nPortions = GetParaPortions().Count(); n < nPortions; ++n)
+    {
+        ParaPortion& rPortion = *GetParaPortions()[n];
+        bool bSkipThis = true;
+        if (rPortion.IsVisible())
+        {
+            // when typing idle formatting, asynchronous Paint. Invisible Portions may be invalid.
+            if (rPortion.IsInvalid())
+                return;
+
+            LineAreaInfo aInfo{
+                nColumn, // nColumn
+                rPortion, // rPortion
+                n, // nPortion
+                nullptr, // pLine
+                0, // nLine
+                { aLineStart, Size{ nColumnWidth, rPortion.GetFirstLineOffset() } }, // aArea
+                0 // nHeightNeededToNotWrap
+            };
+            auto eResult = f(aInfo);
+            if (eResult == CallbackResult::Stop)
+                return;
+            bSkipThis = eResult == CallbackResult::SkipThisPortion;
+
+            sal_uInt16 nSBL = 0;
+            if (!aStatus.IsOutliner())
+            {
+                const SvxLineSpacingItem& rLSItem
+                    = rPortion.GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
+                nSBL = (rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix)
+                           ? GetYValue(rLSItem.GetInterLineSpace())
+                           : 0;
+            }
+
+            adjustYDirectionAware(aLineStart, rPortion.GetFirstLineOffset());
+            for (sal_Int32 nLine = 0, nLines = rPortion.GetLines().Count(); nLine < nLines; nLine++)
+            {
+                EditLine& rLine = rPortion.GetLines()[nLine];
+                tools::Long nLineHeight = rLine.GetHeight();
+                if (nLine != nLines - 1)
+                    nLineHeight += nVertLineSpacing;
+                MoveToNextLine(aLineStart, nLineHeight, nColumn, aOrigin,
+                               &aInfo.nHeightNeededToNotWrap);
+                const bool bInclILS = eOptions & IterFlag::inclILS;
+                if (bInclILS && (nLine != nLines - 1) && !aStatus.IsOutliner())
+                {
+                    adjustYDirectionAware(aLineStart, nSBL);
+                    nLineHeight += nSBL;
+                }
+
+                if (!bSkipThis)
+                {
+                    Point aOtherCorner(aLineStart);
+                    adjustXDirectionAware(aOtherCorner, nColumnWidth);
+                    adjustYDirectionAware(aOtherCorner, -nLineHeight);
+
+                    // Calls to f() for each line
+                    aInfo.nColumn = nColumn;
+                    aInfo.pLine = &rLine;
+                    aInfo.nLine = nLine;
+                    aInfo.aArea = tools::Rectangle::Justify(aLineStart, aOtherCorner);
+                    eResult = f(aInfo);
+                    if (eResult == CallbackResult::Stop)
+                        return;
+                    bSkipThis = eResult == CallbackResult::SkipThisPortion;
+                }
+
+                if (!bInclILS && (nLine != nLines - 1) && !aStatus.IsOutliner())
+                    adjustYDirectionAware(aLineStart, nSBL);
+            }
+            if (!aStatus.IsOutliner())
+            {
+                const SvxULSpaceItem& rULItem
+                    = rPortion.GetNode()->GetContentAttribs().GetItem(EE_PARA_ULSPACE);
+                tools::Long nUL = GetYValue(rULItem.GetLower());
+                adjustYDirectionAware(aLineStart, nUL);
+            }
+        }
+        // Invisible ParaPortion has no height (see ParaPortion::GetHeight), don't handle it
+    }
+}
+
+std::tuple<const ParaPortion*, const EditLine*, tools::Long>
+ImpEditEngine::GetPortionAndLine(Point aDocPos)
+{
+    // First find the column from the point
+    sal_Int32 nClickColumn = 0;
+    for (tools::Long nColumnStart = 0, nColumnWidth = GetColumnWidth(aPaperSize);;
+         nColumnStart += mnColumnSpacing + nColumnWidth, ++nClickColumn)
+    {
+        if (aDocPos.X() <= nColumnStart + nColumnWidth + mnColumnSpacing / 2)
+            break;
+        if (nClickColumn >= mnColumns - 1)
+            break;
+    }
+
+    const ParaPortion* pLastPortion = nullptr;
+    const EditLine* pLastLine = nullptr;
+    tools::Long nLineStartX = 0;
+
+    auto FindLastMatchingPortionAndLine = [&](const LineAreaInfo& rInfo) {
+        if (rInfo.pLine) // Only handle lines, not ParaPortion starts
+        {
+            if (rInfo.nColumn > nClickColumn)
+                return CallbackResult::Stop;
+            pLastPortion = &rInfo.rPortion; // Candidate paragraph
+            pLastLine = rInfo.pLine; // Last visible line not later than click position
+            nLineStartX = getLeftDirectionAware(rInfo.aArea);
+            if (rInfo.nColumn == nClickColumn && getBottomDirectionAware(rInfo.aArea) > aDocPos.Y())
+                return CallbackResult::Stop; // Found it
+        }
+        return CallbackResult::Continue;
+    };
+    IterateLineAreas(FindLastMatchingPortionAndLine, IterFlag::inclILS);
+
+    return { pLastPortion, pLastLine, nLineStartX };
+}
+
 EditPaM ImpEditEngine::GetPaM( Point aDocPos, bool bSmart )
 {
     OSL_ENSURE( GetUpdateMode(), "Must not be reached when Update=FALSE: GetPaM" );

-    tools::Long nY = 0;
-    EditPaM aPaM;
-    sal_Int32 nPortion;
-    for ( nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
+    if (const auto& [pPortion, pLine, nLineStartX] = GetPortionAndLine(aDocPos); pPortion)
     {
-        ParaPortion* pPortion = GetParaPortions()[nPortion];
-        const tools::Long nTmpHeight = pPortion->GetHeight();     // should also be correct for !bVisible!
-        nY += nTmpHeight;
-        if ( nY > aDocPos.Y() )
-        {
-            nY -= nTmpHeight;
-            aDocPos.AdjustY( -nY );
-            // Skip invisible Portions:
-            while ( pPortion && !pPortion->IsVisible() )
-            {
-                nPortion++;
-                pPortion = GetParaPortions().SafeGetObject( nPortion );
-            }
-            SAL_WARN_IF(!pPortion, "editeng", "worrying lack of any visible paragraph");
-            if (!pPortion)
-                return aPaM;
-            return GetPaM(pPortion, aDocPos, bSmart);
+        sal_Int32 nCurIndex
+            = GetChar(pPortion, pLine, aDocPos.X() - nLineStartX, bSmart);
+        EditPaM aPaM(pPortion->GetNode(), nCurIndex);

+        if (nCurIndex && (nCurIndex == pLine->GetEnd())
+            && (pLine != &pPortion->GetLines()[pPortion->GetLines().Count() - 1]))
+        {
+            aPaM = CursorLeft(aPaM);
         }
+
+        return aPaM;
     }
-    // Then search for the last visible:
-    nPortion = GetParaPortions().Count()-1;
-    while ( nPortion && !GetParaPortions()[nPortion]->IsVisible() )
-        nPortion--;
+    return {};
+}

-    OSL_ENSURE( GetParaPortions()[nPortion]->IsVisible(), "No visible paragraph found: GetPaM" );
-    aPaM.SetNode( GetParaPortions()[nPortion]->GetNode() );
-    aPaM.SetIndex( GetParaPortions()[nPortion]->GetNode()->Len() );
-    return aPaM;
+bool ImpEditEngine::IsTextPos(const Point& rDocPos, sal_uInt16 nBorder)
+{
+    if (const auto& [pPortion, pLine, nLineStartX] = GetPortionAndLine(rDocPos); pPortion)
+    {
+        Range aLineXPosStartEnd = GetLineXPosStartEnd(pPortion, pLine);
+        if ((rDocPos.X() >= nLineStartX + aLineXPosStartEnd.Min() - nBorder)
+            && (rDocPos.X() <= nLineStartX + aLineXPosStartEnd.Max() + nBorder))
+            return true;
+    }
+    return false;
 }

 sal_uInt32 ImpEditEngine::GetTextHeight() const
@@ -3236,28 +3434,114 @@ sal_uInt32 ImpEditEngine::GetTextHeightNTP() const
     return nCurTextHeightNTP;
 }

-sal_uInt32 ImpEditEngine::CalcTextHeight( sal_uInt32* pHeightNTP )
+tools::Long ImpEditEngine::Calc1ColumnTextHeight(tools::Long* pHeightNTP)
 {
-    OSL_ENSURE( GetUpdateMode(), "Should not be used when Update=FALSE: CalcTextHeight" );
-    sal_uInt32 nY = 0;
-    sal_uInt32 nPH;
-    sal_uInt32 nEmptyHeight = 0;
-    for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) {
-        ParaPortion* pPortion = GetParaPortions()[nPortion];
-        nPH = pPortion->GetHeight();
-        nY += nPH;
-        if( pHeightNTP ) {
-            if ( pPortion->IsEmpty() )
-                nEmptyHeight += nPH;
-            else
-                nEmptyHeight = 0;
+    tools::Long nHeight = 0;
+    // Pretend that we have ~infinite height to get total height
+    comphelper::ValueRestorationGuard aGuard(nCurTextHeight,
+                                             std::numeric_limits<tools::Long>::max());
+
+    auto FindLastLineBottom = [&](const LineAreaInfo& rInfo) {
+        if (rInfo.pLine)
+        {
+            nHeight = getBottomDirectionAware(rInfo.aArea) + 1;
+            if (pHeightNTP && !rInfo.rPortion.IsEmpty())
+                *pHeightNTP = nHeight;
         }
-    }
+        return CallbackResult::Continue;
+    };
+    IterateLineAreas(FindLastLineBottom, IterFlag::none);
+    return nHeight;
+}

-    if ( pHeightNTP )
-        *pHeightNTP = nY - nEmptyHeight;
+tools::Long ImpEditEngine::CalcTextHeight(tools::Long* pHeightNTP)
+{
+    OSL_ENSURE( GetUpdateMode(), "Should not be used when Update=FALSE: CalcTextHeight" );

-    return nY;
+    if (mnColumns <= 1)
+        return Calc1ColumnTextHeight(pHeightNTP); // All text fits into a single column - done!
+
+    // The final column height can be smaller than total height divided by number of columns (taking
+    // into account first line offset and interline spacing, that aren't considered in positioning
+    // after the wrap). The wrap should only happen after the minimal height is exceeded.
+    tools::Long nTentativeColHeight = mnMinColumnWrapHeight;
+    tools::Long nWantedIncrease = 0;
+    tools::Long nCurrentTextHeight;
+
+    // This does the necessary column balancing for the case when the text does not fit min height.
+    // When the height of column (taken from nCurTextHeight) is too small, the last column will
+    // overflow, so the resulting height of the text will exceed the set column height. Increasing
+    // the column height step by step by the minimal value that allows one of columns to accomodate
+    // one line more, we finally get to the point where all the text fits. At each iteration, the
+    // height is only increased, so it's impossible to have infinite layout loops. The found value
+    // is the global minimum.
+    //
+    // E.g., given the following four line heights:
+    // Line 1: 10;
+    // Line 2: 12;
+    // Line 3: 10;
+    // Line 4: 10;
+    // number of columns 3, and the minimal paper height of 5, the iterations would be:
+    // * Tentative column height is set to 5
+    // <ITERATION 1>
+    // * Line 1 is attempted to go to column 0. Overflow is 5 => moved to column 1.
+    // * Line 2 is attempted to go to column 1 after Line 1; overflow is 17 => moved to column 2.
+    // * Line 3 is attempted to go to column 2 after Line 2; overflow is 17, stays in max column 2.
+    // * Line 4 goes to column 2 after Line 3.
+    // * Final iteration columns are: {empty}, {Line 1}, {Line 2, Line 3, Line 4}
+    // * Total text height is max({0, 10, 32}) == 32 > Tentative column height 5 => NEXT ITERATION
+    // * Minimal height increase that allows at least one column to accomodate one more line is
+    //   min({5, 17, 17}) = 5.
+    // * Tentative column height is set to 5 + 5 = 10.
+    // <ITERATION 2>
+    // * Line 1 goes to column 0, no overflow.
+    // * Line 2 is attempted to go to column 0 after Line 1; overflow is 12 => moved to column 1.
+    // * Line 3 is attempted to go to column 1 after Line 2; overflow is 12 => moved to column 2.
+    // * Line 4 is attempted to go to column 2 after Line 3; overflow is 10, stays in max column 2.
+    // * Final iteration columns are: {Line 1}, {Line 2}, {Line 3, Line 4}
+    // * Total text height is max({10, 12, 20}) == 20 > Tentative column height 10 => NEXT ITERATION
+    // * Minimal height increase that allows at least one column to accomodate one more line is
+    //   min({12, 12, 10}) = 10.
+    // * Tentative column height is set to 10 + 10 == 20.
+    // <ITERATION 3>
+    // * Line 1 goes to column 0, no overflow.
+    // * Line 2 is attempted to go to column 0 after Line 1; overflow is 2 => moved to column 1.
+    // * Line 3 is attempted to go to column 1 after Line 2; overflow is 2 => moved to column 2.
+    // * Line 4 is attempted to go to column 2 after Line 3; no overflow.
+    // * Final iteration columns are: {Line 1}, {Line 2}, {Line 3, Line 4}
+    // * Total text height is max({10, 12, 20}) == 20 == Tentative column height 20 => END.
+    do
+    {
+        nTentativeColHeight += nWantedIncrease;
+        nWantedIncrease = std::numeric_limits<tools::Long>::max();
+        nCurrentTextHeight = 0;
+        auto GetHeightAndWantedIncrease = [&, minHeight = tools::Long(0), lastCol = sal_Int32(0)](
+                                              const LineAreaInfo& rInfo) mutable {
+            if (rInfo.pLine)
+            {
+                if (lastCol != rInfo.nColumn)
+                {
+                    minHeight = std::max(nCurrentTextHeight,
+                                    minHeight); // total height can't be less than previous columns
+                    nWantedIncrease = std::min(rInfo.nHeightNeededToNotWrap, nWantedIncrease);
+                }
+                lastCol = rInfo.nColumn;
+                nCurrentTextHeight = std::max(getBottomDirectionAware(rInfo.aArea) + 1, minHeight);
+                if (pHeightNTP)
+                {
+                    if (rInfo.rPortion.IsEmpty())
+
+                        *pHeightNTP = std::max(*pHeightNTP, minHeight);
+                    else
+                        *pHeightNTP = nCurrentTextHeight;
+                }
+            }
+            return CallbackResult::Continue;
+        };
+        comphelper::ValueRestorationGuard aGuard(nCurTextHeight, nTentativeColHeight);
+        IterateLineAreas(GetHeightAndWantedIncrease, IterFlag::none);
+    } while (nCurrentTextHeight > nTentativeColHeight && nWantedIncrease > 0);
+    return nCurrentTextHeight;
 }

 sal_Int32 ImpEditEngine::GetLineCount( sal_Int32 nParagraph ) const
@@ -3683,62 +3967,6 @@ Range ImpEditEngine::GetInvalidYOffsets( ParaPortion* pPortion )
     return aRange;
 }

-EditPaM ImpEditEngine::GetPaM( ParaPortion* pPortion, Point aDocPos, bool bSmart )
-{
-    OSL_ENSURE( pPortion->IsVisible(), "Why GetPaM() for an invisible paragraph?" );
-    OSL_ENSURE( IsFormatted(), "GetPaM: Not formatted" );
-
-    sal_Int32 nCurIndex = 0;
-    EditPaM aPaM;
-    aPaM.SetNode( pPortion->GetNode() );
-
-    const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
-    sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
-                        ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
-
-    tools::Long nY = pPortion->GetFirstLineOffset();
-
-    OSL_ENSURE( pPortion->GetLines().Count(), "Empty ParaPortion in GetPaM!" );
-
-    const EditLine* pLine = nullptr;
-    for ( sal_Int32 nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ )
-    {
-        const EditLine& rTmpLine = pPortion->GetLines()[nLine];
-        nY += rTmpLine.GetHeight();
-        if ( !aStatus.IsOutliner() )
-            nY += nSBL;
-        if ( nY > aDocPos.Y() )
-        {
-            pLine = &rTmpLine;
-            break;                  // correct Y-position is not of interest
-        }
-
-        nCurIndex = nCurIndex + rTmpLine.GetLen();
-    }
-
-    if ( !pLine ) // may happen only in the range of SA!
-    {
-#if OSL_DEBUG_LEVEL > 0
-        const SvxULSpaceItem& rULSpace = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
-        OSL_ENSURE( nY+GetYValue( rULSpace.GetLower() ) >= aDocPos.Y() , "Index in no line, GetPaM ?" );
-#endif
-        aPaM.SetIndex( pPortion->GetNode()->Len() );
-        return aPaM;
-    }
-
-    // If no line found, only just X-Position => Index
-    nCurIndex = GetChar( pPortion, pLine, aDocPos.X(), bSmart );
-    aPaM.SetIndex( nCurIndex );
-
-    if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) &&
-         ( pLine != &pPortion->GetLines()[pPortion->GetLines().Count()-1] ) )
-    {
-        aPaM = CursorLeft( aPaM );
-    }
-
-    return aPaM;
-}
-
 sal_Int32 ImpEditEngine::GetChar(
     const ParaPortion* pParaPortion, const EditLine* pLine, tools::Long nXPos, bool bSmart)
 {
@@ -4202,91 +4430,6 @@ void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
     }
 }

-tools::Rectangle ImpEditEngine::GetEditCursor( ParaPortion* pPortion, sal_Int32 nIndex, GetCursorFlags nFlags )
-{
-    OSL_ENSURE( pPortion->IsVisible(), "Why GetEditCursor() for an invisible paragraph?" );
-    OSL_ENSURE( IsFormatted() || GetTextRanger(), "GetEditCursor: Not formatted" );
-
-    /*
-     GetCursorFlags::EndOfLine: If after the last character of a wrapped line, remaining
-     at the end of the line, not the beginning of the next one.
-     Purpose:   - END => really after the last character
-                - Selection...
-    */
-
-    tools::Long nY = pPortion->GetFirstLineOffset();
-
-    const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
-    sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
-                        ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
-
-    sal_Int32 nCurIndex = 0;
-    sal_Int32 nLineCount = pPortion->GetLines().Count();
-    OSL_ENSURE( nLineCount, "Empty ParaPortion in GetEditCursor!" );
-    if (nLineCount == 0)
-        return tools::Rectangle();
-    const EditLine* pLine = nullptr;
-    bool bEOL( nFlags & GetCursorFlags::EndOfLine );
-    for (sal_Int32 nLine = 0; nLine < nLineCount; ++nLine)
-    {
-        const EditLine& rTmpLine = pPortion->GetLines()[nLine];
-        if ( ( rTmpLine.GetStart() == nIndex ) || ( rTmpLine.IsIn( nIndex, bEOL ) ) )
-        {
-            pLine = &rTmpLine;
-            break;
-        }
-
-        nCurIndex = nCurIndex + rTmpLine.GetLen();
-        nY += rTmpLine.GetHeight();
-        if ( !aStatus.IsOutliner() )
-            nY += nSBL;
-    }
-    if ( !pLine )
-    {
-        // Cursor at the End of the paragraph.
-        OSL_ENSURE( nIndex == nCurIndex, "Index dead wrong in GetEditCursor!" );
-
-        pLine = &pPortion->GetLines()[nLineCount-1];
-        nY -= pLine->GetHeight();
-        if ( !aStatus.IsOutliner() )
-            nY -= nSBL;
-    }
-
-    tools::Rectangle aEditCursor;
-
-    aEditCursor.SetTop( nY );
-    nY += pLine->GetHeight();
-    aEditCursor.SetBottom( nY-1 );
-
-    // Search within the line...
-    tools::Long nX;
-
-    if ( ( nIndex == pLine->GetStart() ) && ( nFlags & GetCursorFlags::StartOfLine ) )
-    {
-        Range aXRange = GetLineXPosStartEnd( pPortion, pLine );
-        nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Min() : aXRange.Max();
-    }
-    else if ( ( nIndex == pLine->GetEnd() ) && ( nFlags & GetCursorFlags::EndOfLine ) )
-    {
-        Range aXRange = GetLineXPosStartEnd( pPortion, pLine );
-        nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Max() : aXRange.Min();
-    }
-    else
-    {
-        nX = GetXPos( pPortion, pLine, nIndex, bool( nFlags & GetCursorFlags::PreferPortionStart ) );
-    }
-
-    aEditCursor.SetLeft(nX);
-    aEditCursor.SetRight(nX);
-
-    if ( nFlags & GetCursorFlags::TextOnly )
-        aEditCursor.SetTop( aEditCursor.Bottom() - pLine->GetTxtHeight() + 1 );
-    else
-        aEditCursor.SetTop( aEditCursor.Bottom() - std::min( pLine->GetTxtHeight(), pLine->GetHeight() ) + 1 );
-
-    return aEditCursor;
-}
-
 void ImpEditEngine::SetValidPaperSize( const Size& rNewSz )
 {
     aPaperSize = rNewSz;
diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index 7df8aaa92bf4..e74958031a96 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -69,6 +69,7 @@
 #include <osl/diagnose.h>
 #include <comphelper/string.hxx>
 #include <memory>
+#include <set>

 #include <vcl/outdev/ScopedStates.hxx>

@@ -374,8 +375,8 @@ void ImpEditEngine::FormatDoc()

     // Here already, so that not always in CreateLines...
     bool bMapChanged = ImpCheckRefMapMode();
+    std::set<sal_Int32> aRepaintParas;

-    aInvalidRect = tools::Rectangle();  // make empty
     for ( sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
     {
         ParaPortion* pParaPortion = GetParaPortions()[nPara];
@@ -410,46 +411,21 @@ void ImpEditEngine::FormatDoc()
                 pParaPortion->SetMustRepaint( false );
             }

-            // InvalidRect set only once...
-            if ( aInvalidRect.IsEmpty() )
-            {
-                // For Paperwidth 0 (AutoPageSize) it would otherwise be Empty()...
-                tools::Long nWidth = std::max( tools::Long(1), ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) );
-                Range aInvRange( GetInvalidYOffsets( pParaPortion ) );
-                aInvalidRect = tools::Rectangle( Point( 0, nY+aInvRange.Min() ),
-                    Size( nWidth, aInvRange.Len() ) );
-            }
-            else
-            {
-                aInvalidRect.SetBottom( nY + pParaPortion->GetHeight() );
-            }
-        }
-        else if ( bGrow )
-        {
-            aInvalidRect.SetBottom( nY + pParaPortion->GetHeight() );
+            aRepaintParas.insert(nPara);
         }
         nY += pParaPortion->GetHeight();
     }

+    aInvalidRect = tools::Rectangle(); // make empty
+
     // One can also get into the formatting through UpdateMode ON=>OFF=>ON...
     // enable optimization first after Vobis delivery...
     {
-        sal_uInt32 nNewHeightNTP;
-        sal_uInt32 nNewHeight = CalcTextHeight( &nNewHeightNTP );
+        tools::Long nNewHeightNTP;
+        tools::Long nNewHeight = CalcTextHeight(&nNewHeightNTP);
         tools::Long nDiff = nNewHeight - nCurTextHeight;
         if ( nDiff )
             aStatus.GetStatusWord() |= !IsVertical() ? EditStatusFlags::TextHeightChanged : EditStatusFlags::TEXTWIDTHCHANGED;
-        if ( nNewHeight < nCurTextHeight )
-        {
-            aInvalidRect.SetBottom( static_cast<tools::Long>(std::max( nNewHeight, nCurTextHeight )) );
-            if ( aInvalidRect.IsEmpty() )
-            {
-                aInvalidRect.SetTop( 0 );
-                // Left and Right are not evaluated, are however set due to IsEmpty.
-                aInvalidRect.SetLeft( 0 );
-                aInvalidRect.SetRight( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() );
-            }
-        }

         nCurTextHeight = nNewHeight;
         nCurTextHeightNTP = nNewHeightNTP;
@@ -473,6 +449,20 @@ void ImpEditEngine::FormatDoc()
                 }
             }
         }
+
+        if (nDiff)
+            aInvalidRect.Union(tools::Rectangle::Justify(
+                { 0, nNewHeight }, { getWidthDirectionAware(aPaperSize), nCurTextHeight }));
+
+        if (!aRepaintParas.empty())
+        {
+            auto CombineRepaintParasAreas = [&](const LineAreaInfo& rInfo) {
+                if (aRepaintParas.count(rInfo.nPortion))
+                    aInvalidRect.Union(rInfo.aArea);
+                return CallbackResult::Continue;
+            };
+            IterateLineAreas(CombineRepaintParasAreas, IterFlag::inclILS);
+        }
     }

     bIsFormatting = false;
@@ -566,10 +556,10 @@ void ImpEditEngine::CheckPageOverflow()
 {
     SAL_INFO("editeng.chaining", "[CONTROL_STATUS] AutoPageSize is " << (( aStatus.GetControlWord() & EEControlBits::AUTOPAGESIZE ) ? "ON" : "OFF") );

-    sal_uInt32 nBoxHeight = GetMaxAutoPaperSize().Height();
+    tools::Long nBoxHeight = GetMaxAutoPaperSize().Height();
     SAL_INFO("editeng.chaining", "[OVERFLOW-CHECK] Current MaxAutoPaperHeight is " << nBoxHeight);

-    sal_uInt32 nTxtHeight = CalcTextHeight(nullptr);
+    tools::Long nTxtHeight = CalcTextHeight(nullptr);
     SAL_INFO("editeng.chaining", "[OVERFLOW-CHECK] Current Text Height is " << nTxtHeight);

     sal_uInt32 nParaCount = GetParaPortions().Count();
@@ -598,6 +588,13 @@ static sal_Int32 ImplCalculateFontIndependentLineSpacing( const sal_Int32 nFontH
     return ( nFontHeight * 12 ) / 10;   // + 20%
 }

+tools::Long ImpEditEngine::GetColumnWidth(const Size& rPaperSize) const
+{
+    assert(mnColumns >= 1);
+    tools::Long nWidth = IsVertical() ? rPaperSize.Height() : rPaperSize.Width();
+    return (nWidth - mnColumnSpacing * (mnColumns - 1)) / mnColumns;
+}
+
 bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
 {
     ParaPortion* pParaPortion = GetParaPortions()[nPara];
@@ -785,11 +782,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
             }
         }

-        tools::Long nMaxLineWidth;
-        if ( !IsVertical() )
-            nMaxLineWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : aPaperSize.Width();
-        else
-            nMaxLineWidth = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : aPaperSize.Height();
+        const bool bAutoSize = IsVertical() ? aStatus.AutoPageHeight() : aStatus.AutoPageWidth();
+        tools::Long nMaxLineWidth = GetColumnWidth(bAutoSize ? aMaxAutoPaperSize : aPaperSize);

         nMaxLineWidth -= GetXValue( rLRItem.GetRight() );
         nMaxLineWidth -= nStartX;
@@ -797,7 +791,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
         // If PaperSize == long_max, one cannot take away any negative
         // first line indent. (Overflow)
         if ( ( nMaxLineWidth < 0 ) && ( nStartX < 0 ) )
-            nMaxLineWidth = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) - GetXValue( rLRItem.GetRight() );
+            nMaxLineWidth = GetColumnWidth(aPaperSize) - GetXValue(rLRItem.GetRight());

         // If still less than 0, it may be just the right edge.
         if ( nMaxLineWidth <= 0 )
@@ -824,7 +818,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
         {
             GetTextRanger()->SetVertical( IsVertical() );

-            tools::Long nTextY = nStartPosY + GetEditCursor( pParaPortion, pLine->GetStart() ).Top();
+            tools::Long nTextY = nStartPosY + GetEditCursor( pParaPortion, pLine, pLine->GetStart(), GetCursorFlags::NONE ).Top();
             if ( !bSameLineAgain )
             {
                 SeekCursor( pNode, nTmpPos+1, aTmpFont );
@@ -885,7 +879,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                     nTextExtraYOffset += std::max( static_cast<tools::Long>(nTextLineHeight / 10), tools::Long(1) );
                     if ( ( nTextY + nTextExtraYOffset  ) > GetTextRanger()->GetBoundRect().Bottom() )
                     {
-                        nXWidth = !IsVertical() ? GetPaperSize().Width() : GetPaperSize().Height();
+                        nXWidth = getWidthDirectionAware(GetPaperSize());
                         if ( !nXWidth ) // AutoPaperSize
                             nXWidth = 0x7FFFFFFF;
                     }
@@ -1468,7 +1462,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
             // has to be used for the Alignment. If it does not fit or if it
             // will change the paper width, it will be formatted again for
             // Justification! = LEFT anyway.
-            tools::Long nMaxLineWidthFix = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() )
+            tools::Long nMaxLineWidthFix = GetColumnWidth(aPaperSize)
                                         - GetXValue( rLRItem.GetRight() ) - nStartX;
             if ( aTextSize.Width() < nMaxLineWidthFix )
                 nMaxLineWidth = nMaxLineWidthFix;
@@ -1725,7 +1719,7 @@ void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion )
     {
         sal_Int32 nPara = GetParaPortions().GetPos( pParaPortion );
         SvxAdjust eJustification = GetJustification( nPara );
-        tools::Long nMaxLineWidth = !IsVertical() ? aPaperSize.Width() : aPaperSize.Height();
+        tools::Long nMaxLineWidth = GetColumnWidth(aPaperSize);
         nMaxLineWidth -= GetXValue( rLRItem.GetRight() );
         if ( nMaxLineWidth < 0 )
             nMaxLineWidth = 1;
@@ -2636,6 +2630,20 @@ void ImpEditEngine::SetRotation(TextRotation nRotation)
     }
 }

+void ImpEditEngine::SetTextColumns(sal_Int16 nColumns, sal_Int32 nSpacing)
+{
+    if (mnColumns != nColumns || mnColumnSpacing != nSpacing)
+    {
+        mnColumns = nColumns;
+        mnColumnSpacing = nSpacing;
+        if (IsFormatted())
+        {
+            FormatFullDoc();
+            UpdateViews(GetActiveView());
+        }
+    }
+}
+
 void ImpEditEngine::SetFixedCellHeight( bool bUseFixedCellHeight )
 {
     if ( IsFixedCellHeight() != bUseFixedCellHeight )
@@ -2949,6 +2957,177 @@ void ImpEditEngine::RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics
     }
 }

+tools::Long ImpEditEngine::getXDirectionAware(const Point& pt) const
+{
+    if (!IsVertical())
+        return pt.X();
+    else
+        return pt.Y();
+}
+
+tools::Long ImpEditEngine::getYDirectionAware(const Point& pt) const
+{
+    if (!IsVertical())
+        return pt.Y();
+    else
+        return pt.X();
+}
+
+tools::Long ImpEditEngine::getWidthDirectionAware(const Size& sz) const
+{
+    return !IsVertical() ? sz.Width() : sz.Height();
+}
+
+tools::Long ImpEditEngine::getHeightDirectionAware(const Size& sz) const
+{
+    return !IsVertical() ? sz.Height() : sz.Width();
+}
+
+void ImpEditEngine::adjustXDirectionAware(Point& pt, tools::Long x) const
+{
+    if (!IsVertical())
+        pt.AdjustX(x);
+    else
+        pt.AdjustY(IsTopToBottom() ? x : -x);
+}
+
+void ImpEditEngine::adjustYDirectionAware(Point& pt, tools::Long y) const
+{
+    if (!IsVertical())
+        pt.AdjustY(y);
+    else
+        pt.AdjustX(IsTopToBottom() ? -y : y);
+}
+
+void ImpEditEngine::setXDirectionAware(Point& pt, tools::Long x) const
+{
+    if (!IsVertical())
+        pt.setX(x);
+    else
+        pt.setY(x);
+}
+
+void ImpEditEngine::setYDirectionAware(Point& pt, tools::Long y) const
+{
+    if (!IsVertical())
+        pt.setY(y);
+    else
+        pt.setX(y);
+}
+
+tools::Long ImpEditEngine::getYOverflowDirectionAware(const Point& pt,
+                                                      const tools::Rectangle& rectMax) const
+{
+    tools::Long nRes;
+    if (!IsVertical())
+        nRes = pt.Y() - rectMax.Bottom();
+    else if (IsTopToBottom())
+        nRes = rectMax.Left() - pt.X();
+    else
+        nRes = pt.X() - rectMax.Right();
+    return std::max(nRes, tools::Long(0));
+}
+
+bool ImpEditEngine::isXOverflowDirectionAware(const Point& pt, const tools::Rectangle& rectMax) const
+{
+    if (!IsVertical())
+        return pt.X() > rectMax.Right();
+
+    if (IsTopToBottom())
+        return pt.Y() > rectMax.Bottom();
+    else
+        return pt.Y() < rectMax.Top();
+}
+
+tools::Long ImpEditEngine::getLeftDirectionAware(const tools::Rectangle& rect) const
+{
+    if (!IsVertical())
+        return rect.Left();
+
+    if (IsTopToBottom())
+        return rect.Top();
+    else
+        return rect.Bottom();
+}
+
+tools::Long ImpEditEngine::getRightDirectionAware(const tools::Rectangle& rect) const
+{
+    if (!IsVertical())
+        return rect.Right();
+
+    if (IsTopToBottom())
+        return rect.Bottom();
+    else
+        return rect.Top();
+}
+
+tools::Long ImpEditEngine::getTopDirectionAware(const tools::Rectangle& rect) const
+{
+    if (!IsVertical())
+        return rect.Top();
+
+    if (IsTopToBottom())
+        return rect.Right();
+    else
+        return rect.Left();
+}
+
+tools::Long ImpEditEngine::getBottomDirectionAware(const tools::Rectangle& rect) const
+{
+    if (!IsVertical())
+        return rect.Bottom();
+
+    if (IsTopToBottom())
+        return rect.Left();
+    else
+        return rect.Right();
+}
+
+// Returns the resulting shift for the point; allows to apply the same shift to other points
+Point ImpEditEngine::MoveToNextLine(
+    Point& rMovePos, // [in, out] Point that will move to the next line
+    tools::Long nLineHeight, // [in] Y-direction move distance (direction-aware)
+    sal_Int32& rColumn, // [in, out] current column number
+    Point aOrigin, // [in] Origin point to calculate limits and initial Y position in a new column
+    tools::Long* pnHeightNeededToNotWrap // On column wrap, returns how much more height is needed
+) const
+{
+    const Point aOld = rMovePos;
+
+    // Move the point by the requested distance in Y direction
+    adjustYDirectionAware(rMovePos, nLineHeight);
+    // Check if the resulting position has moved beyond the limits, and more columns left.
+    // The limits are defined by a rectangle starting from aOrigin with width of aPaperSize
+    // and height of nCurTextHeight
+    Size aActPaperSize(aPaperSize);
+    if (IsVertical())
+        aActPaperSize.setWidth(nCurTextHeight);
+    else
+        aActPaperSize.setHeight(nCurTextHeight);
+    tools::Long nNeeded = getYOverflowDirectionAware(rMovePos, { aOrigin, aActPaperSize });
+    if (pnHeightNeededToNotWrap)
+        *pnHeightNeededToNotWrap = nNeeded;
+    if (nNeeded && rColumn < mnColumns)
+    {
+        ++rColumn;
+        // If we didn't fit into the last column, indicate that only by setting the column number
+        // to the total number of columns; do not adjust
+        if (rColumn < mnColumns)
+        {
+            // Set Y position of the point to that of aOrigin
+            setYDirectionAware(rMovePos, getYDirectionAware(aOrigin));
+            // Move the point by the requested distance in Y direction
+            adjustYDirectionAware(rMovePos, nLineHeight);
+            // Move the point by the column+spacing distance in X direction
+            adjustXDirectionAware(rMovePos, GetColumnWidth(aPaperSize) + mnColumnSpacing);
+        }
+    }
+
+    return rMovePos - aOld;
+}
+
+// TODO: use IterateLineAreas in ImpEditEngine::Paint, to avoid algorithm duplication
+
 void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Point aStartPos, bool bStripOnly, Degree10 nOrientation )
 {
     if ( !GetUpdateMode() && !bStripOnly )
@@ -2987,6 +3166,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po

     tools::Long nVertLineSpacing = CalcVertLineSpacing(aStartPos);

+    sal_Int32 nColumn = 0;

     // Over all the paragraphs...

@@ -3018,17 +3198,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po

             bool bEndOfParagraphWritten(false);

-            if ( !IsVertical() )
-                aStartPos.AdjustY(pPortion->GetFirstLineOffset() );
-            else
-            {
-                if( IsTopToBottom() )
-                    aStartPos.AdjustX( -(pPortion->GetFirstLineOffset()) );
-                else
-                    aStartPos.AdjustX(pPortion->GetFirstLineOffset() );
-            }
-
-            Point aParaStart( aStartPos );
+            adjustYDirectionAware(aStartPos, pPortion->GetFirstLineOffset());

             const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
             sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
@@ -3040,34 +3210,13 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                 pLine = &pPortion->GetLines()[nLine];
                 nIndex = pLine->GetStart();
                 DBG_ASSERT( pLine, "NULL-Pointer in the line iterator in UpdateViews" );
+                tools::Long nLineHeight = pLine->GetHeight();
+                if (nLine != nLastLine)
+                    nLineHeight += nVertLineSpacing;
+                MoveToNextLine(aStartPos, nLineHeight, nColumn, aOrigin);
                 aTmpPos = aStartPos;
-                if ( !IsVertical() )
-                {
-                    aTmpPos.AdjustX(pLine->GetStartPosX() );
-                    aTmpPos.AdjustY(pLine->GetMaxAscent() );
-                    aStartPos.AdjustY(pLine->GetHeight() );
-                    if (nLine != nLastLine)
-                        aStartPos.AdjustY(nVertLineSpacing );
-                }
-                else
-                {
-                    if ( IsTopToBottom() )
-                    {
-                        aTmpPos.AdjustY(pLine->GetStartPosX() );
-                        aTmpPos.AdjustX( -(pLine->GetMaxAscent()) );
-                        aStartPos.AdjustX( -(pLine->GetHeight()) );
-                        if (nLine != nLastLine)
-                            aStartPos.AdjustX( -nVertLineSpacing );
-                    }
-                    else
-                    {
-                        aTmpPos.AdjustY( -(pLine->GetStartPosX()) );
-                        aTmpPos.AdjustX(pLine->GetMaxAscent() );
-                        aStartPos.AdjustX(pLine->GetHeight() );
-                        if (nLine != nLastLine)
-                            aStartPos.AdjustX(nVertLineSpacing );
-                    }
-                }
+                adjustXDirectionAware(aTmpPos, pLine->GetStartPosX());
+                adjustYDirectionAware(aTmpPos, pLine->GetMaxAscent() - nLineHeight);

                 if ( ( !IsVertical() && ( aStartPos.Y() > aClipRect.Top() ) )
                     || ( IsVertical() && IsTopToBottom() && aStartPos.X() < aClipRect.Right() )
@@ -3081,7 +3230,9 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                     // does, too. No change for not-layouting (painting).
                     if(0 == nLine) // && !bStripOnly)
                     {
-                        GetEditEnginePtr()->PaintingFirstLine( n, aParaStart, aTmpPos.Y(), aOrigin, nOrientation, pOutDev );
+                        Point aLineStart(aStartPos);
+                        adjustYDirectionAware(aLineStart, -nLineHeight);
+                        GetEditEnginePtr()->PaintingFirstLine( n, aLineStart, aTmpPos.Y(), aOrigin, nOrientation, pOutDev );

                         // Remember whether a bullet was painted.
                         const SfxBoolItem& rBulletState = pEditEngine->GetParaAttrib(n, EE_PARA_BULLETSTATE);
@@ -3100,27 +3251,10 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                         const TextPortion& rTextPortion = pPortion->GetTextPortions()[nPortion];

                         tools::Long nPortionXOffset = GetPortionXOffset( pPortion, pLine, nPortion );
-                        if ( !IsVertical() )
-                        {
-                            aTmpPos.setX( aStartPos.X() + nPortionXOffset );
-                            if ( aTmpPos.X() > aClipRect.Right() )
-                                break;  // No further output in line necessary
-                        }
-                        else
-                        {
-                            if( IsTopToBottom() )
-                            {
-                                aTmpPos.setY( aStartPos.Y() + nPortionXOffset );
-                                if ( aTmpPos.Y() > aClipRect.Bottom() )
-                                    break;  // No further output in line necessary
-                            }
-                            else
-                            {
-                                aTmpPos.setY( aStartPos.Y() - nPortionXOffset );
-                                if (aTmpPos.Y() < aClipRect.Top())
-                                    break;  // No further output in line necessary
-                            }
-                        }
+                        setXDirectionAware(aTmpPos, getXDirectionAware(aStartPos));
+                        adjustXDirectionAware(aTmpPos, nPortionXOffset);
+                        if (isXOverflowDirectionAware(aTmpPos, aClipRect))
+                            break; // No further output in line necessary

                         switch ( rTextPortion.GetKind() )
                         {
@@ -3208,44 +3342,12 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                                                 const tools::Long nAdvanceY = -pLine->GetMaxAscent();

                                                 Point aTopLeftRectPos( aTmpPos );
-                                                if ( !IsVertical() )
-                                                {
-                                                    aTopLeftRectPos.AdjustX(nAdvanceX );
-                                                    aTopLeftRectPos.AdjustY(nAdvanceY );
-                                                }
-                                                else
-                                                {
-                                                    if( IsTopToBottom() )
-                                                    {
-                                                        aTopLeftRectPos.AdjustY( -nAdvanceX );
-                                                        aTopLeftRectPos.AdjustX(nAdvanceY );
-                                                    }
-                                                    else
-                                                    {
-                                                        aTopLeftRectPos.AdjustY(nAdvanceX );
-                                                        aTopLeftRectPos.AdjustX( -nAdvanceY );
-                                                    }
-                                                }
+                                                adjustXDirectionAware(aTopLeftRectPos, nAdvanceX);
+                                                adjustYDirectionAware(aTopLeftRectPos, nAdvanceY);

                                                 Point aBottomRightRectPos( aTopLeftRectPos );
-                                                if ( !IsVertical() )
-                                                {
-                                                    aBottomRightRectPos.AdjustX(2 * nHalfBlankWidth );
-                                                    aBottomRightRectPos.AdjustY(pLine->GetHeight() );
-                                                }
-                                                else
-                                                {
-                                                    if (IsTopToBottom())
-                                                    {
-                                                        aBottomRightRectPos.AdjustX(pLine->GetHeight() );
-                                                        aBottomRightRectPos.AdjustY( -(2 * nHalfBlankWidth) );
-                                                    }
-                                                    else
-                                                    {
-                                                        aBottomRightRectPos.AdjustX( -(pLine->GetHeight()) );
-                                                        aBottomRightRectPos.AdjustY(2 * nHalfBlankWidth );
-                                                    }
-                                                }
+                                                adjustXDirectionAware(aBottomRightRectPos, 2 * nHalfBlankWidth);
+                                                adjustYDirectionAware(aBottomRightRectPos, pLine->GetHeight());

                                                 pOutDev->Push( PushFlags::FILLCOLOR );
                                                 pOutDev->Push( PushFlags::LINECOLOR );
@@ -3271,17 +3373,8 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                                                     const Size aSlashSize = aTmpFont.QuickGetTextSize( pOutDev, aSlash, 0, 1 );
                                                     Point aSlashPos( aTmpPos );
                                                     const tools::Long nAddX = nHalfBlankWidth - aSlashSize.Width() / 2;
-                                                    if ( !IsVertical() )
-                                                    {
-                                                        aSlashPos.setX( aTopLeftRectPos.X() + nAddX );
-                                                    }
-                                                    else
-                                                    {
-                                                        if (IsTopToBottom())
-                                                            aSlashPos.setY( aTopLeftRectPos.Y() + nAddX );
-                                                        else
-                                                            aSlashPos.setY( aTopLeftRectPos.Y() - nAddX );
-                                                    }
+                                                    setXDirectionAware(aSlashPos, getXDirectionAware(aTopLeftRectPos));
+                                                    adjustXDirectionAware(aSlashPos, nAddX);

                                                     aTmpFont.QuickDrawText( pOutDev, aSlashPos, aSlash, 0, 1 );

@@ -3325,24 +3418,8 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                                             // what will lead to a compressed look with multiple lines
                                             const sal_uInt16 nMaxAscent(pLine->GetMaxAscent());

-                                            if ( !IsVertical() )
-                                            {
-                                                aStartPos.AdjustY(nMaxAscent );
-                                                aTmpPos.AdjustY(nMaxAscent );
-                                            }
-                                            else
-                                            {
-                                                if (IsTopToBottom())
-                                                {
-                                                    aTmpPos.AdjustX( -nMaxAscent );
-                                                    aStartPos.AdjustX( -nMaxAscent );
-                                                }
-                                                else
-                                                {
-                                                    aTmpPos.AdjustX(nMaxAscent );
-                                                    aStartPos.AdjustX(nMaxAscent );
-                                                }
-                                            }
+                                            aTmpPos += MoveToNextLine(aStartPos, nMaxAscent,
+                                                                      nColumn, aOrigin);
                                         }
                                         std::vector< sal_Int32 >::iterator curIt = itSubLines;
                                         ++itSubLines;
@@ -3509,15 +3586,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                                         if ( aTmpFont.GetEscapement() )
                                         {
                                             tools::Long nDiff = aTmpFont.GetFontSize().Height() * aTmpFont.GetEscapement() / 100L;
-                                            if ( !IsVertical() )
-                                                aOutPos.AdjustY( -nDiff );
-                                            else
-                                            {
-                                                if (IsTopToBottom())
-                                                    aOutPos.AdjustX(nDiff );
-                                                else
-                                                    aOutPos.AdjustX( -nDiff );
-                                            }
+                                            adjustYDirectionAware(aOutPos, -nDiff);
                                             aRedLineTmpPos = aOutPos;
                                             aTmpFont.SetEscapement( 0 );
                                         }
@@ -3644,13 +3713,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                                             if( _nEsc )
                                             {
                                                 tools::Long nShift = (_nEsc * aTmpFont.GetFontSize().Height()) / 100L;
-                                                if( !IsVertical() )
-                                                    aRedLineTmpPos.AdjustY( -nShift );
-                                                else
-                                                    if (IsTopToBottom())
-                                                        aRedLineTmpPos.AdjustX(nShift );
-                                                    else
-                                                        aRedLineTmpPos.AdjustX( -nShift );
+                                                adjustYDirectionAware(aRedLineTmpPos, -nShift);
                                             }
                                         }
                                         Color aOldColor( pOutDev->GetLineColor() );
@@ -3764,23 +3827,11 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po

                 if ( ( nLine != nLastLine ) && !aStatus.IsOutliner() )
                 {
-                    if ( !IsVertical() )
-                        aStartPos.AdjustY(nSBL );
-                    else
-                    {
-                        if( IsTopToBottom() )
-                            aStartPos.AdjustX( -nSBL );
-                        else
-                            aStartPos.AdjustX(nSBL );
-                    }
+                    adjustYDirectionAware(aStartPos, nSBL);
                 }

                 // no more visible actions?
-                if ( !IsVertical() && ( aStartPos.Y() >= aClipRect.Bottom() ) )
-                    break;
-                else if ( IsVertical() && IsTopToBottom() && ( aStartPos.X() <= aClipRect.Left() ) )
-                    break;
-                else if (IsVertical() && !IsTopToBottom() && (aStartPos.X() >= aClipRect.Right()))
+                if (getYOverflowDirectionAware(aStartPos, aClipRect))
                     break;
             }

@@ -3788,15 +3839,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
             {
                 const SvxULSpaceItem& rULItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
                 tools::Long nUL = GetYValue( rULItem.GetLower() );
-                if ( !IsVertical() )
-                    aStartPos.AdjustY(nUL );
-                else
-                {
-                    if (IsTopToBottom())
-                        aStartPos.AdjustX( -nUL );
-                    else
-                        aStartPos.AdjustX(nUL );
-                }
+                adjustYDirectionAware(aStartPos, nUL);
             }

             // #108052# Safer way for #i108052# and #i118881#: If for the current ParaPortion
@@ -3822,26 +3865,14 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
         }
         else
         {
-            if ( !IsVertical() )
-                aStartPos.AdjustY(nParaHeight );
-            else
-            {
-                if (IsTopToBottom())
-                    aStartPos.AdjustX( -nParaHeight );
-                else
-                    aStartPos.AdjustX(nParaHeight );
-            }
+            adjustYDirectionAware(aStartPos, nParaHeight);
         }

         if ( pPDFExtOutDevData )
             pPDFExtOutDevData->EndStructureElement();

         // no more visible actions?
-        if ( !IsVertical() && ( aStartPos.Y() > aClipRect.Bottom() ) )
-            break;
-        if ( IsVertical() && IsTopToBottom() && ( aStartPos.X() < aClipRect.Left() ) )
-            break;
-        if (IsVertical() && !IsTopToBottom() && ( aStartPos.X() > aClipRect.Right() ) )
+        if (getYOverflowDirectionAware(aStartPos, aClipRect))
             break;
     }
 }
@@ -3861,26 +3892,16 @@ void ImpEditEngine::Paint( ImpEditView* pView, const tools::Rectangle& rRect, Ou

     Point aStartPos;
     if ( !IsVertical() )
-    {
         aStartPos = pView->GetOutputArea().TopLeft();
-        aStartPos.AdjustX( -(pView->GetVisDocLeft()) );
-        aStartPos.AdjustY( -(pView->GetVisDocTop()) );
-    }
     else
     {
         if( IsTopToBottom() )
-        {
             aStartPos = pView->GetOutputArea().TopRight();
-            aStartPos.AdjustX(pView->GetVisDocTop() );
-            aStartPos.AdjustY( -(pView->GetVisDocLeft()) );
-        }
         else
-        {
             aStartPos = pView->GetOutputArea().BottomLeft();
-            aStartPos.AdjustX( -(pView->GetVisDocTop()) );
-            aStartPos.AdjustY(pView->GetVisDocLeft() );
-        }
     }
+    adjustXDirectionAware(aStartPos, -(pView->GetVisDocLeft()));
+    adjustYDirectionAware(aStartPos, -(pView->GetVisDocTop()));

     // If Doc-width < Output Area,Width and not wrapped fields,
     // the fields usually protrude if > line.
@@ -4029,7 +4050,7 @@ EditSelection ImpEditEngine::MoveParagraphs( Range aOldPositions, sal_Int32 nNew
         {
             aInvalidRect = tools::Rectangle();  // make empty
             aInvalidRect.SetLeft( 0 );
-            aInvalidRect.SetRight( aPaperSize.Width() );
+            aInvalidRect.SetRight(GetColumnWidth(aPaperSize));
             aInvalidRect.SetTop( GetParaPortions().GetYOffset( pUpperPortion ) );
             aInvalidRect.SetBottom( GetParaPortions().GetYOffset( pLowerPortion ) + pLowerPortion->GetHeight() );

@@ -4159,19 +4180,14 @@ tools::Long ImpEditEngine::CalcVertLineSpacing(Point& rStartPos) const
         }
     }

-    tools::Long nTotalSpace = IsVertical() ? aPaperSize.Width() : aPaperSize.Height();
+    tools::Long nTotalSpace = getHeightDirectionAware(aPaperSize);
     nTotalSpace -= nTotalOccupiedHeight;
     if (nTotalSpace <= 0 || nTotalLineCount <= 1)
         return 0;

+    // Shift the text to the right for the asian layout mode.
     if (IsVertical())
-    {
-        if( IsTopToBottom() )
-            // Shift the text to the right for the asian layout mode.
-            rStartPos.AdjustX(nTotalSpace );
-        else
-            rStartPos.AdjustX( -nTotalSpace );
-    }
+        adjustYDirectionAware(rStartPos, -nTotalSpace);

     return nTotalSpace / (nTotalLineCount-1);
 }
@@ -4248,7 +4264,7 @@ void ImpEditEngine::SetFlatMode( bool bFlat )

 void ImpEditEngine::SetCharStretching( sal_uInt16 nX, sal_uInt16 nY )
 {
-    bool bChanged(false);
+    bool bChanged;
     if ( !IsVertical() )
     {
         bChanged = nStretchX!=nX || nStretchY!=nY;
@@ -4632,10 +4648,10 @@ void ImpEditEngine::ImplExpandCompressedPortions( EditLine* pLine, ParaPortion*
     }
 }

-void ImpEditEngine::ImplUpdateOverflowingParaNum(sal_uInt32 nPaperHeight)
+void ImpEditEngine::ImplUpdateOverflowingParaNum(tools::Long nPaperHeight)
 {
-    sal_uInt32 nY = 0;
-    sal_uInt32 nPH;
+    tools::Long nY = 0;
+    tools::Long nPH;

     for ( sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++ ) {
         ParaPortion* pPara = GetParaPortions()[nPara];
@@ -4651,12 +4667,12 @@ void ImpEditEngine::ImplUpdateOverflowingParaNum(sal_uInt32 nPaperHeight)
     }
 }

-void ImpEditEngine::ImplUpdateOverflowingLineNum(sal_uInt32 nPaperHeight,
+void ImpEditEngine::ImplUpdateOverflowingLineNum(tools::Long nPaperHeight,
                                              sal_uInt32 nOverflowingPara,
-                                             sal_uInt32 nHeightBeforeOverflowingPara)
+                                             tools::Long nHeightBeforeOverflowingPara)
 {
-    sal_uInt32 nY = nHeightBeforeOverflowingPara;
-    sal_uInt32 nLH;
+    tools::Long nY = nHeightBeforeOverflowingPara;
+    tools::Long nLH;

     ParaPortion *pPara = GetParaPortions()[nOverflowingPara];

diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx
index e42a36c5e826..c41b8169a4cb 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -1094,7 +1094,7 @@ std::unique_ptr<EditTextObject> ImpEditEngine::CreateTextObject( EditSelection a
     // sleeper set up when Olli paragraphs not hacked!
     if ( bAllowBigObjects && bOnlyFullParagraphs && IsFormatted() && GetUpdateMode() && ( nTextPortions >= nBigObjectStart ) )
     {
-        XParaPortionList* pXList = new XParaPortionList( GetRefDevice(), aPaperSize.Width(), nStretchX, nStretchY );
+        XParaPortionList* pXList = new XParaPortionList( GetRefDevice(), GetColumnWidth(aPaperSize), nStretchX, nStretchY );
         pTxtObj->mpImpl->SetPortionInfo(std::unique_ptr<XParaPortionList>(pXList));
         for ( nNode = nStartNode; nNode <= nEndNode; nNode++  )
         {
@@ -1177,7 +1177,7 @@ EditSelection ImpEditEngine::InsertTextObject( const EditTextObject& rTextObject
     bool bUsePortionInfo = false;
     XParaPortionList* pPortionInfo = rTextObject.mpImpl->GetPortionInfo();

-    if ( pPortionInfo && ( static_cast<tools::Long>(pPortionInfo->GetPaperWidth()) == aPaperSize.Width() )
+    if ( pPortionInfo && ( static_cast<tools::Long>(pPortionInfo->GetPaperWidth()) == GetColumnWidth(aPaperSize) )
             && ( pPortionInfo->GetRefMapMode() == GetRefDevice()->GetMapMode() )
             && ( pPortionInfo->GetStretchX() == nStretchX )
             && ( pPortionInfo->GetStretchY() == nStretchY ) )
diff --git a/editeng/source/outliner/outlin2.cxx b/editeng/source/outliner/outlin2.cxx
index ff3d1583a5f1..ba556de35c7a 100644
--- a/editeng/source/outliner/outlin2.cxx
+++ b/editeng/source/outliner/outlin2.cxx
@@ -223,6 +223,11 @@ void Outliner::SetMaxAutoPaperSize( const Size& rSz )
     pEditEngine->SetMaxAutoPaperSize( rSz );
 }

+void Outliner::SetMinColumnWrapHeight(tools::Long nVal)
+{
+    pEditEngine->SetMinColumnWrapHeight(nVal);
+}
+
 bool Outliner::IsExpanded( Paragraph const * pPara ) const
 {
     return pParaList->HasVisibleChildren( pPara );
@@ -532,6 +537,11 @@ bool Outliner::IsTopToBottom() const
     return pEditEngine->IsTopToBottom();
 }

+void Outliner::SetTextColumns(sal_Int16 nColumns, sal_Int32 nSpacing)
+{
+    pEditEngine->SetTextColumns(nColumns, nSpacing);
+}
+
 void Outliner::SetFixedCellHeight( bool bUseFixedCellHeight )
 {
     pEditEngine->SetFixedCellHeight( bUseFixedCellHeight );
diff --git a/include/editeng/editeng.hxx b/include/editeng/editeng.hxx
index 575e43d49e3f..18b136037acb 100644
--- a/include/editeng/editeng.hxx
+++ b/include/editeng/editeng.hxx
@@ -242,6 +242,8 @@ public:
     void            SetRotation(TextRotation nRotation);
     TextRotation    GetRotation() const;

+    void SetTextColumns(sal_Int16 nColumns, sal_Int32 nSpacing);
+
     void            SetFixedCellHeight( bool bUseFixedCellHeight );

     void                        SetDefaultHorizontalTextDirection( EEHorizontalTextDirection eHTextDir );
@@ -270,6 +272,8 @@ public:
     const Size&     GetMaxAutoPaperSize() const;
     void            SetMaxAutoPaperSize( const Size& rSz );

+    void SetMinColumnWrapHeight(tools::Long nVal);
+
     OUString        GetText( LineEnd eEnd = LINEEND_LF ) const;
     OUString        GetText( const ESelection& rSelection ) const;
     sal_uInt32      GetTextLen() const;
diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx
index a6bc9fbd7ff2..d063040e4bc9 100644
--- a/include/editeng/outliner.hxx
+++ b/include/editeng/outliner.hxx
@@ -657,6 +657,8 @@ public:
     bool            IsVertical() const;
     bool            IsTopToBottom() const;

+    void SetTextColumns(sal_Int16 nColumns, sal_Int32 nSpacing);
+
     void            SetFixedCellHeight( bool bUseFixedCellHeight );

     void                        SetDefaultHorizontalTextDirection( EEHorizontalTextDirection eHTextDir );
@@ -786,6 +788,8 @@ public:
     const Size&     GetMaxAutoPaperSize() const;
     void            SetMaxAutoPaperSize( const Size& rSz );

+    void SetMinColumnWrapHeight(tools::Long nVal);
+
     void            SetDefTab( sal_uInt16 nTab );

     bool            IsFlatMode() const;
diff --git a/include/oox/ppt/pptimport.hxx b/include/oox/ppt/pptimport.hxx
index e96f04b70374..f04cb632e574 100644
--- a/include/oox/ppt/pptimport.hxx
+++ b/include/oox/ppt/pptimport.hxx
@@ -77,8 +77,6 @@ public:

     ::Color getSchemeColor( sal_Int32 nToken ) const;

-    static std::vector< PPTShape* > maPPTShapes;
-
 #if OSL_DEBUG_LEVEL > 0
     static XmlFilterBase* mpDebugFilterBase;
 #endif
diff --git a/include/oox/ppt/pptshape.hxx b/include/oox/ppt/pptshape.hxx
index e67a77635111..f452e585abcf 100644
--- a/include/oox/ppt/pptshape.hxx
+++ b/include/oox/ppt/pptshape.hxx
@@ -66,8 +66,7 @@ public:
             const oox::drawingml::Theme* pTheme,
             const css::uno::Reference< css::drawing::XShapes >& rxShapes,
             basegfx::B2DHomMatrix& aTransformation,
-            ::oox::drawingml::ShapeIdMap* pShapeMap,
-            bool bhasSameSubTypeIndex = false );
+            ::oox::drawingml::ShapeIdMap* pShapeMap );

     ShapeLocation getShapeLocation() const { return meShapeLocation; };
     void setReferenced( bool bReferenced ){ mbReferenced = bReferenced; };
diff --git a/include/svl/solar.hrc b/include/svl/solar.hrc
index 317d45a84bc1..521e24365f9f 100644
--- a/include/svl/solar.hrc
+++ b/include/svl/solar.hrc
@@ -23,7 +23,7 @@
 // defines ------------------------------------------------------------------

 #define OWN_ATTR_VALUE_START                    3900
-#define OWN_ATTR_VALUE_END                      4005
+#define OWN_ATTR_VALUE_END                      4006

 #define RID_LIB_START               10000
 #define RID_LIB_END                 19999
diff --git a/include/svx/SvxXTextColumns.hxx b/include/svx/SvxXTextColumns.hxx
new file mode 100644
index 000000000000..0dbc92ba9611
--- /dev/null
+++ b/include/svx/SvxXTextColumns.hxx
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/XInterface.hpp>
+
+#include <svx/svxdllapi.h>
+
+SVXCORE_DLLPUBLIC css::uno::Reference<css::uno::XInterface>
+SvxXTextColumns_createInstance() noexcept;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/include/svx/dialogs.hrc b/include/svx/dialogs.hrc
index 5dc3fc6faa58..f03600a74fe0 100644
--- a/include/svx/dialogs.hrc
+++ b/include/svx/dialogs.hrc
@@ -45,6 +45,7 @@
 #define RID_SVXPAGE_TRANSPARENCE            (RID_SVX_START +  54)
 #define RID_SVXPAGE_TEXTATTR                (RID_SVX_START + 153)
 #define RID_SVXPAGE_TEXTANIMATION           (RID_SVX_START + 184)
+#define RID_SVXPAGE_TEXTCOLUMNS             (RID_SVX_START + 154)
 #define RID_SVXPAGE_MEASURE                 (RID_SVX_START + 161)
 #define RID_SVXPAGE_CONNECTION              (RID_SVX_START + 191)
 #define RID_SVXPAGE_LINE_DEF                (RID_SVX_START +  52)
diff --git a/include/svx/strings.hrc b/include/svx/strings.hrc
index 95e9690b0b9e..50231f03bcc4 100644
--- a/include/svx/strings.hrc
+++ b/include/svx/strings.hrc
@@ -401,6 +401,8 @@
 #define SIP_SA_TEXT_ANIDELAY                                NC_("SIP_SA_TEXT_ANIDELAY", "Speed of ticker")
 #define SIP_SA_TEXT_ANIAMOUNT                               NC_("SIP_SA_TEXT_ANIAMOUNT", "Ticker step size")
 #define SIP_SA_TEXT_CONTOURFRAME                            NC_("SIP_SA_TEXT_CONTOURFRAME", "Outline text flow")
+#define SIP_SA_TEXTCOLUMNS_NUMBER                           NC_("SIP_SA_TEXTCOLUMNS_NUMBER", "Columns number")
+#define SIP_SA_TEXTCOLUMNS_SPACING                          NC_("SIP_SA_TEXTCOLUMNS_SPACING", "Columns spacing")
 #define SIP_SA_XMLATTRIBUTES                                NC_("SIP_SA_XMLATTRIBUTES", "User-defined attributes")
 #define SIP_SA_TEXT_USEFIXEDCELLHEIGHT                      NC_("SIP_SA_TEXT_USEFIXEDCELLHEIGHT", "Use font-independent line spacing")
 #define SIP_SA_WORDWRAP                                     NC_("SIP_SA_WORDWRAP", "Word wrap text in shape")
diff --git a/include/svx/svddef.hxx b/include/svx/svddef.hxx
index 30031e20dde2..f4b5c0986d7c 100644
--- a/include/svx/svddef.hxx
+++ b/include/svx/svddef.hxx
@@ -138,6 +138,7 @@ class SdrVertShearAllItem;
 class SdrVertShearOneItem;
 class SdrYesNoItem;
 class SfxBoolItem;
+class SfxInt16Item;
 class SfxUInt16Item;
 class SfxUInt32Item;
 class SfxStringItem;
@@ -426,7 +427,12 @@ constexpr sal_uInt16                  SDRATTR_SOFTEDGE_FIRST(SDRATTR_GLOW_LAST +
 constexpr TypedWhichId<SdrMetricItem> SDRATTR_SOFTEDGE_RADIUS(SDRATTR_SOFTEDGE_FIRST + 0);
 constexpr sal_uInt16                  SDRATTR_SOFTEDGE_LAST(SDRATTR_SOFTEDGE_RADIUS);

-constexpr sal_uInt16 SDRATTR_END (SDRATTR_SOFTEDGE_LAST);      /* 1357 */ /* 1333 V4+++*/ /* 1243 V4+++*/  /*1213*/ /*1085*/ /*1040*/ /*Pool V2: 1123,V1: 1065 */
+constexpr sal_uInt16 SDRATTR_TEXTCOLUMNS_FIRST(SDRATTR_SOFTEDGE_LAST + 1);
+constexpr TypedWhichId<SfxInt16Item> SDRATTR_TEXTCOLUMNS_NUMBER(SDRATTR_TEXTCOLUMNS_FIRST + 0);
+constexpr TypedWhichId<SdrMetricItem> SDRATTR_TEXTCOLUMNS_SPACING(SDRATTR_TEXTCOLUMNS_FIRST + 1);
+constexpr sal_uInt16 SDRATTR_TEXTCOLUMNS_LAST(SDRATTR_TEXTCOLUMNS_SPACING);
+
+constexpr sal_uInt16 SDRATTR_END (SDRATTR_TEXTCOLUMNS_LAST);      /* 1357 */ /* 1333 V4+++*/ /* 1243 V4+++*/  /*1213*/ /*1085*/ /*1040*/ /*Pool V2: 1123,V1: 1065 */

 #endif // INCLUDED_SVX_SVDDEF_HXX

diff --git a/include/svx/svdotext.hxx b/include/svx/svdotext.hxx
index 9d74bffec93e..26ed2d4c6e2c 100644
--- a/include/svx/svdotext.hxx
+++ b/include/svx/svdotext.hxx
@@ -389,7 +389,7 @@ public:
     // FitToSize and Fontwork are not taken into account in GetTextSize()!
     virtual const Size& GetTextSize() const;
     void FitFrameToTextSize();
-    double GetFontScaleY() const;
+    sal_uInt16 GetFontScaleY() const;

     // Simultaneously sets the text into the Outliner (possibly
     // the one of the EditOutliner) and sets the PaperSize.
@@ -436,6 +436,13 @@ public:
     SdrTextAniKind GetTextAniKind() const;
     SdrTextAniDirection GetTextAniDirection() const;

+    bool HasTextColumnsNumber() const;
+    sal_Int16 GetTextColumnsNumber() const;
+    void SetTextColumnsNumber(sal_Int16 nColumns);
+    bool HasTextColumnsSpacing() const;
+    sal_Int32 GetTextColumnsSpacing() const;
+    void SetTextColumnsSpacing(sal_Int32 nSpacing);
+
     // react on model/page change
     virtual void handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage) override;

diff --git a/include/svx/unoshprp.hxx b/include/svx/unoshprp.hxx
index 20a49f1f4d62..98bea3cd1c09 100644
--- a/include/svx/unoshprp.hxx
+++ b/include/svx/unoshprp.hxx
@@ -60,6 +60,7 @@
 #include <com/sun/star/drawing/TextureProjectionMode.hpp>
 #include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
 #include <com/sun/star/text/GraphicCrop.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
 #include <com/sun/star/drawing/BitmapMode.hpp>
 #include <com/sun/star/drawing/CameraGeometry.hpp>
 #include <com/sun/star/text/WritingMode.hpp>
@@ -193,7 +194,9 @@
 #define OWN_ATTR_SIGNATURELINE_IS_SIGNED        (OWN_ATTR_VALUE_START+103)
 #define OWN_ATTR_QRCODE                         (OWN_ATTR_VALUE_START+104)
 #define OWN_ATTR_TEXTFITTOSIZESCALE             (OWN_ATTR_VALUE_START+105)
-// ATTENTION: maximum is OWN_ATTR_VALUE_START+105 svx, see include/svl/solar.hrc
+#define OWN_ATTR_TEXTCOLUMNS                    (OWN_ATTR_VALUE_START+106)
+// ATTENTION: current maximum is OWN_ATTR_VALUE_START+106 svx; wnen adding values, update
+// OWN_ATTR_VALUE_END in include/svl/solar.hrc accordingly

 // #FontWork#
 #define FONTWORK_PROPERTIES \
@@ -316,6 +319,7 @@
     { u"" UNO_NAME_TEXT_VERTADJUST,       SDRATTR_TEXT_VERTADJUST,        cppu::UnoType<css::drawing::TextVerticalAdjust>::get(),    0,      0},\
     { u"" UNO_NAME_TEXT_WORDWRAP,         SDRATTR_TEXT_WORDWRAP,          cppu::UnoType<bool>::get(),        0,      0}, \
     { u"" UNO_NAME_TEXT_CHAINNEXTNAME,    SDRATTR_TEXT_CHAINNEXTNAME,     ::cppu::UnoType<OUString>::get(),        0,      0}, \
+    { u"TextColumns",                     OWN_ATTR_TEXTCOLUMNS,           cppu::UnoType<css::text::XTextColumns>::get(), 0, 0 }, \
     SVX_UNOEDIT_CHAR_PROPERTIES, \
     SVX_UNOEDIT_PARA_PROPERTIES,

diff --git a/offapi/com/sun/star/drawing/TextProperties.idl b/offapi/com/sun/star/drawing/TextProperties.idl
index 4516c9829781..eb045624aba0 100644
--- a/offapi/com/sun/star/drawing/TextProperties.idl
+++ b/offapi/com/sun/star/drawing/TextProperties.idl
@@ -40,6 +40,7 @@
 #include <com/sun/star/drawing/TextVerticalAdjust.idl>
 #include <com/sun/star/drawing/TextHorizontalAdjust.idl>
 #include <com/sun/star/text/WritingMode.idl>
+#include <com/sun/star/text/XTextColumns.idl>


  module com {  module sun {  module star {  module drawing {
@@ -249,6 +250,13 @@ published service TextProperties
     /** This value selects the writing mode for the text.
      */
     [property] ::com::sun::star::text::WritingMode TextWritingMode;
+
+
+    /** Column layout properties for the text.
+
+        @since LibreOffice 7.2
+     */
+    [optional, property] ::com::sun::star::text::XTextColumns TextColumns;
 };


diff --git a/oox/inc/drawingml/table/tableproperties.hxx b/oox/inc/drawingml/table/tableproperties.hxx
index ec8b3c4c5b60..34e361b18add 100644
--- a/oox/inc/drawingml/table/tableproperties.hxx
+++ b/oox/inc/drawingml/table/tableproperties.hxx
@@ -58,9 +58,6 @@ public:
         const css::uno::Reference < css::beans::XPropertySet > & xPropSet,
         const ::oox::drawingml::TextListStylePtr& pMasterTextListStyle );

-    /// Distributes text body with multiple columns in table cells.
-    void pullFromTextBody(oox::drawingml::TextBodyPtr pTextBody, sal_Int32 nShapeWidth, bool bhasSameSubTypeIndex, bool bMaster);
-
 private:

     const TableStyle&                   getUsedTableStyle(const ::oox::core::XmlFilterBase& rFilterBase, std::unique_ptr<TableStyle>& rTableStyleToDelete);
diff --git a/oox/inc/drawingml/textbodyproperties.hxx b/oox/inc/drawingml/textbodyproperties.hxx
index 8a51c2bb906e..41fbb832a5d8 100644
--- a/oox/inc/drawingml/textbodyproperties.hxx
+++ b/oox/inc/drawingml/textbodyproperties.hxx
@@ -42,8 +42,6 @@ struct TextBodyProperties
     std::optional< sal_Int32 >                    moTextOffRight;
     css::drawing::TextVerticalAdjust                meVA;
     OUString                                        msPrst;
-    /// Number of requested columns.
-    sal_Int32 mnNumCol = 1;
     /// Normal autofit: font scale (default: 100%).
     sal_Int32 mnFontScale = 100000;
     OUString msHorzOverflow;
diff --git a/oox/source/drawingml/table/tableproperties.cxx b/oox/source/drawingml/table/tableproperties.cxx
index 1c12c10eda47..69117123dca8 100644
--- a/oox/source/drawingml/table/tableproperties.cxx
+++ b/oox/source/drawingml/table/tableproperties.cxx
@@ -145,7 +145,7 @@ void TableProperties::pushToPropSet(const ::oox::core::XmlFilterBase& rFilterBas
     for (auto& tableRow : mvTableRows)
     {
         sal_Int32 nColumn = 0;
-        sal_Int32 nColumnSize = mvTableGrid.size();
+        sal_Int32 nColumnSize = tableRow.getTableCells().size();
         sal_Int32 nRemovedColumn = 0; //

         for (sal_Int32 nColIndex = 0; nColIndex < nColumnSize; nColIndex++)
@@ -206,65 +206,6 @@ void TableProperties::pushToPropSet(const ::oox::core::XmlFilterBase& rFilterBas

     xTableStyleToDelete.reset();
 }
-
-void TableProperties::pullFromTextBody(oox::drawingml::TextBodyPtr pTextBody, sal_Int32 nShapeWidth, bool bhasSameSubTypeIndex, bool bMaster)
-{
-    // Create table grid and a single row.
-    sal_Int32 nNumCol = pTextBody->getTextProperties().mnNumCol;
-    std::vector<sal_Int32>& rTableGrid(getTableGrid());
-    std::vector<drawingml::table::TableRow>& rTableRows(getTableRows());
-    sal_Int32 nColWidth = nShapeWidth / nNumCol;
-
-    if(!bhasSameSubTypeIndex)
-    {
-        for (sal_Int32 nCol = 0; nCol < nNumCol; ++nCol)
-            rTableGrid.push_back(nColWidth);
-
-        rTableRows.emplace_back();
-    }
-
-    if(rTableRows.empty())
-        rTableRows.emplace_back();
-
-    oox::drawingml::table::TableRow& rTableRow = rTableRows.back();
-    std::vector<oox::drawingml::table::TableCell>& rTableCells = rTableRow.getTableCells();
-
-    // Create the cells and distribute the paragraphs from pTextBody.
-    sal_Int32 nNumPara = pTextBody->getParagraphs().size();
-    sal_Int32 nParaPerCol = std::ceil(double(nNumPara) / nNumCol);
-    // Font scale of text body will be applied at a text run level.
-    sal_Int32 nFontScale = pTextBody->getTextProperties().mnFontScale;
-    size_t nPara = 0;
-    for (sal_Int32 nCol = 0; nCol < nNumCol; ++nCol)
-    {
-        rTableCells.emplace_back();
-        oox::drawingml::table::TableCell& rTableCell = rTableCells.at(nCol);
-        TextBodyPtr pCellTextBody = std::make_shared<TextBody>();
-        rTableCell.setTextBody(pCellTextBody);
-
-        // Copy properties provided by <a:lstStyle>.
-        pCellTextBody->getTextListStyle() = pTextBody->getTextListStyle();
-
-        if (bMaster)
-            continue;
-
-        for (sal_Int32 nParaInCol = 0; nParaInCol < nParaPerCol; ++nParaInCol)
-        {
-            if (nPara < pTextBody->getParagraphs().size())
-            {
-                std::shared_ptr<oox::drawingml::TextParagraph> pParagraph
-                    = pTextBody->getParagraphs()[nPara];
-                if (nFontScale != 100000)
-                {
-                    for (auto& pRun : pParagraph->getRuns())
-                        pRun->getTextCharacterProperties().moFontScale = nFontScale;
-                }
-                pCellTextBody->appendParagraph(pParagraph);
-            }
-            ++nPara;
-        }
-    }
-}
 }

 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/drawingml/textbodypropertiescontext.cxx b/oox/source/drawingml/textbodypropertiescontext.cxx
index 4d94191dcfc7..e2811d6667ba 100644
--- a/oox/source/drawingml/textbodypropertiescontext.cxx
+++ b/oox/source/drawingml/textbodypropertiescontext.cxx
@@ -22,6 +22,7 @@
 #include <com/sun/star/text/WritingMode.hpp>
 #include <com/sun/star/drawing/TextFitToSizeType.hpp>
 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
 #include <drawingml/textbodyproperties.hxx>
 #include <drawingml/textbody.hxx>
 #include <drawingml/customshapegeometry.hxx>
@@ -32,6 +33,7 @@
 #include <oox/token/namespaces.hxx>
 #include <oox/token/properties.hxx>
 #include <oox/token/tokens.hxx>
+#include <svx/SvxXTextColumns.hxx>

 using namespace ::oox::core;
 using namespace ::com::sun::star;
@@ -85,7 +87,17 @@ TextBodyPropertiesContext::TextBodyPropertiesContext( ContextHandler2Helper cons
     mrTextBodyProp.msVertOverflow = rAttribs.getString(XML_vertOverflow, "");

     // ST_TextColumnCount
-    mrTextBodyProp.mnNumCol = rAttribs.getInteger( XML_numCol, 1 );
+    if (const sal_Int32 nColumns = rAttribs.getInteger(XML_numCol, 0); nColumns > 0)
+    {
+        css::uno::Reference<css::text::XTextColumns> xCols(SvxXTextColumns_createInstance(),
+                                                           css::uno::UNO_QUERY_THROW);
+        xCols->setColumnCount(nColumns);
+        css::uno::Reference<css::beans::XPropertySet> xProps(xCols, css::uno::UNO_QUERY_THROW);
+        // ST_PositiveCoordinate32
+        const sal_Int32 nSpacing = convertEmuToHmm(rAttribs.getInteger(XML_spcCol, 0));
+        xProps->setPropertyValue("AutomaticDistance", css::uno::Any(nSpacing));
+        mrTextBodyProp.maPropertyMap.setAnyProperty(PROP_TextColumns, css::uno::Any(xCols));
+    }

     // ST_Angle
     mrTextBodyProp.moRotation = rAttribs.getInteger( XML_rot );
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 8cfd4a6dabc5..263cd5c06b67 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -85,6 +85,7 @@
 #include <com/sun/star/text/WritingMode2.hpp>
 #include <com/sun/star/text/GraphicCrop.hpp>
 #include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
 #include <com/sun/star/text/XTextContent.hpp>
 #include <com/sun/star/text/XTextField.hpp>
 #include <com/sun/star/text/XTextRange.hpp>
@@ -3060,6 +3061,22 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo
         sal_Int32 nShapeTextRotateAngle = 0;
         if (GetProperty(xTextSet, "RotateAngle"))
             nShapeTextRotateAngle = rXPropSet->getPropertyValue("RotateAngle").get<sal_Int32>() / 300;
+        sal_Int16 nCols = 0;
+        sal_Int32 nColSpacing = -1;
+        if (GetProperty(rXPropSet, "TextColumns"))
+        {
+            if (css::uno::Reference<css::text::XTextColumns> xCols{ mAny, css::uno::UNO_QUERY })
+            {
+                nCols = xCols->getColumnCount();
+                if (css::uno::Reference<css::beans::XPropertySet> xProps{ mAny,
+                                                                          css::uno::UNO_QUERY })
+                {
+                    if (GetProperty(xProps, "AutomaticDistance"))
+                        mAny >>= nColSpacing;
+                }
+            }
+        }
+
         std::optional<OString> isUpright;
         if (GetProperty(rXPropSet, "InteropGrabBag"))
         {
@@ -3114,6 +3131,8 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo
         }

         mpFS->startElementNS( (nXmlNamespace ? nXmlNamespace : XML_a), XML_bodyPr,
+                               XML_numCol, sax_fastparser::UseIf(OString::number(nCols), nCols > 0),
+                               XML_spcCol, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nColSpacing)), nCols > 0 && nColSpacing >= 0),
                                XML_wrap, pWrap,
                                XML_horzOverflow, sHorzOverflow,
                                XML_vertOverflow, sVertOverflow,
@@ -3229,10 +3248,7 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo
                 {
                     SdrTextObj* pTextObject = dynamic_cast<SdrTextObj*>(pTextShape->GetSdrObject());
                     if (pTextObject)
-                    {
-                        double fScaleY = pTextObject->GetFontScaleY();
-                        nFontScale = static_cast<sal_uInt32>(fScaleY * 100) * 1000;
-                    }
+                        nFontScale = pTextObject->GetFontScaleY() * 1000;
                 }

                 mpFS->singleElementNS(XML_a, XML_normAutofit, XML_fontScale,
diff --git a/oox/source/ppt/pptimport.cxx b/oox/source/ppt/pptimport.cxx
index f7d00920705e..dea04a98e9a3 100644
--- a/oox/source/ppt/pptimport.cxx
+++ b/oox/source/ppt/pptimport.cxx
@@ -70,7 +70,6 @@ PowerPointImport::PowerPointImport( const Reference< XComponentContext >& rxCont

 PowerPointImport::~PowerPointImport()
 {
-    maPPTShapes.clear();
 }

 /// Visits the relations from pRelations which are of type rType.
diff --git a/oox/source/ppt/pptshape.cxx b/oox/source/ppt/pptshape.cxx
index 96ca319f2a8e..e326cba50464 100644
--- a/oox/source/ppt/pptshape.cxx
+++ b/oox/source/ppt/pptshape.cxx
@@ -114,8 +114,7 @@ void PPTShape::addShape(
         const oox::drawingml::Theme* pTheme,
         const Reference< XShapes >& rxShapes,
         basegfx::B2DHomMatrix& aTransformation,
-        ::oox::drawingml::ShapeIdMap* pShapeMap,
-        bool bhasSameSubTypeIndex )
+        ::oox::drawingml::ShapeIdMap* pShapeMap )
 {
     SAL_INFO("oox.ppt","add shape id: " << msId << " location: " << ((meShapeLocation == Master) ? "master" : ((meShapeLocation == Slide) ? "slide" : ((meShapeLocation == Layout) ? "layout" : "other"))) << " subtype: " << mnSubType << " service: " << msServiceName);
     // only placeholder from layout are being inserted
@@ -225,36 +224,6 @@ void PPTShape::addShape(
             }
         }

-        if (sServiceName != "com.sun.star.drawing.TableShape")
-        {
-            if (TextBodyPtr pTextBody = getTextBody())
-            {
-                // If slide shape has not numCol but placeholder has we should inherit from placeholder.
-                if (pTextBody->getTextProperties().mnNumCol == 1 &&
-                    mnSubType &&
-                    getSubTypeIndex().has() &&
-                    rSlidePersist.getMasterPersist())
-                {
-                    oox::drawingml::ShapePtr pPlaceholder = PPTShape::findPlaceholderByIndex(
-                                                                            getSubTypeIndex().get(),
-                                                                            rSlidePersist.getMasterPersist()->getShapes()->getChildren());
-                    if (pPlaceholder && pPlaceholder->getTableProperties())
-                        pTextBody->getTextProperties().mnNumCol = pPlaceholder->getTableProperties()->getTableGrid().size();
-                }
-
-                sal_Int32 nNumCol = pTextBody->getTextProperties().mnNumCol;
-                if (nNumCol > 1)
-                {
-                    // This shape is not a table, but has multiple columns,
-                    // represent that as a table.
-                    sServiceName = "com.sun.star.drawing.TableShape";
-                    oox::drawingml::table::TablePropertiesPtr pTableProperties = getTableProperties();
-                    pTableProperties->pullFromTextBody(pTextBody, maSize.Width, bhasSameSubTypeIndex, meShapeLocation == Layout);
-                    setTextBody(nullptr);
-                }
-            }
-        }
-
         SAL_INFO("oox.ppt","shape service: " << sServiceName);

         if (mnSubType && getSubTypeIndex().has() && meShapeLocation == Layout)
diff --git a/oox/source/ppt/slidepersist.cxx b/oox/source/ppt/slidepersist.cxx
index dc18ec06e128..74bd8165bc7a 100644
--- a/oox/source/ppt/slidepersist.cxx
+++ b/oox/source/ppt/slidepersist.cxx
@@ -23,7 +23,6 @@
 #include <com/sun/star/frame/XModel.hpp>
 #include <oox/ppt/timenode.hxx>
 #include <oox/ppt/pptshape.hxx>
-#include <oox/ppt/pptimport.hxx>
 #include <oox/ppt/slidepersist.hxx>
 #include <drawingml/fillproperties.hxx>
 #include <oox/drawingml/shapepropertymap.hxx>
@@ -35,7 +34,6 @@
 #include <oox/core/xmlfilterbase.hxx>
 #include <drawingml/textliststyle.hxx>
 #include <drawingml/textparagraphproperties.hxx>
-#include <drawingml/textbody.hxx>

 #include <osl/diagnose.h>

@@ -54,8 +52,6 @@ using namespace ::com::sun::star::animations;

 namespace oox::ppt {

-std::vector< PPTShape* > PowerPointImport::maPPTShapes;
-
 SlidePersist::SlidePersist( XmlFilterBase& rFilter, bool bMaster, bool bNotes,
     const css::uno::Reference< css::drawing::XDrawPage >& rxPage,
         oox::drawingml::ShapePtr const & pShapesPtr, const drawingml::TextListStylePtr & pDefaultTextStyle )
@@ -132,29 +128,12 @@ sal_Int16 SlidePersist::getLayoutFromValueToken() const
     return nLayout;
 }

-static bool hasSameSubTypeIndex(sal_Int32 checkSubTypeIndex)
-{
-    sal_Int32 nSubTypeIndex = -1;
-    for(PPTShape* pPPTShape : PowerPointImport::maPPTShapes)
-    {
-        if(!pPPTShape->getSubTypeIndex().has())
-            continue;
-
-        nSubTypeIndex = pPPTShape->getSubTypeIndex().get();
-
-        if( nSubTypeIndex == checkSubTypeIndex )
-            return true;
-    }
-    return false;
-}
 void SlidePersist::createXShapes( XmlFilterBase& rFilterBase )
 {
     applyTextStyles( rFilterBase );

     Reference< XShapes > xShapes( getPage() );
     std::vector< oox::drawingml::ShapePtr >& rShapes( maShapesPtr->getChildren() );
-    bool bhasSameSubTypeIndex = false;
-    sal_Int32 nNumCol = 1;

     for (auto const& shape : rShapes)
     {
@@ -164,17 +143,7 @@ void SlidePersist::createXShapes( XmlFilterBase& rFilterBase )
             PPTShape* pPPTShape = dynamic_cast< PPTShape* >( child.get() );
             basegfx::B2DHomMatrix aTransformation;
             if ( pPPTShape )
-            {
-                bhasSameSubTypeIndex = hasSameSubTypeIndex( pPPTShape->getSubTypeIndex().get());
-
-                if(pPPTShape->getTextBody())
-                    nNumCol = pPPTShape->getTextBody()->getTextProperties().mnNumCol;
-
-                if(pPPTShape->getSubTypeIndex().has() && nNumCol > 1 )
-                    PowerPointImport::maPPTShapes.push_back(pPPTShape);
-
-                pPPTShape->addShape( rFilterBase, *this, getTheme().get(), xShapes, aTransformation, &getShapeMap(), bhasSameSubTypeIndex );
-            }
+                pPPTShape->addShape( rFilterBase, *this, getTheme().get(), xShapes, aTransformation, &getShapeMap() );
             else
                 child->addShape( rFilterBase, getTheme().get(), xShapes, aTransformation, maShapesPtr->getFillProperties(), &getShapeMap() );
         }
diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt
index d50cd4bb124d..980c1bb8c0f2 100644
--- a/oox/source/token/properties.txt
+++ b/oox/source/token/properties.txt
@@ -528,6 +528,7 @@ TextBox
 TextBreak
 TextCameraZRotateAngle
 TextColor
+TextColumns
 TextFitToSize
 TextFrames
 TextHorizontalAdjust
diff --git a/sc/qa/uitest/chart/chartLegend.py b/sc/qa/uitest/chart/chartLegend.py
index 7e2e085d135b..7ee844008d40 100644
--- a/sc/qa/uitest/chart/chartLegend.py
+++ b/sc/qa/uitest/chart/chartLegend.py
@@ -13,6 +13,7 @@ from libreoffice.calc.document import get_cell_by_position
 from libreoffice.uno.propertyvalue import mkPropertyValues
 from uitest.uihelper.common import get_state_as_dict, type_text
 from uitest.debug import sleep
+from uitest.uihelper import guarded
 import org.libreoffice.unotest
 import pathlib

@@ -23,119 +24,91 @@ def get_url_for_data_file(file_name):

 class chartLegend(UITestCase):
    def test_chart_display_legend_dialog(self):
-    calc_doc = self.ui_test.load_file(get_url_for_data_file("tdf98390.ods"))
-    xCalcDoc = self.xUITest.getTopFocusWindow()
-    gridwin = xCalcDoc.getChild("grid_window")
-    document = self.ui_test.get_component()
-
-    gridwin.executeAction("SELECT", mkPropertyValues({"OBJECT": "Object 1"}))
-    gridwin.executeAction("ACTIVATE", tuple())
-    xChartMainTop = self.xUITest.getTopFocusWindow()
-    xChartMain = xChartMainTop.getChild("chart_window")
-    xSeriesObj =  xChartMain.getChild("CID/D=0:CS=0:CT=0:Series=0")
-    self.ui_test.execute_dialog_through_action(xSeriesObj, "COMMAND", mkPropertyValues({"COMMAND": "InsertMenuLegend"}))
-    xDialog = self.xUITest.getTopFocusWindow()
-
-    left = xDialog.getChild("left")
-    right = xDialog.getChild("right")
-    top = xDialog.getChild("top")
-    bottom = xDialog.getChild("bottom")
-
-    left.executeAction("CLICK", tuple())
-
-    xOKBtn = xDialog.getChild("ok")
-    self.ui_test.close_dialog_through_button(xOKBtn)
-
-    #reopen and verify InsertMenuLegend dialog
-    gridwin.executeAction("SELECT", mkPropertyValues({"OBJECT": "Object 1"}))
-    gridwin.executeAction("ACTIVATE", tuple())
-    xChartMainTop = self.xUITest.getTopFocusWindow()
-    xChartMain = xChartMainTop.getChild("chart_window")
-    xSeriesObj =  xChartMain.getChild("CID/D=0:CS=0:CT=0:Series=0")
-    self.ui_test.execute_dialog_through_action(xSeriesObj, "COMMAND", mkPropertyValues({"COMMAND": "InsertMenuLegend"}))
-    xDialog = self.xUITest.getTopFocusWindow()
-
-    left = xDialog.getChild("left")
-    right = xDialog.getChild("right")
-    top = xDialog.getChild("top")
-    bottom = xDialog.getChild("bottom")
-    show = xDialog.getChild("show")
-
-    self.assertEqual(get_state_as_dict(left)["Checked"], "true")
-    self.assertEqual(get_state_as_dict(right)["Checked"], "false")
-    self.assertEqual(get_state_as_dict(top)["Checked"], "false")
-    self.assertEqual(get_state_as_dict(bottom)["Checked"], "false")
-
-    show.executeAction("CLICK", tuple())
-
-    xOKBtn = xDialog.getChild("ok")
-    self.ui_test.close_dialog_through_button(xOKBtn)
-
-    #reopen and verify InsertMenuLegend dialog
-    gridwin.executeAction("SELECT", mkPropertyValues({"OBJECT": "Object 1"}))
-    gridwin.executeAction("ACTIVATE", tuple())
-    xChartMainTop = self.xUITest.getTopFocusWindow()
-    xChartMain = xChartMainTop.getChild("chart_window")
-    xSeriesObj =  xChartMain.getChild("CID/D=0:CS=0:CT=0:Series=0")
-    self.ui_test.execute_dialog_through_action(xSeriesObj, "COMMAND", mkPropertyValues({"COMMAND": "InsertMenuLegend"}))
-    xDialog = self.xUITest.getTopFocusWindow()
-
-    left = xDialog.getChild("left")
-    right = xDialog.getChild("right")
-    top = xDialog.getChild("top")
-    bottom = xDialog.getChild("bottom")
-    show = xDialog.getChild("show")
-
-    self.assertEqual(get_state_as_dict(left)["Checked"], "true")
-    self.assertEqual(get_state_as_dict(right)["Checked"], "false")
-    self.assertEqual(get_state_as_dict(top)["Checked"], "false")
-    self.assertEqual(get_state_as_dict(bottom)["Checked"], "false")
-
-    self.assertEqual(get_state_as_dict(show)["Selected"], "false")
-
-    xOKBtn = xDialog.getChild("ok")
-    self.ui_test.close_dialog_through_button(xOKBtn)
-    self.ui_test.close_doc()
+    with guarded.load_file(self, get_url_for_data_file("tdf98390.ods")) as calc_doc:
+      xCalcDoc = self.xUITest.getTopFocusWindow()
+      gridwin = xCalcDoc.getChild("grid_window")
+      document = self.ui_test.get_component()
+
+      gridwin.executeAction("SELECT", mkPropertyValues({"OBJECT": "Object 1"}))
+      gridwin.executeAction("ACTIVATE", tuple())
+      xChartMainTop = self.xUITest.getTopFocusWindow()
+      xChartMain = xChartMainTop.getChild("chart_window")
+      xSeriesObj =  xChartMain.getChild("CID/D=0:CS=0:CT=0:Series=0")
+      with guarded.execute_dialog_through_action(self, xSeriesObj, "COMMAND", mkPropertyValues({"COMMAND": "InsertMenuLegend"})) as xDialog:
+        left = xDialog.getChild("left")
+        right = xDialog.getChild("right")
+        top = xDialog.getChild("top")
+        bottom = xDialog.getChild("bottom")
+
+        left.executeAction("CLICK", tuple())
+
+      #reopen and verify InsertMenuLegend dialog
+      gridwin.executeAction("SELECT", mkPropertyValues({"OBJECT": "Object 1"}))
+      gridwin.executeAction("ACTIVATE", tuple())
+      xChartMainTop = self.xUITest.getTopFocusWindow()
+      xChartMain = xChartMainTop.getChild("chart_window")
+      xSeriesObj =  xChartMain.getChild("CID/D=0:CS=0:CT=0:Series=0")
+      with guarded.execute_dialog_through_action(self, xSeriesObj, "COMMAND", mkPropertyValues({"COMMAND": "InsertMenuLegend"})) as xDialog:
+        left = xDialog.getChild("left")
+        right = xDialog.getChild("right")
+        top = xDialog.getChild("top")
+        bottom = xDialog.getChild("bottom")
+        show = xDialog.getChild("show")
+
+        self.assertEqual(get_state_as_dict(left)["Checked"], "true")
+        self.assertEqual(get_state_as_dict(right)["Checked"], "false")
+        self.assertEqual(get_state_as_dict(top)["Checked"], "false")
+        self.assertEqual(get_state_as_dict(bottom)["Checked"], "false")
+
+        show.executeAction("CLICK", tuple())
+
+      #reopen and verify InsertMenuLegend dialog
+      gridwin.executeAction("SELECT", mkPropertyValues({"OBJECT": "Object 1"}))
+      gridwin.executeAction("ACTIVATE", tuple())
+      xChartMainTop = self.xUITest.getTopFocusWindow()
+      xChartMain = xChartMainTop.getChild("chart_window")
+      xSeriesObj =  xChartMain.getChild("CID/D=0:CS=0:CT=0:Series=0")
+      with guarded.execute_dialog_through_action(self, xSeriesObj, "COMMAND", mkPropertyValues({"COMMAND": "InsertMenuLegend"})) as xDialog:
+        left = xDialog.getChild("left")
+        right = xDialog.getChild("right")
+        top = xDialog.getChild("top")
+        bottom = xDialog.getChild("bottom")
+        show = xDialog.getChild("show")
+
+        self.assertEqual(get_state_as_dict(left)["Checked"], "true")
+        self.assertEqual(get_state_as_dict(right)["Checked"], "false")
+        self.assertEqual(get_state_as_dict(top)["Checked"], "false")
+        self.assertEqual(get_state_as_dict(bottom)["Checked"], "false")
+
+        self.assertEqual(get_state_as_dict(show)["Selected"], "false")

    def test_legends_move_with_arrows_keys(self):

-    calc_doc = self.ui_test.load_file(get_url_for_data_file("dataLabels.ods"))
-    xCalcDoc = self.xUITest.getTopFocusWindow()
-    gridwin = xCalcDoc.getChild("grid_window")
+    with guarded.load_file(self, get_url_for_data_file("dataLabels.ods")) as calc_doc:
+      xCalcDoc = self.xUITest.getTopFocusWindow()
+      gridwin = xCalcDoc.getChild("grid_window")

-    change_measurement_unit(self, "Centimeter")
+      change_measurement_unit(self, "Centimeter")

-    gridwin.executeAction("SELECT", mkPropertyValues({"OBJECT": "Object 1"}))
-    gridwin.executeAction("ACTIVATE", tuple())
-    xChartMainTop = self.xUITest.getTopFocusWindow()
-    xChartMain = xChartMainTop.getChild("chart_window")
+      gridwin.executeAction("SELECT", mkPropertyValues({"OBJECT": "Object 1"}))
+      gridwin.executeAction("ACTIVATE", tuple())
+      xChartMainTop = self.xUITest.getTopFocusWindow()
+      xChartMain = xChartMainTop.getChild("chart_window")

-    # Select the legends
-    xLegends = xChartMain.getChild("CID/D=0:Legend=")
-    xLegends.executeAction("SELECT", tuple())
+      # Select the legends
+      xLegends = xChartMain.getChild("CID/D=0:Legend=")
+      xLegends.executeAction("SELECT", tuple())

-    self.ui_test.execute_dialog_through_action(xLegends, "COMMAND", mkPropertyValues({"COMMAND": "TransformDialog"}))
+      with guarded.execute_dialog_through_action(self, xLegends, "COMMAND", mkPropertyValues({"COMMAND": "TransformDialog"})) as xDialog:
+        self.assertEqual("4.61", get_state_as_dict(xDialog.getChild("MTR_FLD_POS_X"))['Value'])
+        self.assertEqual("1.53", get_state_as_dict(xDialog.getChild("MTR_FLD_POS_Y"))['Value'])

-    xDialog = self.xUITest.getTopFocusWindow()
-    self.assertEqual("4.61", get_state_as_dict(xDialog.getChild("MTR_FLD_POS_X"))['Value'])
-    self.assertEqual("1.54", get_state_as_dict(xDialog.getChild("MTR_FLD_POS_Y"))['Value'])
+      xChartMain.executeAction("TYPE", mkPropertyValues({"KEYCODE": "UP"}))
+      xChartMain.executeAction("TYPE", mkPropertyValues({"KEYCODE": "LEFT"}))

-    xOkBtn = xDialog.getChild("ok")
-    xOkBtn.executeAction("CLICK", tuple())
-
-    xChartMain.executeAction("TYPE", mkPropertyValues({"KEYCODE": "UP"}))
-    xChartMain.executeAction("TYPE", mkPropertyValues({"KEYCODE": "LEFT"}))
-
-    self.ui_test.execute_dialog_through_action(xLegends, "COMMAND", mkPropertyValues({"COMMAND": "TransformDialog"}))
-
-    # Check the position has changed after moving the label using the arrows keys
-    xDialog = self.xUITest.getTopFocusWindow()
-    self.assertEqual("4.51", get_state_as_dict(xDialog.getChild("MTR_FLD_POS_X"))['Value'])
-    self.assertEqual("1.44", get_state_as_dict(xDialog.getChild("MTR_FLD_POS_Y"))['Value'])
-
-    xOkBtn = xDialog.getChild("ok")
-    xOkBtn.executeAction("CLICK", tuple())
-
-    self.ui_test.close_doc()
+      # Check the position has changed after moving the label using the arrows keys
+      with guarded.execute_dialog_through_action(self, xLegends, "COMMAND", mkPropertyValues({"COMMAND": "TransformDialog"})) as xDialog:
+        self.assertEqual("4.51", get_state_as_dict(xDialog.getChild("MTR_FLD_POS_X"))['Value'])
+        self.assertEqual("1.43", get_state_as_dict(xDialog.getChild("MTR_FLD_POS_Y"))['Value'])

 # vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sc/qa/unit/filters-test.cxx b/sc/qa/unit/filters-test.cxx
index a994297ff2c0..30ef7f12aa3e 100644
--- a/sc/qa/unit/filters-test.cxx
+++ b/sc/qa/unit/filters-test.cxx
@@ -514,7 +514,7 @@ void ScFiltersTest::testCommentSize()

     const tools::Rectangle& rNewRect = pCaption->GetLogicRect();
     CPPUNIT_ASSERT_EQUAL(rOldRect.getWidth(), rNewRect.getWidth());
-    CPPUNIT_ASSERT_EQUAL(tools::Long(1605), rNewRect.getHeight());
+    CPPUNIT_ASSERT_EQUAL(tools::Long(1606), rNewRect.getHeight());

     rDoc.GetUndoManager()->Undo();

diff --git a/sd/qa/uitest/impress_tests/tdf91762.py b/sd/qa/uitest/impress_tests/tdf91762.py
index 2487bc2a4726..b05670c4af63 100644
--- a/sd/qa/uitest/impress_tests/tdf91762.py
+++ b/sd/qa/uitest/impress_tests/tdf91762.py
@@ -26,9 +26,9 @@ class tdf91762(UITestCase):
         self.ui_test.close_dialog_through_button(xOkBtn)

         document = self.ui_test.get_component()
-        self.assertEqual(1929, document.DrawPages[0].getByIndex(1).BoundRect.Height)
+        self.assertEqual(1931, document.DrawPages[0].getByIndex(1).BoundRect.Height)
         self.assertEqual(25198, document.DrawPages[0].getByIndex(1).Size.Width)
-        self.assertEqual(1923, document.DrawPages[0].getByIndex(1).Size.Height)
+        self.assertEqual(1925, document.DrawPages[0].getByIndex(1).Size.Height)

         self.assertEqual(1400, document.DrawPages[0].getByIndex(1).Position.X)
         self.assertEqual(3685, document.DrawPages[0].getByIndex(1).Position.Y)
@@ -40,8 +40,8 @@ class tdf91762(UITestCase):
             xEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": "RETURN"}))

         # tdf#138011: Without the fix in place, this test would have failed with
-        # AssertionError: 5494 != 3559
-        self.assertEqual(5494, document.DrawPages[0].getByIndex(1).BoundRect.Height)
+        # AssertionError: 5496 != 3559
+        self.assertEqual(5496, document.DrawPages[0].getByIndex(1).BoundRect.Height)

         self.ui_test.close_doc()

diff --git a/sd/qa/uitest/impress_tests/textColumnsDialog.py b/sd/qa/uitest/impress_tests/textColumnsDialog.py
new file mode 100644
index 000000000000..266c55bada6b
--- /dev/null
+++ b/sd/qa/uitest/impress_tests/textColumnsDialog.py
@@ -0,0 +1,53 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+from uitest.uihelper.common import get_state_as_dict
+from libreoffice.uno.propertyvalue import mkPropertyValues
+from uitest.uihelper.common import change_measurement_unit, select_pos
+from uitest.framework import UITestCase
+from uitest.uihelper import guarded
+
+class textColumnsDialog(UITestCase):
+
+    def test_textColumnsDialog(self):
+        with guarded.create_doc_in_start_center(self, "impress") as document:
+
+            xTemplateDlg = self.xUITest.getTopFocusWindow()
+            xCancelBtn = xTemplateDlg.getChild("cancel")
+            self.ui_test.close_dialog_through_button(xCancelBtn)
+
+            xImpressDoc = self.xUITest.getTopFocusWindow()
+
+            xEditWin = xImpressDoc.getChild("impress_win")
+            xEditWin.executeAction("SELECT", mkPropertyValues({"OBJECT":"Unnamed Drawinglayer object 1"}))
+            self.assertEqual("com.sun.star.drawing.SvxShapeCollection", document.CurrentSelection.getImplementationName())
+
+            # Test defaults and set some values
+            with guarded.execute_dialog_through_command(self, ".uno:TextAttributes") as xDialog:
+                xTabs = xDialog.getChild("tabcontrol")
+                select_pos(xTabs, "2")
+                colNumber = xDialog.getChild('FLD_COL_NUMBER')
+                colSpacing = xDialog.getChild('MTR_FLD_COL_SPACING')
+                self.assertEqual('1', get_state_as_dict(colNumber)['Text'])
+                self.assertEqual('0.00″', get_state_as_dict(colSpacing)['Text'])
+                colNumber.executeAction("TYPE", mkPropertyValues({"KEYCODE": "BACKSPACE"}))
+                colNumber.executeAction("TYPE", mkPropertyValues({"TEXT": "3"}))
+                colSpacing.executeAction("TYPE", mkPropertyValues({"KEYCODE": "BACKSPACE"}))
+                colSpacing.executeAction("TYPE", mkPropertyValues({"TEXT": "1.5"}))
+
+            # Test that settings persist
+            with guarded.execute_dialog_through_command(self, ".uno:TextAttributes") as xDialog:
+                xTabs = xDialog.getChild("tabcontrol")
+                select_pos(xTabs, "2")
+                colNumber = xDialog.getChild('FLD_COL_NUMBER')
+                colSpacing = xDialog.getChild('MTR_FLD_COL_SPACING')
+                self.assertEqual('3', get_state_as_dict(colNumber)['Text'])
+                self.assertEqual('1.50″', get_state_as_dict(colSpacing)['Text'])
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sd/qa/unit/data/xml/n593612_0.xml b/sd/qa/unit/data/xml/n593612_0.xml
index 7c93f494e3ca..51fb75eba050 100644
--- a/sd/qa/unit/data/xml/n593612_0.xml
+++ b/sd/qa/unit/data/xml/n593612_0.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <XShapes>
- <XShape positionX="11429" positionY="1324" sizeX="2259" sizeY="15209" type="com.sun.star.drawing.CustomShape" name="Rectangle 52" text="&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;" fontHeight="24.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="TOP" textLeftDistance="254" textRightDistance="254" textUpperDistance="127" textLowerDistance="127" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="SOLID" fillColor="3c8c93" fillTransparence="0" fillTransparenceGradientName="">
+ <XShape positionX="11429" positionY="1324" sizeX="2259" sizeY="15210" type="com.sun.star.drawing.CustomShape" name="Rectangle 52" text="&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;&#10;" fontHeight="24.000000" fontColor="ffffffff" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="CENTER" textVerticalAdjust="TOP" textLeftDistance="254" textRightDistance="254" textUpperDistance="127" textLowerDistance="127" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="0" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="SOLID" fillColor="3c8c93" fillTransparence="0" fillTransparenceGradientName="">
   <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
   <FillGradient style="LINEAR" startColor="3465a4" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
   <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -10,7 +10,7 @@
   <LineEnd/>
   <Transformation>
    <Line1 column1="2260.000000" column2="0.000000" column3="11429.000000"/>
-   <Line2 column1="0.000000" column2="15210.000000" column3="1324.000000"/>
+   <Line2 column1="0.000000" column2="15211.000000" column3="1324.000000"/>
    <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
   </Transformation>
   <CustomShapeGeometry>
diff --git a/sd/qa/unit/data/xml/n758621_1.xml b/sd/qa/unit/data/xml/n758621_1.xml
index 556c18673065..92de100a09f1 100644
--- a/sd/qa/unit/data/xml/n758621_1.xml
+++ b/sd/qa/unit/data/xml/n758621_1.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <XShapes>
- <XShape positionX="1485" positionY="610" sizeX="18411" sizeY="1954" type="com.sun.star.presentation.TitleTextShape" fontHeight="40.000000" fontColor="ff0000" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="CENTER" textLeftDistance="250" textRightDistance="250" textUpperDistance="130" textLowerDistance="130" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1645" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
+ <XShape positionX="1485" positionY="609" sizeX="18411" sizeY="1955" type="com.sun.star.presentation.TitleTextShape" fontHeight="40.000000" fontColor="ff0000" textAutoGrowHeight="true" textAutoGrowWidth="false" textContourFrame="false" textFitToSize="NONE" textHorizontalAdjust="LEFT" textVerticalAdjust="CENTER" textLeftDistance="250" textRightDistance="250" textUpperDistance="130" textLowerDistance="130" textMaximumFrameHeight="0" textMaximumFrameWidth="0" textMinimumFrameHeight="1645" textMinimumFrameWidth="0" textAnimationAmount="0" textAnimationCount="0" textAnimationDelay="0" textAnimationDirection="LEFT" textAnimationKind="NONE" textAnimationStartInside="false" textAnimationStopInside="false" textWritingMode="LR_TB" fillStyle="NONE" fillColor="ffffff" fillTransparence="0" fillTransparenceGradientName="">
   <FillTransparenceGradient style="LINEAR" startColor="000000" endColor="000000" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
   <FillGradient style="LINEAR" startColor="000000" endColor="ffffff" angle="0" border="0" xOffset="50" yOffset="50" startIntensity="100" endIntensity="100" stepCount="0"/>
   <FillHatch style="SINGLE" color="3465a4" distance="20" angle="0"/>
@@ -10,7 +10,7 @@
   <LineEnd/>
   <Transformation>
    <Line1 column1="18412.000000" column2="0.000000" column3="1485.000000"/>
-   <Line2 column1="0.000000" column2="1955.000000" column3="610.000000"/>
+   <Line2 column1="0.000000" column2="1956.000000" column3="609.000000"/>
    <Line3 column1="0.000000" column2="0.000000" column3="1.000000"/>
   </Transformation>
  </XShape>
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index e140c41c126d..5e09f0a2996f 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -89,6 +89,7 @@
 #include <com/sun/star/frame/Desktop.hpp>
 #include <com/sun/star/text/GraphicCrop.hpp>
 #include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
 #include <com/sun/star/xml/dom/XDocument.hpp>

 #include <stlpool.hxx>
@@ -225,7 +226,6 @@ public:
     void testPatternImport();
     void testPptCrop();
     void testTdf120028();
-    void testTdf120028b();
     void testDescriptionImport();
     void testTdf83247();
     void testTdf47365();
@@ -335,7 +335,6 @@ public:
     CPPUNIT_TEST(testTdf116266);
     CPPUNIT_TEST(testPptCrop);
     CPPUNIT_TEST(testTdf120028);
-    CPPUNIT_TEST(testTdf120028b);
     CPPUNIT_TEST(testDescriptionImport);
     CPPUNIT_TEST(testTdf83247);
     CPPUNIT_TEST(testTdf47365);
@@ -990,26 +989,20 @@ void SdImportTest::testMultiColTexts()
     sd::DrawDocShellRef xDocShRef = loadURL( m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/multicol.pptx"), PPTX );
     const SdrPage *pPage = GetPage( 1, xDocShRef );

-    sdr::table::SdrTableObj *pTableObj = dynamic_cast<sdr::table::SdrTableObj*>(pPage->GetObj(0));
-    CPPUNIT_ASSERT( pTableObj );
+    auto pTextObj = dynamic_cast<SdrTextObj*>(pPage->GetObj(0));
+    CPPUNIT_ASSERT(pTextObj);

-    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pTableObj->getRowCount());
-    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pTableObj->getColumnCount());
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(2), pTextObj->GetTextColumnsNumber());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), pTextObj->GetTextColumnsSpacing());

-    sdr::table::SdrTableObj *pMasterTableObj = dynamic_cast<sdr::table::SdrTableObj*>(pPage->TRG_GetMasterPage().GetObj(0));
-    CPPUNIT_ASSERT( pMasterTableObj );
+    auto pMasterTextObj = dynamic_cast<SdrTextObj*>(pPage->TRG_GetMasterPage().GetObj(0));
+    CPPUNIT_ASSERT(pMasterTextObj);

-    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMasterTableObj->getRowCount());
-    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pMasterTableObj->getColumnCount());
+    CPPUNIT_ASSERT_EQUAL(sal_Int16(2), pMasterTextObj->GetTextColumnsNumber());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), pMasterTextObj->GetTextColumnsSpacing());

-    uno::Reference< table::XCellRange > xTable(pMasterTableObj->getTable(), uno::UNO_QUERY_THROW);
-    uno::Reference< beans::XPropertySet > xCell;
-    xCell.set(xTable->getCellByPosition(0, 0), uno::UNO_QUERY_THROW);
-    uno::Reference<text::XTextRange> xParagraph(getParagraphFromShape(0, xCell));
-    uno::Reference<text::XTextRange> xRun( getRunFromParagraph (0, xParagraph ) );
-    OUString sText = xRun->getString();
-
-    CPPUNIT_ASSERT_EQUAL(OUString(""), sText); //We don't import master table text for multicolumn case.
+    uno::Reference<text::XTextRange> xText(pMasterTextObj->getUnoShape(), uno::UNO_QUERY_THROW);
+    CPPUNIT_ASSERT_EQUAL(OUString("mastershape1\nmastershape2"), xText->getString());
 }

 void SdImportTest::testPredefinedTableStyle()
@@ -3023,7 +3016,7 @@ void SdImportTest::testTdf116266()

 void SdImportTest::testTdf120028()
 {
-    // Check that the table shape has 4 columns.
+    // Check that the text shape has 4 columns.
     ::sd::DrawDocShellRef xDocShRef
         = loadURL(m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/tdf120028.pptx"), PPTX);
     uno::Reference<drawing::XDrawPagesSupplier> xDoc(xDocShRef->GetDoc()->getUnoModel(),
@@ -3033,63 +3026,22 @@ void SdImportTest::testTdf120028()
     uno::Reference<drawing::XDrawPage> xPage(xDoc->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
     CPPUNIT_ASSERT(xPage.is());

-    // This failed, shape was not a table, all text was rendered in a single
-    // column.
     uno::Reference<beans::XPropertySet> xShape(getShape(0, xPage));
-    uno::Reference<table::XColumnRowRange> xModel(xShape->getPropertyValue("Model"),
-                                                  uno::UNO_QUERY);
-    CPPUNIT_ASSERT(xModel.is());
-
-    uno::Reference<table::XTableColumns> xColumns = xModel->getColumns();
-    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), xColumns->getCount());
-
-    // Check font size in the A1 cell.
-    uno::Reference<table::XCellRange> xCells(xModel, uno::UNO_QUERY);
-    uno::Reference<beans::XPropertySet> xCell(xCells->getCellByPosition(0, 0), uno::UNO_QUERY);
-    uno::Reference<text::XTextRange> xParagraph(getParagraphFromShape(0, xCell));
+    uno::Reference<text::XTextColumns> xCols(xShape->getPropertyValue("TextColumns"),
+                                             uno::UNO_QUERY_THROW);
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(4), xCols->getColumnCount());
+    uno::Reference<beans::XPropertySet> xColProps(xCols, uno::UNO_QUERY_THROW);
+    CPPUNIT_ASSERT_EQUAL(uno::Any(sal_Int32(0)), xColProps->getPropertyValue("AutomaticDistance"));
+
+    // Check font size in the shape.
+    uno::Reference<text::XTextRange> xParagraph(getParagraphFromShape(0, xShape));
     uno::Reference<text::XTextRange> xRun(getRunFromParagraph(0, xParagraph));
-    uno::Reference<beans::XPropertySet> xPropSet(xRun, uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xPropSet(xRun, uno::UNO_QUERY_THROW);
     double fCharHeight = 0;
     xPropSet->getPropertyValue("CharHeight") >>= fCharHeight;
-    // This failed, non-scaled height was 13.5.
-    CPPUNIT_ASSERT_DOUBLES_EQUAL(11.5, fCharHeight, 1E-12);
-
-    xDocShRef->DoClose();
-}
-
-void SdImportTest::testTdf120028b()
-{
-    // Check that the table shape has 4 columns.
-    ::sd::DrawDocShellRef xDocShRef
-        = loadURL(m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/tdf120028b.pptx"), PPTX);
-    uno::Reference<drawing::XDrawPagesSupplier> xDoc(xDocShRef->GetDoc()->getUnoModel(),
-                                                     uno::UNO_QUERY);
-    CPPUNIT_ASSERT(xDoc.is());
-
-    uno::Reference<drawing::XDrawPage> xPage(xDoc->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
-    CPPUNIT_ASSERT(xPage.is());
-
-    uno::Reference<beans::XPropertySet> xShape(getShape(0, xPage));
-    CPPUNIT_ASSERT(xShape.is());
-
-    uno::Reference<table::XColumnRowRange> xModel(xShape->getPropertyValue("Model"),
-                                                  uno::UNO_QUERY);
-    CPPUNIT_ASSERT(xModel.is());
-
-    uno::Reference<table::XTableColumns> xColumns = xModel->getColumns();
-    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4), xColumns->getCount());
-
-    // Check font color in the A1 cell.
-    uno::Reference<table::XCellRange> xCells(xModel, uno::UNO_QUERY);
-    uno::Reference<beans::XPropertySet> xCell(xCells->getCellByPosition(0, 0), uno::UNO_QUERY);
-    uno::Reference<text::XTextRange> xParagraph(getParagraphFromShape(0, xCell));
-    uno::Reference<text::XTextRange> xRun(getRunFromParagraph(0, xParagraph));
-    uno::Reference<beans::XPropertySet> xPropSet(xRun, uno::UNO_QUERY);
-    sal_Int32 nCharColor = 0;
-    xPropSet->getPropertyValue("CharColor") >>= nCharColor;
-    // This was 0x1f497d, not white: text list style from placeholder shape
-    // from slide layout was ignored.
-    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0xffffff), nCharColor);
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(13.5, fCharHeight, 1E-12);
+    // 13.5 * 86% is approx. 11.6 (the correct scaled font size)
+    CPPUNIT_ASSERT_EQUAL(uno::Any(sal_Int16(86)), xShape->getPropertyValue("TextFitToSizeScale"));

     xDocShRef->DoClose();
 }
diff --git a/sd/qa/unit/misc-tests.cxx b/sd/qa/unit/misc-tests.cxx
index 75818805295a..82734af9eb73 100644
--- a/sd/qa/unit/misc-tests.cxx
+++ b/sd/qa/unit/misc-tests.cxx
@@ -59,6 +59,8 @@
 #include <tools/gen.hxx>
 #include <svx/view3d.hxx>
 #include <svx/scene3d.hxx>
+#include <svx/sdmetitm.hxx>
+#include <svx/unoapi.hxx>

 using namespace ::com::sun::star;

@@ -81,6 +83,7 @@ public:
     void testTdf67248();
     void testTdf119956();
     void testTdf120527();
+    void testTextColumns();
     void testTdf98839_ShearVFlipH();
     void testTdf130988();
     void testTdf131033();
@@ -103,6 +106,7 @@ public:
     CPPUNIT_TEST(testTdf67248);
     CPPUNIT_TEST(testTdf119956);
     CPPUNIT_TEST(testTdf120527);
+    CPPUNIT_TEST(testTextColumns);
     CPPUNIT_TEST(testTdf98839_ShearVFlipH);
     CPPUNIT_TEST(testTdf130988);
     CPPUNIT_TEST(testTdf131033);
@@ -492,6 +496,51 @@ void SdMiscTest::testTdf120527()
     xDocShRef->DoClose();
 }

+// Testing document model part of editengine-columns
+void SdMiscTest::testTextColumns()
+{
+    ::sd::DrawDocShellRef xDocShRef
+        = new ::sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress);
+    uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier = getDoc(xDocShRef);
+    uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
+    // Insert a new page.
+    uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPages->insertNewByIndex(0),
+                                                 uno::UNO_SET_THROW);
+    uno::Reference<drawing::XShapes> xShapes(xDrawPage, uno::UNO_QUERY_THROW);
+    uno::Reference<lang::XMultiServiceFactory> const xDoc(xDocShRef->GetDoc()->getUnoModel(),
+                                                          uno::UNO_QUERY);
+
+    {
+        // Create a text shape
+        uno::Reference<drawing::XShape> xShape(
+            xDoc->createInstance("com.sun.star.drawing.TextShape"), uno::UNO_QUERY_THROW);
+        uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY_THROW);
+
+        // Add the shape to the page.
+        xShapes->add(xShape);
+
+        // Set up columns
+        auto pTextObj = dynamic_cast<SdrTextObj*>(GetSdrObjectFromXShape(xShape));
+        CPPUNIT_ASSERT(pTextObj);
+        pTextObj->SetMergedItem(SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER, 2));
+        pTextObj->SetMergedItem(SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING, 1000));
+    }
+
+    {
+        // Retrieve the shape and check columns
+        uno::Reference<container::XIndexAccess> xIndexAccess(xDrawPage, uno::UNO_QUERY_THROW);
+        uno::Reference<drawing::XShape> xShape(xIndexAccess->getByIndex(0), uno::UNO_QUERY_THROW);
+
+        auto pTextObj = dynamic_cast<SdrTextObj*>(GetSdrObjectFromXShape(xShape));
+        CPPUNIT_ASSERT(pTextObj);
+
+        CPPUNIT_ASSERT_EQUAL(sal_Int16(2), pTextObj->GetTextColumnsNumber());
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), pTextObj->GetTextColumnsSpacing());
+    }
+
+    xDocShRef->DoClose();
+}
+
 /// Draw miscellaneous tests.

 // Since LO 6.2 the visible/printable/locked information for layers is always
diff --git a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
index beba53b67078..18b923de4461 100644
--- a/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
+++ b/sd/qa/unit/tiledrendering/LOKitSearchTest.cxx
@@ -653,7 +653,7 @@ void LOKitSearchTest::testSearchIn2MixedObjects()
     CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
     CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());

-    CPPUNIT_ASSERT_EQUAL(OString("3546, 3174, 738, 402"),
+    CPPUNIT_ASSERT_EQUAL(OString("3546, 3173, 738, 401"),
                          mpCallbackRecorder->m_aSearchResultSelection[0]);

     // Search next
@@ -679,7 +679,7 @@ void LOKitSearchTest::testSearchIn2MixedObjects()
     CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultSelection.size());
     CPPUNIT_ASSERT_EQUAL(size_t(1), mpCallbackRecorder->m_aSearchResultPart.size());

-    CPPUNIT_ASSERT_EQUAL(OString("3546, 3174, 738, 402"),
+    CPPUNIT_ASSERT_EQUAL(OString("3546, 3173, 738, 401"),
                          mpCallbackRecorder->m_aSearchResultSelection[0]);
 #endif
 }
diff --git a/sd/source/core/stlsheet.cxx b/sd/source/core/stlsheet.cxx
index 52d05351b3b9..3f6b0b905db9 100644
--- a/sd/source/core/stlsheet.cxx
+++ b/sd/source/core/stlsheet.cxx
@@ -1186,6 +1186,19 @@ PropertyState SAL_CALL SdStyleSheet::getPropertyState( const OUString& PropertyN
             return PropertyState_AMBIGUOUS_VALUE;
         }
     }
+    else if (pEntry->nWID == OWN_ATTR_TEXTCOLUMNS)
+    {
+        const SfxItemSet& rSet = GetItemSet();
+
+        const auto eState1 = rSet.GetItemState(SDRATTR_TEXTCOLUMNS_NUMBER, false);
+        const auto eState2 = rSet.GetItemState(SDRATTR_TEXTCOLUMNS_SPACING, false);
+        if (eState1 == SfxItemState::SET || eState2 == SfxItemState::SET)
+            return PropertyState_DIRECT_VALUE;
+        else if (eState1 == SfxItemState::DEFAULT && eState2 == SfxItemState::DEFAULT)
+            return PropertyState_DEFAULT_VALUE;
+        else
+            return PropertyState_AMBIGUOUS_VALUE;
+    }
     else
     {
         SfxItemSet &rStyleSet = GetItemSet();
diff --git a/svx/Library_svxcore.mk b/svx/Library_svxcore.mk
index 3d4590d216a1..e8cbb606b086 100644
--- a/svx/Library_svxcore.mk
+++ b/svx/Library_svxcore.mk
@@ -391,6 +391,7 @@ $(eval $(call gb_Library_add_exception_objects,svxcore,\
     svx/source/toolbars/fontworkbar \
     svx/source/unodraw/gluepts \
     svx/source/unodraw/shapepropertynotifier \
+    svx/source/unodraw/SvxXTextColumns \
     svx/source/unodraw/tableshape \
     svx/source/unodraw/unobrushitemhelper \
     svx/source/unodraw/unobtabl \
diff --git a/svx/source/sdr/properties/attributeproperties.cxx b/svx/source/sdr/properties/attributeproperties.cxx
index 55dbf646210e..c79ccbd75c52 100644
--- a/svx/source/sdr/properties/attributeproperties.cxx
+++ b/svx/source/sdr/properties/attributeproperties.cxx
@@ -128,7 +128,8 @@ namespace sdr::properties
                 // ranges from SdrAttrObj
                 svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
                 SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
-                SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION>{});
+                SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+                SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST>{});
         }

         AttributeProperties::AttributeProperties(SdrObject& rObj)
diff --git a/svx/source/sdr/properties/captionproperties.cxx b/svx/source/sdr/properties/captionproperties.cxx
index 0afd70af5234..b657b1879fe9 100644
--- a/svx/source/sdr/properties/captionproperties.cxx
+++ b/svx/source/sdr/properties/captionproperties.cxx
@@ -38,6 +38,7 @@ namespace sdr::properties
                     // Ranges from SdrAttrObj, SdrCaptionObj:
                     SDRATTR_START, SDRATTR_MISC_LAST,
                     SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+                    SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
                     // Range from SdrTextObj:
                     EE_ITEMS_START, EE_ITEMS_END>{});
         }
diff --git a/svx/source/sdr/properties/circleproperties.cxx b/svx/source/sdr/properties/circleproperties.cxx
index 895029ca7939..c0a9e6aec14e 100644
--- a/svx/source/sdr/properties/circleproperties.cxx
+++ b/svx/source/sdr/properties/circleproperties.cxx
@@ -42,6 +42,7 @@ namespace sdr::properties
                     SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
                     SDRATTR_CIRC_FIRST, SDRATTR_CIRC_LAST,
                     SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+                    SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
                     // Range from SdrTextObj:
                     EE_ITEMS_START, EE_ITEMS_END>{});
         }
diff --git a/svx/source/sdr/properties/connectorproperties.cxx b/svx/source/sdr/properties/connectorproperties.cxx
index 29a2b7edeb5f..f5e50cb53f83 100644
--- a/svx/source/sdr/properties/connectorproperties.cxx
+++ b/svx/source/sdr/properties/connectorproperties.cxx
@@ -39,6 +39,7 @@ namespace sdr::properties
                     SDRATTR_START, SDRATTR_SHADOW_LAST,
                     SDRATTR_MISC_FIRST, SDRATTR_EDGE_LAST,
                     SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+                    SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
                     // Range from SdrTextObj:
                     EE_ITEMS_START, EE_ITEMS_END>{});
         }
diff --git a/svx/source/sdr/properties/customshapeproperties.cxx b/svx/source/sdr/properties/customshapeproperties.cxx
index 0d1443081910..ba028bd29f8f 100644
--- a/svx/source/sdr/properties/customshapeproperties.cxx
+++ b/svx/source/sdr/properties/customshapeproperties.cxx
@@ -73,7 +73,7 @@ namespace sdr::properties
                     // Graphic attributes, 3D properties, CustomShape
                     // properties:
                     SDRATTR_GRAF_FIRST, SDRATTR_CUSTOMSHAPE_LAST,
-                    SDRATTR_GLOW_FIRST, SDRATTR_SOFTEDGE_LAST,
+                    SDRATTR_GLOW_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
                     // Range from SdrTextObj:
                     EE_ITEMS_START, EE_ITEMS_END>{});
         }
diff --git a/svx/source/sdr/properties/graphicproperties.cxx b/svx/source/sdr/properties/graphicproperties.cxx
index 2819826caad5..966cb68ab7ff 100644
--- a/svx/source/sdr/properties/graphicproperties.cxx
+++ b/svx/source/sdr/properties/graphicproperties.cxx
@@ -67,7 +67,7 @@ namespace sdr::properties
                 // range from SdrGrafObj
                 SDRATTR_GRAF_FIRST, SDRATTR_GRAF_LAST,

-                SDRATTR_GLOW_FIRST, SDRATTR_SOFTEDGE_LAST,
+                SDRATTR_GLOW_FIRST, SDRATTR_TEXTCOLUMNS_LAST,

                 // range from SdrTextObj
                 EE_ITEMS_START, EE_ITEMS_END>{});
diff --git a/svx/source/sdr/properties/measureproperties.cxx b/svx/source/sdr/properties/measureproperties.cxx
index 5519930e3dda..67b33192d890 100644
--- a/svx/source/sdr/properties/measureproperties.cxx
+++ b/svx/source/sdr/properties/measureproperties.cxx
@@ -48,6 +48,7 @@ namespace sdr::properties
                     SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
                     SDRATTR_MEASURE_FIRST, SDRATTR_MEASURE_LAST,
                     SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+                    SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
                     // Range from SdrTextObj:
                     EE_ITEMS_START, EE_ITEMS_END>{});
         }
diff --git a/svx/source/sdr/properties/textproperties.cxx b/svx/source/sdr/properties/textproperties.cxx
index 8a90de5c848b..3a3335b6c0e5 100644
--- a/svx/source/sdr/properties/textproperties.cxx
+++ b/svx/source/sdr/properties/textproperties.cxx
@@ -54,6 +54,7 @@ namespace sdr::properties
                 svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
                 SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
                 SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
+                SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,

                 // range from SdrTextObj
                 EE_ITEMS_START, EE_ITEMS_END>{});
@@ -87,6 +88,12 @@ namespace sdr::properties
             // #i101556# ItemSet has changed -> new version
             maVersion++;

+            if (auto pOutliner = rObj.GetTextEditOutliner())
+            {
+                pOutliner->SetTextColumns(rObj.GetTextColumnsNumber(),
+                                          rObj.GetTextColumnsSpacing());
+            }
+
             const svx::ITextProvider& rTextProvider(getTextProvider());
             sal_Int32 nText = rTextProvider.getTextCount();
             while (nText--)
diff --git a/svx/source/svdraw/svdattr.cxx b/svx/source/svdraw/svdattr.cxx
index 28bbfe39afce..a0e8887da5a0 100644
--- a/svx/source/svdraw/svdattr.cxx
+++ b/svx/source/svdraw/svdattr.cxx
@@ -335,6 +335,9 @@ SdrItemPool::SdrItemPool(

     rPoolDefaults[SDRATTR_SOFTEDGE_RADIUS - SDRATTR_START] = new SdrMetricItem(SDRATTR_SOFTEDGE_RADIUS, 0);

+    rPoolDefaults[SDRATTR_TEXTCOLUMNS_NUMBER - SDRATTR_START] = new SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER, 1);
+    rPoolDefaults[SDRATTR_TEXTCOLUMNS_SPACING - SDRATTR_START] = new SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING, 0);
+
     // set own ItemInfos
     mpLocalItemInfos[SDRATTR_SHADOW-SDRATTR_START]._nSID=SID_ATTR_FILL_SHADOW;
     mpLocalItemInfos[SDRATTR_SHADOWCOLOR-SDRATTR_START]._nSID=SID_ATTR_SHADOW_COLOR;
@@ -356,6 +359,9 @@ SdrItemPool::SdrItemPool(

     mpLocalItemInfos[SDRATTR_SOFTEDGE_RADIUS - SDRATTR_START]._nSID = SID_ATTR_SOFTEDGE_RADIUS;

+    mpLocalItemInfos[SDRATTR_TEXTCOLUMNS_NUMBER - SDRATTR_START]._nSID = 0 /*TODO*/;
+    mpLocalItemInfos[SDRATTR_TEXTCOLUMNS_SPACING - SDRATTR_START]._nSID = 0 /*TODO*/;
+
     // it's my own creation level, set Defaults and ItemInfos
     SetDefaults(mpLocalPoolDefaults);
     SetItemInfos(mpLocalItemInfos.get());
@@ -622,6 +628,9 @@ OUString SdrItemPool::GetItemName(sal_uInt16 nWhich)
         case EE_FEATURE_LINEBR  : pResId = SIP_EE_FEATURE_LINEBR;break;
         case EE_FEATURE_NOTCONV : pResId = SIP_EE_FEATURE_NOTCONV;break;
         case EE_FEATURE_FIELD   : pResId = SIP_EE_FEATURE_FIELD;break;
+
+        case SDRATTR_TEXTCOLUMNS_NUMBER: pResId = SIP_SA_TEXTCOLUMNS_NUMBER; break;
+        case SDRATTR_TEXTCOLUMNS_SPACING: pResId = SIP_SA_TEXTCOLUMNS_SPACING; break;
     } // switch

     return SvxResId(pResId);
diff --git a/svx/source/svdraw/svdotext.cxx b/svx/source/svdraw/svdotext.cxx
index 0daeb7cc9a5d..855e07d4c4af 100644
--- a/svx/source/svdraw/svdotext.cxx
+++ b/svx/source/svdraw/svdotext.cxx
@@ -51,6 +51,7 @@
 #include <vcl/virdev.hxx>
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
 #include <sal/log.hxx>
+#include <o3tl/temporary.hxx>

 using namespace com::sun::star;

@@ -682,11 +683,13 @@ void SdrTextObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRe
         if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
         {
             rOutliner.SetMinAutoPaperSize(Size(nAnkWdt, 0));
+            rOutliner.SetMinColumnWrapHeight(nAnkHgt);
         }

         if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
         {
             rOutliner.SetMinAutoPaperSize(Size(0, nAnkHgt));
+            rOutliner.SetMinColumnWrapHeight(nAnkWdt);
         }
     }

@@ -1188,67 +1191,15 @@ void SdrTextObj::ImpSetupDrawOutlinerForPaint( bool             bContourFrame,
     }
 }

-double SdrTextObj::GetFontScaleY() const
+sal_uInt16 SdrTextObj::GetFontScaleY() const
 {
-    SdrText* pText = getActiveText();
-    if (pText == nullptr || !pText->GetOutlinerParaObject())
-        return 1.0;
-
     SdrOutliner& rOutliner = ImpGetDrawOutliner();
-    const Size aShapeSize = GetSnapRect().GetSize();
-    const Size aSize(aShapeSize.Width() - GetTextLeftDistance() - GetTextRightDistance(),
-        aShapeSize.Height() - GetTextUpperDistance() - GetTextLowerDistance());
-
-    rOutliner.SetPaperSize(aSize);
-    rOutliner.SetUpdateMode(true);
-    rOutliner.SetText(*pText->GetOutlinerParaObject());
-    bool bIsVerticalWriting = IsVerticalWriting();
-
-    // Algorithm from SdrTextObj::ImpAutoFitText
-
-    sal_uInt16 nMinStretchX = 0, nMinStretchY = 0;
-    sal_uInt16 nCurrStretchX = 100, nCurrStretchY = 100;
-    sal_uInt16 aOldStretchXVals[] = { 0,0,0 };
-    const size_t aStretchArySize = SAL_N_ELEMENTS(aOldStretchXVals);
-    for (unsigned int i = 0; i<aStretchArySize; ++i)
-    {
-        const Size aCurrTextSize = rOutliner.CalcTextSizeNTP();
-        double fFactor(1.0);
-        if (bIsVerticalWriting)
-        {
-            if (aCurrTextSize.Width() != 0)
-            {
-                fFactor = double(aSize.Width()) / aCurrTextSize.Width();
-            }
-        }
-        else if (aCurrTextSize.Height() != 0)
-        {
-            fFactor = double(aSize.Height()) / aCurrTextSize.Height();
-        }
-        fFactor = std::sqrt(fFactor);
-
-        rOutliner.GetGlobalCharStretching(nCurrStretchX, nCurrStretchY);
-
-        if (fFactor >= 1.0)
-        {
-            nMinStretchX = std::max(nMinStretchX, nCurrStretchX);
-            nMinStretchY = std::max(nMinStretchY, nCurrStretchY);
-        }
-
-        aOldStretchXVals[i] = nCurrStretchX;
-        if (std::find(aOldStretchXVals, aOldStretchXVals + i, nCurrStretchX) != aOldStretchXVals + i)
-            break; // same value already attained once; algo is looping, exit
+    // This eventually calls ImpAutoFitText
+    UpdateOutlinerFormatting(rOutliner, o3tl::temporary(tools::Rectangle()));

-        if (fFactor < 1.0 || nCurrStretchX != 100)
-        {
-            nCurrStretchX = sal::static_int_cast<sal_uInt16>(nCurrStretchX*fFactor);
-            nCurrStretchY = sal::static_int_cast<sal_uInt16>(nCurrStretchY*fFactor);
-            rOutliner.SetGlobalCharStretching(std::min(sal_uInt16(100), nCurrStretchX),
-                std::min(sal_uInt16(100), nCurrStretchY));
-        }
-    }
-
-    return std::min(sal_uInt16(100), nCurrStretchY) / 100.0;
+    sal_uInt16 nStretchY;
+    rOutliner.GetGlobalCharStretching(o3tl::temporary(sal_uInt16()), nStretchY);
+    return nStretchY;
 }

 void SdrTextObj::ImpAutoFitText( SdrOutliner& rOutliner ) const
@@ -1777,6 +1728,36 @@ SdrTextAniDirection SdrTextObj::GetTextAniDirection() const
     return GetObjectItemSet().Get(SDRATTR_TEXT_ANIDIRECTION).GetValue();
 }

+bool SdrTextObj::HasTextColumnsNumber() const
+{
+    return GetObjectItemSet().HasItem(SDRATTR_TEXTCOLUMNS_NUMBER);
+}
+
+sal_Int16 SdrTextObj::GetTextColumnsNumber() const
+{
+    return GetObjectItemSet().Get(SDRATTR_TEXTCOLUMNS_NUMBER).GetValue();
+}
+
+void SdrTextObj::SetTextColumnsNumber(sal_Int16 nColumns)
+{
+    SetObjectItem(SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER, nColumns));
+}
+
+bool SdrTextObj::HasTextColumnsSpacing() const
+{
+    return GetObjectItemSet().HasItem(SDRATTR_TEXTCOLUMNS_SPACING);
+}
+
+sal_Int32 SdrTextObj::GetTextColumnsSpacing() const
+{
+    return GetObjectItemSet().Get(SDRATTR_TEXTCOLUMNS_SPACING).GetValue();
+}
+
+void SdrTextObj::SetTextColumnsSpacing(sal_Int32 nSpacing)
+{
+    SetObjectItem(SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING, nSpacing));
+}
+
 // Get necessary data for text scroll animation. ATM base it on a Text-Metafile and a
 // painting rectangle. Rotation is excluded from the returned values.
 GDIMetaFile* SdrTextObj::GetTextScrollMetaFileAndRectangle(
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx
index de362466fe03..b54202c51847 100644
--- a/svx/source/svdraw/svdotextdecomposition.cxx
+++ b/svx/source/svdraw/svdotextdecomposition.cxx
@@ -770,11 +770,13 @@ void SdrTextObj::impDecomposeAutoFitTextPrimitive(
     if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !bVerticalWriting)
     {
         rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
+        rOutliner.SetMinColumnWrapHeight(nAnchorTextHeight);
     }

     if(SDRTEXTVERTADJUST_BLOCK == eVAdj && bVerticalWriting)
     {
         rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
+        rOutliner.SetMinColumnWrapHeight(nAnchorTextWidth);
     }

     rOutliner.SetPaperSize(aNullSize);
@@ -983,10 +985,12 @@ void SdrTextObj::impDecomposeBlockTextPrimitive(
         if(bHorizontalIsBlock)
         {
             rOutliner.SetMinAutoPaperSize(Size(nAnchorTextWidth, 0));
+            rOutliner.SetMinColumnWrapHeight(nAnchorTextHeight);
         }
         else if(bVerticalIsBlock)
         {
             rOutliner.SetMinAutoPaperSize(Size(0, nAnchorTextHeight));
+            rOutliner.SetMinColumnWrapHeight(nAnchorTextWidth);
         }

         if((rSdrBlockTextPrimitive.getWordWrap() || IsTextFrame()) && !rSdrBlockTextPrimitive.getUnlimitedPage())
diff --git a/svx/source/svdraw/svdotxed.cxx b/svx/source/svdraw/svdotxed.cxx
index 6e423029f582..f62bd8d913cc 100644
--- a/svx/source/svdraw/svdotxed.cxx
+++ b/svx/source/svdraw/svdotxed.cxx
@@ -349,6 +349,7 @@ void SdrTextObj::ImpSetTextEditParams() const
     pEdtOutl->SetMinAutoPaperSize(aPaperMin);
     pEdtOutl->SetMaxAutoPaperSize(aPaperMax);
     pEdtOutl->SetPaperSize(Size());
+    pEdtOutl->SetTextColumns(GetTextColumnsNumber(), GetTextColumnsSpacing());
     if (bContourFrame) {
         tools::Rectangle aAnchorRect;
         TakeTextAnchorRect(aAnchorRect);
diff --git a/svx/source/svdraw/svdoutl.cxx b/svx/source/svdraw/svdoutl.cxx
index fed5e1c82f25..738309182fd7 100644
--- a/svx/source/svdraw/svdoutl.cxx
+++ b/svx/source/svdraw/svdoutl.cxx
@@ -57,6 +57,7 @@ void SdrOutliner::SetTextObj( const SdrTextObj* pObj )
         SetMinAutoPaperSize( Size() );
         SetMaxAutoPaperSize( aMaxSize );
         SetPaperSize( aMaxSize );
+        SetTextColumns(pObj->GetTextColumnsNumber(), pObj->GetTextColumnsSpacing());
         ClearPolygon();
     }

diff --git a/svx/source/unodraw/SvxXTextColumns.cxx b/svx/source/unodraw/SvxXTextColumns.cxx
new file mode 100644
index 000000000000..3d4732cc9817
--- /dev/null
+++ b/svx/source/unodraw/SvxXTextColumns.cxx
@@ -0,0 +1,334 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyVetoException.hpp>
+#include <com/sun/star/beans/UnknownPropertyException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <com/sun/star/text/ColumnSeparatorStyle.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/util/Color.hpp>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/safeint.hxx>
+#include <svl/itemprop.hxx>
+#include <svx/SvxXTextColumns.hxx>
+#include <tools/UnitConversion.hxx>
+#include <vcl/svapp.hxx>
+
+#include <numeric>
+
+namespace
+{
+enum : sal_uInt16
+{
+    WID_TXTCOL_IS_AUTOMATIC,
+    WID_TXTCOL_AUTO_DISTANCE,
+    WID_TXTCOL_LINE_WIDTH,
+    WID_TXTCOL_LINE_COLOR,
+    WID_TXTCOL_LINE_REL_HGT,
+    WID_TXTCOL_LINE_ALIGN,
+    WID_TXTCOL_LINE_IS_ON,
+    WID_TXTCOL_LINE_STYLE,
+};
+
+SfxItemPropertyMapEntry const saTextColumns_Impl[] = {
+    { u"IsAutomatic", WID_TXTCOL_IS_AUTOMATIC, cppu::UnoType<bool>::get(),
+      css::beans::PropertyAttribute::READONLY, 0 },
+    { u"AutomaticDistance", WID_TXTCOL_AUTO_DISTANCE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+    { u"SeparatorLineWidth", WID_TXTCOL_LINE_WIDTH, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+    { u"SeparatorLineColor", WID_TXTCOL_LINE_COLOR,
+      cppu::UnoType<com::sun::star::util::Color>::get(), 0, 0 },
+    { u"SeparatorLineRelativeHeight", WID_TXTCOL_LINE_REL_HGT, cppu::UnoType<sal_Int32>::get(), 0,
+      0 },
+    { u"SeparatorLineVerticalAlignment", WID_TXTCOL_LINE_ALIGN,
+      cppu::UnoType<css::style::VerticalAlignment>::get(), 0, 0 },
+    { u"SeparatorLineIsOn", WID_TXTCOL_LINE_IS_ON, cppu::UnoType<bool>::get(), 0, 0 },
+    { u"SeparatorLineStyle", WID_TXTCOL_LINE_STYLE, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+    { u"", 0, css::uno::Type(), 0, 0 },
+};
+
+class SvxXTextColumns final
+    : public cppu::WeakImplHelper<css::beans::XPropertySet, css::text::XTextColumns,
+                                  css::lang::XServiceInfo>
+{
+public:
+    SvxXTextColumns() = default;
+
+    // XTextColumns
+    virtual sal_Int32 SAL_CALL getReferenceValue() override;
+    virtual sal_Int16 SAL_CALL getColumnCount() override;
+    virtual void SAL_CALL setColumnCount(sal_Int16 nColumns) override;
+    virtual css::uno::Sequence<css::text::TextColumn> SAL_CALL getColumns() override;
+    virtual void SAL_CALL
+    setColumns(const css::uno::Sequence<css::text::TextColumn>& Columns) override;
+
+    // XPropertySet
+    virtual css::uno::Reference<css::beans::XPropertySetInfo>
+        SAL_CALL getPropertySetInfo() override;
+    virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName,
+                                           const css::uno::Any& aValue) override;
+    virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
+    virtual void SAL_CALL addPropertyChangeListener(
+        const OUString& aPropertyName,
+        const css::uno::Reference<css::beans::XPropertyChangeListener>& xListener) override;
+    virtual void SAL_CALL removePropertyChangeListener(
+        const OUString& aPropertyName,
+        const css::uno::Reference<css::beans::XPropertyChangeListener>& aListener) override;
+    virtual void SAL_CALL addVetoableChangeListener(
+        const OUString& PropertyName,
+        const css::uno::Reference<css::beans::XVetoableChangeListener>& aListener) override;
+    virtual void SAL_CALL removeVetoableChangeListener(
+        const OUString& PropertyName,
+        const css::uno::Reference<css::beans::XVetoableChangeListener>& aListener) override;
+
+    // XServiceInfo
+    virtual OUString SAL_CALL getImplementationName() override;
+    virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+    virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+private:
+    sal_Int32 m_nReference = USHRT_MAX;
+    css::uno::Sequence<css::text::TextColumn> m_aTextColumns;
+    bool m_bIsAutomaticWidth = true;
+    sal_Int32 m_nAutoDistance = 0;
+
+    const SfxItemPropertySet m_aPropSet = { saTextColumns_Impl };
+
+    //separator line
+    sal_Int32 m_nSepLineWidth = 0;
+    com::sun::star::util::Color m_nSepLineColor = 0; // black
+    sal_Int32 m_nSepLineHeightRelative = 100; // full height
+    css::style::VerticalAlignment m_nSepLineVertAlign = css::style::VerticalAlignment_MIDDLE;
+    bool m_bSepLineIsOn = false;
+    sal_Int16 m_nSepLineStyle = css::text::ColumnSeparatorStyle::NONE;
+};
+
+OUString SvxXTextColumns::getImplementationName() { return "com.sun.star.comp.svx.TextColumns"; }
+
+sal_Bool SvxXTextColumns::supportsService(const OUString& rServiceName)
+{
+    return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence<OUString> SvxXTextColumns::getSupportedServiceNames()
+{
+    return { "com.sun.star.text.TextColumns" };
+}
+
+sal_Int32 SvxXTextColumns::getReferenceValue()
+{
+    SolarMutexGuard aGuard;
+    return m_nReference;
+}
+
+sal_Int16 SvxXTextColumns::getColumnCount()
+{
+    SolarMutexGuard aGuard;
+    return static_cast<sal_Int16>(m_aTextColumns.getLength());
+}
+
+void SvxXTextColumns::setColumnCount(sal_Int16 nColumns)
+{
+    SolarMutexGuard aGuard;
+    if (nColumns <= 0)
+        throw css::uno::RuntimeException();
+    m_bIsAutomaticWidth = true;
+    m_aTextColumns.realloc(nColumns);
+    css::text::TextColumn* pCols = m_aTextColumns.getArray();
+    m_nReference = USHRT_MAX;
+    sal_Int32 nWidth = m_nReference / nColumns;
+    sal_Int32 nDiff = m_nReference - nWidth * nColumns;
+    sal_Int32 nDist = m_nAutoDistance / 2;
+    for (sal_Int16 i = 0; i < nColumns; i++)
+    {
+        pCols[i].Width = nWidth;
+        pCols[i].LeftMargin = i == 0 ? 0 : nDist;
+        pCols[i].RightMargin = i == nColumns - 1 ? 0 : nDist;
+    }
+    pCols[nColumns - 1].Width += nDiff;
+}
+
+css::uno::Sequence<css::text::TextColumn> SvxXTextColumns::getColumns()
+{
+    SolarMutexGuard aGuard;
+    return m_aTextColumns;
+}
+
+void SvxXTextColumns::setColumns(const css::uno::Sequence<css::text::TextColumn>& rColumns)
+{
+    SolarMutexGuard aGuard;
+    sal_Int32 nReferenceTemp = std::accumulate(
+        rColumns.begin(), rColumns.end(), sal_Int32(0),
+        [](const sal_Int32 nSum, const css::text::TextColumn& rCol) { return nSum + rCol.Width; });
+    m_bIsAutomaticWidth = false;
+    m_nReference = !nReferenceTemp ? USHRT_MAX : nReferenceTemp;
+    m_aTextColumns = rColumns;
+}
+
+css::uno::Reference<css::beans::XPropertySetInfo> SvxXTextColumns::getPropertySetInfo()
+{
+    return m_aPropSet.getPropertySetInfo();
+}
+
+void SvxXTextColumns::setPropertyValue(const OUString& rPropertyName, const css::uno::Any& aValue)
+{
+    const SfxItemPropertySimpleEntry* pEntry = m_aPropSet.getPropertyMap().getByName(rPropertyName);
+    if (!pEntry)
+        throw css::beans::UnknownPropertyException("Unknown property: " + rPropertyName,
+                                                   static_cast<cppu::OWeakObject*>(this));
+    if (pEntry->nFlags & css::beans::PropertyAttribute::READONLY)
+        throw css::beans::PropertyVetoException("Property is read-only: " + rPropertyName,
+                                                static_cast<cppu::OWeakObject*>(this));
+
+    switch (pEntry->nWID)
+    {
+        case WID_TXTCOL_LINE_WIDTH:
+            if (sal_Int32 nTmp; !(aValue >>= nTmp) || nTmp < 0)
+                throw css::lang::IllegalArgumentException();
+            else
+                m_nSepLineWidth = convertMm100ToTwip(nTmp);
+            break;
+        case WID_TXTCOL_LINE_COLOR:
+            if (!(aValue >>= m_nSepLineColor))
+                throw css::lang::IllegalArgumentException();
+            break;
+        case WID_TXTCOL_LINE_STYLE:
+            if (!(aValue >>= m_nSepLineStyle))
+                throw css::lang::IllegalArgumentException();
+            break;
+        case WID_TXTCOL_LINE_REL_HGT:
+            if (sal_Int32 nTmp; !(aValue >>= nTmp) || nTmp < 0)
+                throw css::lang::IllegalArgumentException();
+            else
+                m_nSepLineHeightRelative = nTmp;
+            break;
+        case WID_TXTCOL_LINE_ALIGN:
+            if (css::style::VerticalAlignment eAlign; aValue >>= eAlign)
+                m_nSepLineVertAlign = eAlign;
+            else if (sal_Int8 nTmp; aValue >>= nTmp)
+                m_nSepLineVertAlign = static_cast<css::style::VerticalAlignment>(nTmp);
+            else
+                throw css::lang::IllegalArgumentException();
+            break;
+        case WID_TXTCOL_LINE_IS_ON:
+            if (!(aValue >>= m_bSepLineIsOn))
+                throw css::lang::IllegalArgumentException();
+            break;
+        case WID_TXTCOL_AUTO_DISTANCE:
+            if (sal_Int32 nTmp; !(aValue >>= nTmp) || nTmp < 0 || nTmp >= m_nReference)
+                throw css::lang::IllegalArgumentException();
+            else
+            {
+                m_nAutoDistance = nTmp;
+                sal_Int32 nColumns = m_aTextColumns.getLength();
+                css::text::TextColumn* pCols = m_aTextColumns.getArray();
+                sal_Int32 nDist = m_nAutoDistance / 2;
+                for (sal_Int32 i = 0; i < nColumns; i++)
+                {
+                    pCols[i].LeftMargin = i == 0 ? 0 : nDist;
+                    pCols[i].RightMargin = i == nColumns - 1 ? 0 : nDist;
+                }
+            }
+            break;
+    }
+}
+
+css::uno::Any SvxXTextColumns::getPropertyValue(const OUString& rPropertyName)
+{
+    const SfxItemPropertySimpleEntry* pEntry = m_aPropSet.getPropertyMap().getByName(rPropertyName);
+    if (!pEntry)
+        throw css::beans::UnknownPropertyException("Unknown property: " + rPropertyName,
+                                                   static_cast<cppu::OWeakObject*>(this));
+
+    css::uno::Any aRet;
+    switch (pEntry->nWID)
+    {
+        case WID_TXTCOL_LINE_WIDTH:
+            aRet <<= static_cast<sal_Int32>(convertTwipToMm100(m_nSepLineWidth));
+            break;
+        case WID_TXTCOL_LINE_COLOR:
+            aRet <<= m_nSepLineColor;
+            break;
+        case WID_TXTCOL_LINE_STYLE:
+            aRet <<= m_nSepLineStyle;
+            break;
+        case WID_TXTCOL_LINE_REL_HGT:
+            aRet <<= m_nSepLineHeightRelative;
+            break;
+        case WID_TXTCOL_LINE_ALIGN:
+            aRet <<= m_nSepLineVertAlign;
+            break;
+        case WID_TXTCOL_LINE_IS_ON:
+            aRet <<= m_bSepLineIsOn;
+            break;
+        case WID_TXTCOL_IS_AUTOMATIC:
+            aRet <<= m_bIsAutomaticWidth;
+            break;
+        case WID_TXTCOL_AUTO_DISTANCE:
+            aRet <<= m_nAutoDistance;
+            break;
+    }
+    return aRet;
+}
+
+void SvxXTextColumns::addPropertyChangeListener(
+    const OUString& /*rPropertyName*/,
+    const css::uno::Reference<css::beans::XPropertyChangeListener>& /*xListener*/)
+{
+}
+
+void SvxXTextColumns::removePropertyChangeListener(
+    const OUString& /*rPropertyName*/,
+    const css::uno::Reference<css::beans::XPropertyChangeListener>& /*xListener*/)
+{
+}
+
+void SvxXTextColumns::addVetoableChangeListener(
+    const OUString& /*rPropertyName*/,
+    const css::uno::Reference<css::beans::XVetoableChangeListener>& /*xListener*/)
+{
+}
+
+void SvxXTextColumns::removeVetoableChangeListener(
+    const OUString& /*rPropertyName*/,
+    const css::uno::Reference<css::beans::XVetoableChangeListener>& /*xListener*/)
+{
+}
+}
+
+css::uno::Reference<css::uno::XInterface> SvxXTextColumns_createInstance() noexcept
+{
+    return static_cast<cppu::OWeakObject*>(new SvxXTextColumns);
+}
+
+extern "C" SVXCORE_DLLPUBLIC css::uno::XInterface*
+com_sun_star_comp_svx_TextColumns_get_implementation(css::uno::XComponentContext*,
+                                                     css::uno::Sequence<css::uno::Any> const&)
+{
+    return cppu::acquire(new SvxXTextColumns);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/svx/source/unodraw/unomod.cxx b/svx/source/unodraw/unomod.cxx
index eb80ab186deb..69f1b468f10d 100644
--- a/svx/source/unodraw/unomod.cxx
+++ b/svx/source/unodraw/unomod.cxx
@@ -48,6 +48,7 @@
 #include <svx/unomodel.hxx>
 #include <svx/svdobj.hxx>
 #include <svx/svdpage.hxx>
+#include <svx/SvxXTextColumns.hxx>
 #include <svx/unoshape.hxx>
 #include <svx/xmlgrhlp.hxx>

@@ -182,6 +183,10 @@ css::uno::Reference<css::uno::XInterface> create(
         uno::Reference< uno::XInterface> xRet( static_cast< ::cppu::OWeakObject* >( pGraphicHelper.get() ) );
         return xRet;
     }
+    else if (rServiceSpecifier == "com.sun.star.text.TextColumns")
+    {
+        return SvxXTextColumns_createInstance();
+    }

     uno::Reference< uno::XInterface > xRet( SvxUnoDrawMSFactory::createTextField( rServiceSpecifier ) );
     if( !xRet.is() )
diff --git a/svx/source/unodraw/unopool.cxx b/svx/source/unodraw/unopool.cxx
index ec293ac1bf55..082841bb0827 100644
--- a/svx/source/unodraw/unopool.cxx
+++ b/svx/source/unodraw/unopool.cxx
@@ -247,6 +247,13 @@ void SvxUnoDrawPool::_getPropertyStates( const comphelper::PropertyMapEntry** pp
                     }
                 }
                 break;
+            case OWN_ATTR_TEXTCOLUMNS:
+                if (IsStaticDefaultItem(&pPool->GetDefaultItem(sal_uInt16(SDRATTR_TEXTCOLUMNS_NUMBER)))
+                    && IsStaticDefaultItem(&pPool->GetDefaultItem(sal_uInt16(SDRATTR_TEXTCOLUMNS_SPACING))))
+                    *pStates = beans::PropertyState_DEFAULT_VALUE;
+                else
+                    *pStates = beans::PropertyState_DIRECT_VALUE;
+                break;
             default:
                 //#i18732# - correction:
                 // use method <IsStaticDefaultItem(..)> instead of using probably
diff --git a/svx/source/unodraw/unoshape.cxx b/svx/source/unodraw/unoshape.cxx
index 1885348f9c64..9461bb00dafa 100644
--- a/svx/source/unodraw/unoshape.cxx
+++ b/svx/source/unodraw/unoshape.cxx
@@ -84,6 +84,7 @@
 #include <vcl/wmf.hxx>
 #include <svx/sdtfsitm.hxx>
 #include <svx/svdoutl.hxx>
+#include <svx/SvxXTextColumns.hxx>

 #include <memory>
 #include <vector>
@@ -183,14 +184,7 @@ sal_Int16 GetTextFitToSizeScale(SdrObject* pObject)
         return 0;
     }

-    std::unique_ptr<SdrOutliner> pOutliner
-        = pTextObj->getSdrModelFromSdrObject().createOutliner(OutlinerMode::TextObject);
-    tools::Rectangle aBoundRect(pTextObj->GetCurrentBoundRect());
-    pTextObj->SetupOutlinerFormatting(*pOutliner, aBoundRect);
-    sal_uInt16 nX = 0;
-    sal_uInt16 nY = 0;
-    pOutliner->GetGlobalCharStretching(nX, nY);
-    return nY;
+    return pTextObj->GetFontScaleY();
 }
 }

@@ -2519,6 +2513,27 @@ bool SvxShape::setPropertyValueImpl( const OUString&, const SfxItemPropertySimpl
             return false;
         }
     }
+
+    case OWN_ATTR_TEXTCOLUMNS:
+    {
+        if (auto pTextObj = dynamic_cast<SdrTextObj*>(GetSdrObject()))
+        {
+            css::uno::Reference<css::text::XTextColumns> xTextColumns;
+            if (rValue >>= xTextColumns)
+            {
+                pTextObj->SetTextColumnsNumber(xTextColumns->getColumnCount());
+                if (css::uno::Reference<css::beans::XPropertySet> xPropSet{ xTextColumns,
+                                                                            css::uno::UNO_QUERY })
+                {
+                    auto aVal = xPropSet->getPropertyValue("AutomaticDistance");
+                    if (sal_Int32 nSpacing; aVal >>= nSpacing)
+                        pTextObj->SetTextColumnsSpacing(nSpacing);
+                }
+            }
+        }
+        return true;
+    }
+
     default:
     {
         return false;
@@ -2919,6 +2934,23 @@ bool SvxShape::getPropertyValueImpl( const OUString&, const SfxItemPropertySimpl
         break;
     }

+    case OWN_ATTR_TEXTCOLUMNS:
+    {
+        if (auto pTextObj = dynamic_cast<const SdrTextObj*>(GetSdrObject()))
+        {
+            if (pTextObj->HasTextColumnsNumber() || pTextObj->HasTextColumnsSpacing())
+            {
+                auto xIf = SvxXTextColumns_createInstance();
+                css::uno::Reference<css::text::XTextColumns> xCols(xIf, css::uno::UNO_QUERY_THROW);
+                xCols->setColumnCount(pTextObj->GetTextColumnsNumber());
+                css::uno::Reference<css::beans::XPropertySet> xProp(xIf, css::uno::UNO_QUERY_THROW);
+                xProp->setPropertyValue("AutomaticDistance",
+                                        css::uno::Any(pTextObj->GetTextColumnsSpacing()));
+                rValue <<= xIf;
+            }
+        }
+        break;
+    }

     default:
         return false;
diff --git a/svx/util/svxcore.component b/svx/util/svxcore.component
index b36a8d71bcb4..d8989b71f4e9 100644
--- a/svx/util/svxcore.component
+++ b/svx/util/svxcore.component
@@ -92,4 +92,8 @@
     constructor="com_sun_star_comp_svx_StylesPreviewToolBoxControl_get_implementation">
     <service name="com.sun.star.frame.ToolbarController"/>
   </implementation>
+  <implementation name="com.sun.star.comp.svx.TextColumns"
+    constructor="com_sun_star_comp_svx_TextColumns_get_implementation">
+    <service name="com.sun.star.text.TextColumns"/>
+  </implementation>
 </component>
diff --git a/sw/inc/unomap.hxx b/sw/inc/unomap.hxx
index 1cd22609f02e..d2c54d204188 100644
--- a/sw/inc/unomap.hxx
+++ b/sw/inc/unomap.hxx
@@ -58,7 +58,6 @@ struct SfxItemPropertyMapEntry;
 #define PROPERTY_MAP_AUTO_TEXT_GROUP        31
 #define PROPERTY_MAP_TEXTPORTION_EXTENSIONS 34
 #define PROPERTY_MAP_FOOTNOTE               35
-#define PROPERTY_MAP_TEXT_COLUMS            36
 #define PROPERTY_MAP_PARAGRAPH              37
 #define PROPERTY_MAP_EMBEDDED_OBJECT        38
 #define PROPERTY_MAP_REDLINE                39
@@ -305,16 +304,6 @@ struct SfxItemPropertyMapEntry;
 #define WID_IS_OUTLINE                  4
 #define WID_DEFAULT_LIST_ID             5

-// TextColumns
-#define WID_TXTCOL_LINE_WIDTH           0
-#define WID_TXTCOL_LINE_COLOR           1
-#define WID_TXTCOL_LINE_REL_HGT         2
-#define WID_TXTCOL_LINE_ALIGN           3
-#define WID_TXTCOL_LINE_IS_ON           4
-#define WID_TXTCOL_IS_AUTOMATIC         5
-#define WID_TXTCOL_AUTO_DISTANCE        6
-#define WID_TXTCOL_LINE_STYLE           7
-
 // This define would need the include of <svx/unoshprp.hxx>, but this ends
 // in a mess; there *are* double used symbols which are used in a #define in
 // editengine and as an enum in sw; these will then collide and lead to severe
diff --git a/sw/inc/unosett.hxx b/sw/inc/unosett.hxx
index 4b3f177fb034..9a118f99cdec 100644
--- a/sw/inc/unosett.hxx
+++ b/sw/inc/unosett.hxx
@@ -239,71 +239,6 @@ public:

 };

-class SwXTextColumns final : public cppu::WeakAggImplHelper4
-<
-
-    css::lang::XUnoTunnel,
-    css::beans::XPropertySet,
-    css::text::XTextColumns,
-    css::lang::XServiceInfo
->
-{
-    sal_Int32                   m_nReference;
-    css::uno::Sequence< css::text::TextColumn>    m_aTextColumns;
-    bool                        m_bIsAutomaticWidth;
-    sal_Int32                   m_nAutoDistance;
-
-    const SfxItemPropertySet*   m_pPropSet;
-
-    //separator line
-    sal_Int32                   m_nSepLineWidth;
-    Color                       m_nSepLineColor;
-    sal_Int8                    m_nSepLineHeightRelative;
-    css::style::VerticalAlignment m_nSepLineVertAlign;
-    bool                        m_bSepLineIsOn;
-    sal_Int8                    m_nSepLineStyle;
-
-
-    virtual ~SwXTextColumns() override;
-public:
-    SwXTextColumns();
-    SwXTextColumns(const SwFormatCol& rFormatCol);
-
-    static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
-
-    //XUnoTunnel
-    virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
-
-    //XTextColumns
-    virtual sal_Int32 SAL_CALL getReferenceValue(  ) override;
-    virtual sal_Int16 SAL_CALL getColumnCount(  ) override;
-    virtual void SAL_CALL setColumnCount( sal_Int16 nColumns ) override;
-    virtual css::uno::Sequence< css::text::TextColumn > SAL_CALL getColumns(  ) override;
-    virtual void SAL_CALL setColumns( const css::uno::Sequence< css::text::TextColumn >& Columns ) override;
-
-    //XPropertySet
-    virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(  ) override;
-    virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
-    virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
-    virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
-    virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
-    virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
-    virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
-
-    //XServiceInfo
-    virtual OUString SAL_CALL getImplementationName() override;
-    virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
-    virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
-
-    sal_Int32   GetSepLineWidth() const {return m_nSepLineWidth;}
-    Color       GetSepLineColor() const {return m_nSepLineColor;}
-    sal_Int8    GetSepLineHeightRelative() const {return    m_nSepLineHeightRelative;}
-    css::style::VerticalAlignment GetSepLineVertAlign() const {return m_nSepLineVertAlign;}
-    bool        GetSepLineIsOn() const {return  m_bSepLineIsOn;}
-    sal_Int8    GetSepLineStyle() const {return m_nSepLineStyle;}
-
-    bool        IsAutomaticWidth() const {return m_bIsAutomaticWidth;}
-};
 #endif

 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index 8755ee81235d..046566250a8c 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -17,6 +17,9 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */

+#include <sal/config.h>
+
+#include <com/sun/star/text/ColumnSeparatorStyle.hpp>
 #include <com/sun/star/text/WrapTextMode.hpp>
 #include <com/sun/star/text/TextContentAnchorType.hpp>
 #include <com/sun/star/container/XIndexContainer.hpp>
@@ -78,6 +81,7 @@
 #include <unomid.h>
 #include <strings.hrc>
 #include <svx/svdundo.hxx>
+#include <svx/SvxXTextColumns.hxx>
 #include <sortedobjs.hxx>
 #include <HandleAnchorNodeChg.hxx>
 #include <calbck.hxx>
@@ -85,6 +89,7 @@
 #include <drawdoc.hxx>
 #include <hints.hxx>
 #include <frameformats.hxx>
+#include <unoprnms.hxx>

 #include <ndtxt.hxx>

@@ -1097,7 +1102,81 @@ bool SwFormatCol::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const
     }
     else
     {
-        uno::Reference< text::XTextColumns >  xCols = new SwXTextColumns(*this);
+        uno::Reference<text::XTextColumns> xCols(SvxXTextColumns_createInstance(),
+                                                 css::uno::UNO_QUERY_THROW);
+        uno::Reference<beans::XPropertySet> xProps(xCols, css::uno::UNO_QUERY_THROW);
+
+        if (GetNumCols() > 0)
+        {
+            xCols->setColumnCount(GetNumCols());
+            const sal_uInt16 nItemGutterWidth = GetGutterWidth();
+            sal_Int32 nAutoDistance = IsOrtho() ? USHRT_MAX == nItemGutterWidth
+                                                      ? DEF_GUTTER_WIDTH
+                                                      : static_cast<sal_Int32>(nItemGutterWidth)
+                                                : 0;
+            nAutoDistance = convertTwipToMm100(nAutoDistance);
+            xProps->setPropertyValue(UNO_NAME_AUTOMATIC_DISTANCE, uno::Any(nAutoDistance));
+
+            if (!IsOrtho())
+            {
+                auto aTextColumns = xCols->getColumns();
+                text::TextColumn* pColumns = aTextColumns.getArray();
+                const SwColumns& rCols = GetColumns();
+                for (sal_Int32 i = 0; i < aTextColumns.getLength(); ++i)
+                {
+                    const SwColumn* pCol = &rCols[i];
+
+                    pColumns[i].Width = pCol->GetWishWidth();
+                    pColumns[i].LeftMargin = convertTwipToMm100(pCol->GetLeft());
+                    pColumns[i].RightMargin = convertTwipToMm100(pCol->GetRight());
+                }
+                xCols->setColumns(aTextColumns); // sets "IsAutomatic" property to false
+            }
+        }
+        uno::Any aVal;
+        aVal <<= static_cast<sal_Int32>(GetLineWidth());
+        xProps->setPropertyValue(UNO_NAME_SEPARATOR_LINE_WIDTH, aVal);
+        aVal <<= GetLineColor();
+        xProps->setPropertyValue(UNO_NAME_SEPARATOR_LINE_COLOR, aVal);
+        aVal <<= static_cast<sal_Int32>(GetLineHeight());
+        xProps->setPropertyValue(UNO_NAME_SEPARATOR_LINE_RELATIVE_HEIGHT, aVal);
+        aVal <<= GetLineAdj() != COLADJ_NONE;
+        xProps->setPropertyValue(UNO_NAME_SEPARATOR_LINE_IS_ON, aVal);
+        sal_Int16 nStyle;
+        switch (GetLineStyle())
+        {
+            case SvxBorderLineStyle::SOLID:
+                nStyle = css::text::ColumnSeparatorStyle::SOLID;
+                break;
+            case SvxBorderLineStyle::DOTTED:
+                nStyle = css::text::ColumnSeparatorStyle::DOTTED;
+                break;
+            case SvxBorderLineStyle::DASHED:
+                nStyle = css::text::ColumnSeparatorStyle::DASHED;
+                break;
+            case SvxBorderLineStyle::NONE:
+            default:
+                nStyle = css::text::ColumnSeparatorStyle::NONE;
+                break;
+        }
+        aVal <<= nStyle;
+        xProps->setPropertyValue(UNO_NAME_SEPARATOR_LINE_STYLE, aVal);
+        style::VerticalAlignment eAlignment;
+        switch (GetLineAdj())
+        {
+            case COLADJ_TOP:
+                eAlignment = style::VerticalAlignment_TOP;
+                break;
+            case COLADJ_BOTTOM:
+                eAlignment = style::VerticalAlignment_BOTTOM;
+                break;
+            case COLADJ_CENTER:
+            case COLADJ_NONE:
+            default:
+                eAlignment = style::VerticalAlignment_MIDDLE;
+        }
+        aVal <<= eAlignment;
+        xProps->setPropertyValue(UNO_NAME_SEPARATOR_LINE_VERTIVAL_ALIGNMENT, aVal);
         rVal <<= xCols;
     }
     return true;
@@ -1141,24 +1220,33 @@ bool SwFormatCol::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
             m_nWidth = nWidthSum;
             m_bOrtho = false;

-            auto pSwColums = comphelper::getUnoTunnelImplementation<SwXTextColumns>(xCols);
-            if(pSwColums)
+            if (uno::Reference<beans::XPropertySet> xProps{ xCols, css::uno::UNO_QUERY })
             {
-                m_bOrtho = pSwColums->IsAutomaticWidth();
-                m_nLineWidth = pSwColums->GetSepLineWidth();
-                m_aLineColor = pSwColums->GetSepLineColor();
-                m_nLineHeight = pSwColums->GetSepLineHeightRelative();
-                switch ( pSwColums->GetSepLineStyle() )
+                xProps->getPropertyValue(UNO_NAME_IS_AUTOMATIC) >>= m_bOrtho;
+                xProps->getPropertyValue(UNO_NAME_SEPARATOR_LINE_WIDTH) >>= m_nLineWidth;
+                xProps->getPropertyValue(UNO_NAME_SEPARATOR_LINE_COLOR) >>= m_aLineColor;
+                if (sal_Int32 nHeight;
+                    xProps->getPropertyValue(UNO_NAME_SEPARATOR_LINE_RELATIVE_HEIGHT) >>= nHeight)
+                    m_nLineHeight = nHeight;
+                switch (xProps->getPropertyValue(UNO_NAME_SEPARATOR_LINE_STYLE).get<sal_Int16>())
                 {
                     default:
-                    case 0: m_eLineStyle = SvxBorderLineStyle::NONE; break;
-                    case 1: m_eLineStyle = SvxBorderLineStyle::SOLID; break;
-                    case 2: m_eLineStyle = SvxBorderLineStyle::DOTTED; break;
-                    case 3: m_eLineStyle = SvxBorderLineStyle::DASHED; break;
+                    case css::text::ColumnSeparatorStyle::NONE:
+                        m_eLineStyle = SvxBorderLineStyle::NONE;
+                        break;
+                    case css::text::ColumnSeparatorStyle::SOLID:
+                        m_eLineStyle = SvxBorderLineStyle::SOLID;
+                        break;
+                    case css::text::ColumnSeparatorStyle::DOTTED:
+                        m_eLineStyle = SvxBorderLineStyle::DOTTED;
+                        break;
+                    case css::text::ColumnSeparatorStyle::DASHED:
+                        m_eLineStyle = SvxBorderLineStyle::DASHED;
+                        break;
                 }
-                if(!pSwColums->GetSepLineIsOn())
+                if (!xProps->getPropertyValue(UNO_NAME_SEPARATOR_LINE_IS_ON).get<bool>())
                     m_eAdj = COLADJ_NONE;
-                else switch(pSwColums->GetSepLineVertAlign())
+                else switch (xProps->getPropertyValue(UNO_NAME_SEPARATOR_LINE_VERTIVAL_ALIGNMENT).get<style::VerticalAlignment>())
                 {
                     case style::VerticalAlignment_TOP: m_eAdj = COLADJ_TOP;  break;
                     case style::VerticalAlignment_MIDDLE: m_eAdj = COLADJ_CENTER; break;
diff --git a/sw/source/core/unocore/unocoll.cxx b/sw/source/core/unocore/unocoll.cxx
index a6287cbd714d..65d10d0d96f4 100644
--- a/sw/source/core/unocore/unocoll.cxx
+++ b/sw/source/core/unocore/unocoll.cxx
@@ -35,6 +35,7 @@
 #include <o3tl/safeint.hxx>
 #include <svtools/unoimap.hxx>
 #include <svtools/unoevent.hxx>
+#include <svx/SvxXTextColumns.hxx>
 #include <unotbl.hxx>
 #include <unostyle.hxx>
 #include <unofield.hxx>
@@ -795,7 +796,7 @@ SwXServiceProvider::MakeInstance(SwServiceType nObjectType, SwDoc & rDoc)
             xRet = static_cast<cppu::OWeakObject*>(new SwXNumberingRules(rDoc));
         break;
         case SwServiceType::TextColumns:
-            xRet = static_cast<cppu::OWeakObject*>(new SwXTextColumns);
+            xRet = SvxXTextColumns_createInstance();
         break;
         case SwServiceType::Defaults:
             xRet = static_cast<cppu::OWeakObject*>(new SwXTextDefaults(&rDoc));
diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx
index fc8d3713c4a2..a6877c91ad35 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -681,23 +681,6 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s
                 m_aMapEntriesArr[nPropertyId] = GetFootnotePropertyMap();
             }
             break;
-            case PROPERTY_MAP_TEXT_COLUMS :
-            {
-                static SfxItemPropertyMapEntry const aTextColumns_Impl[] =
-                {
-                    {u"" UNO_NAME_IS_AUTOMATIC, WID_TXTCOL_IS_AUTOMATIC, cppu::UnoType<bool>::get(),PropertyAttribute::READONLY, 0},
-                    {u"" UNO_NAME_AUTOMATIC_DISTANCE, WID_TXTCOL_AUTO_DISTANCE, cppu::UnoType<sal_Int32>::get(),PROPERTY_NONE, 0},
-                    {u"" UNO_NAME_SEPARATOR_LINE_WIDTH, WID_TXTCOL_LINE_WIDTH, cppu::UnoType<sal_Int32>::get(),PROPERTY_NONE, 0},
-                    {u"" UNO_NAME_SEPARATOR_LINE_COLOR, WID_TXTCOL_LINE_COLOR, cppu::UnoType<sal_Int32>::get(),PROPERTY_NONE,    0},
-                    {u"" UNO_NAME_SEPARATOR_LINE_RELATIVE_HEIGHT, WID_TXTCOL_LINE_REL_HGT, cppu::UnoType<sal_Int32>::get(),PROPERTY_NONE,    0},
-                    {u"" UNO_NAME_SEPARATOR_LINE_VERTIVAL_ALIGNMENT, WID_TXTCOL_LINE_ALIGN, cppu::UnoType<css::style::VerticalAlignment>::get(),PROPERTY_NONE,   0},
-                    {u"" UNO_NAME_SEPARATOR_LINE_IS_ON, WID_TXTCOL_LINE_IS_ON, cppu::UnoType<bool>::get(),PROPERTY_NONE,  0},
-                    {u"" UNO_NAME_SEPARATOR_LINE_STYLE, WID_TXTCOL_LINE_STYLE, cppu::UnoType<sal_Int8>::get(),PROPERTY_NONE, 0},
-                    { u"", 0, css::uno::Type(), 0, 0 }
-                };
-                m_aMapEntriesArr[nPropertyId] = aTextColumns_Impl;
-            }
-            break;
             case PROPERTY_MAP_REDLINE :
             {
                 m_aMapEntriesArr[nPropertyId] = GetRedlinePropertyMap();
diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx
index 11508d462912..c6cff3dd7906 100644
--- a/sw/source/core/unocore/unomap1.cxx
+++ b/sw/source/core/unocore/unomap1.cxx
@@ -1274,12 +1274,6 @@ const SfxItemPropertySet*  SwUnoPropertyMapProvider::GetPropertySet( sal_uInt16
                 m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_FOOTNOTE;
             }
             break;
-            case PROPERTY_MAP_TEXT_COLUMS            :
-            {
-                static SfxItemPropertySet aPROPERTY_MAP_TEXT_COLUMS(pEntries);
-                m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_TEXT_COLUMS;
-            }
-            break;
             case PROPERTY_MAP_PARAGRAPH              :
             {
                 static SfxItemPropertySet aPROPERTY_MAP_PARAGRAPH(pEntries);
diff --git a/sw/source/core/unocore/unosett.cxx b/sw/source/core/unocore/unosett.cxx
index b36bc88a7bef..a4394972d889 100644
--- a/sw/source/core/unocore/unosett.cxx
+++ b/sw/source/core/unocore/unosett.cxx
@@ -90,11 +90,6 @@ namespace
         return pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier();
     }
 }
-// Constants for the css::text::ColumnSeparatorStyle
-#define API_COL_LINE_NONE               0
-#define API_COL_LINE_SOLID              1
-#define API_COL_LINE_DOTTED             2
-#define API_COL_LINE_DASHED             3

 #define WID_PREFIX                      0
 #define WID_SUFFIX                      1
@@ -2166,290 +2161,4 @@ SwXChapterNumbering::~SwXChapterNumbering()
 {
 }

-OUString SwXTextColumns::getImplementationName()
-{
-    return "SwXTextColumns";
-}
-
-sal_Bool SwXTextColumns::supportsService(const OUString& rServiceName)
-{
-    return cppu::supportsService(this, rServiceName);
-}
-
-Sequence< OUString > SwXTextColumns::getSupportedServiceNames()
-{
-    Sequence<OUString> aRet { "com.sun.star.text.TextColumns" };
-    return aRet;
-}
-
-SwXTextColumns::SwXTextColumns() :
-    m_nReference(0),
-    m_bIsAutomaticWidth(true),
-    m_nAutoDistance(0),
-    m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_COLUMS)),
-    m_nSepLineWidth(0),
-    m_nSepLineColor(0), //black
-    m_nSepLineHeightRelative(100),//full height
-    m_nSepLineVertAlign(style::VerticalAlignment_MIDDLE),
-    m_bSepLineIsOn(false),
-    m_nSepLineStyle(API_COL_LINE_NONE) // None
-{
-}
-
-SwXTextColumns::SwXTextColumns(const SwFormatCol& rFormatCol) :
-    m_nReference(0),
-    m_aTextColumns(rFormatCol.GetNumCols()),
-    m_bIsAutomaticWidth(rFormatCol.IsOrtho()),
-    m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_COLUMS))
-{
-    const sal_uInt16 nItemGutterWidth = rFormatCol.GetGutterWidth();
-    m_nAutoDistance = m_bIsAutomaticWidth ?
-                        USHRT_MAX == nItemGutterWidth ? DEF_GUTTER_WIDTH : static_cast<sal_Int32>(nItemGutterWidth)
-                        : 0;
-    m_nAutoDistance = convertTwipToMm100(m_nAutoDistance);
-
-    TextColumn* pColumns = m_aTextColumns.getArray();
-    const SwColumns& rCols = rFormatCol.GetColumns();
-    for(sal_Int32 i = 0; i < m_aTextColumns.getLength(); ++i)
-    {
-        const SwColumn* pCol = &rCols[i];
-
-        pColumns[i].Width = pCol->GetWishWidth();
-        m_nReference += pColumns[i].Width;
-        pColumns[i].LeftMargin =    convertTwipToMm100(pCol->GetLeft ());
-        pColumns[i].RightMargin =   convertTwipToMm100(pCol->GetRight());
-    }
-    if(!m_aTextColumns.hasElements())
-        m_nReference = USHRT_MAX;
-
-    m_nSepLineWidth = rFormatCol.GetLineWidth();
-    m_nSepLineColor = rFormatCol.GetLineColor();
-    m_nSepLineHeightRelative = rFormatCol.GetLineHeight();
-    m_bSepLineIsOn = rFormatCol.GetLineAdj() != COLADJ_NONE;
-    sal_Int8 nStyle = API_COL_LINE_NONE;
-    switch (rFormatCol.GetLineStyle())
-    {
-        case SvxBorderLineStyle::SOLID: nStyle = API_COL_LINE_SOLID; break;
-        case SvxBorderLineStyle::DOTTED: nStyle= API_COL_LINE_DOTTED; break;
-        case SvxBorderLineStyle::DASHED: nStyle= API_COL_LINE_DASHED; break;
-        default: break;
-    }
-    m_nSepLineStyle = nStyle;
-    switch(rFormatCol.GetLineAdj())
-    {
-        case COLADJ_TOP:    m_nSepLineVertAlign = style::VerticalAlignment_TOP;   break;
-        case COLADJ_BOTTOM: m_nSepLineVertAlign = style::VerticalAlignment_BOTTOM;    break;
-        case COLADJ_CENTER:
-        case COLADJ_NONE:   m_nSepLineVertAlign = style::VerticalAlignment_MIDDLE;
-    }
-}
-
-SwXTextColumns::~SwXTextColumns()
-{
-}
-
-sal_Int32 SwXTextColumns::getReferenceValue()
-{
-    SolarMutexGuard aGuard;
-    return m_nReference;
-}
-
-sal_Int16 SwXTextColumns::getColumnCount()
-{
-    SolarMutexGuard aGuard;
-    return static_cast< sal_Int16>( m_aTextColumns.getLength() );
-}
-
-void SwXTextColumns::setColumnCount(sal_Int16 nColumns)
-{
-    SolarMutexGuard aGuard;
-    if(nColumns <= 0)
-        throw uno::RuntimeException();
-    m_bIsAutomaticWidth = true;
-    m_aTextColumns.realloc(nColumns);
-    TextColumn* pCols = m_aTextColumns.getArray();
-    m_nReference = USHRT_MAX;
-    sal_Int32 nWidth = m_nReference / nColumns;
-    sal_Int32 nDiff = m_nReference - nWidth * nColumns;
-    sal_Int32 nDist = m_nAutoDistance / 2;
-    for(sal_Int16 i = 0; i < nColumns; i++)
-    {
-        pCols[i].Width = nWidth;
-        pCols[i].LeftMargin = i == 0 ? 0 : nDist;
-        pCols[i].RightMargin = i == nColumns - 1 ? 0 : nDist;
-    }
-    pCols[nColumns - 1].Width += nDiff;
-}
-
-uno::Sequence< TextColumn > SwXTextColumns::getColumns()
-{
-    SolarMutexGuard aGuard;
-    return m_aTextColumns;
-}
-
-void SwXTextColumns::setColumns(const uno::Sequence< TextColumn >& rColumns)
-{
-    SolarMutexGuard aGuard;
-    sal_Int32 nReferenceTemp = std::accumulate(rColumns.begin(), rColumns.end(), sal_Int32(0),
-        [](const sal_Int32 nSum, const TextColumn& rCol) { return nSum + rCol.Width; });
-    m_bIsAutomaticWidth = false;
-    m_nReference = !nReferenceTemp ? USHRT_MAX : nReferenceTemp;
-    m_aTextColumns = rColumns;
-}
-
-uno::Reference< XPropertySetInfo > SwXTextColumns::getPropertySetInfo(  )
-{
-    static uno::Reference< beans::XPropertySetInfo >  aRef = m_pPropSet->getPropertySetInfo();
-    return aRef;
-}
-
-void SwXTextColumns::setPropertyValue( const OUString& rPropertyName, const Any& aValue )
-{
-    const SfxItemPropertySimpleEntry*  pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName );
-    if (!pEntry)
-        throw UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
-    if ( pEntry->nFlags & PropertyAttribute::READONLY)
-        throw PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
-
-    switch(pEntry->nWID)
-    {
-        case WID_TXTCOL_LINE_WIDTH:
-        {
-            sal_Int32 nTmp = 0;
-            aValue >>= nTmp;
-            if(nTmp < 0)
-                throw IllegalArgumentException();
-            m_nSepLineWidth = convertMm100ToTwip(nTmp);
-        }
-        break;
-        case WID_TXTCOL_LINE_COLOR:
-            aValue >>= m_nSepLineColor;
-        break;
-        case WID_TXTCOL_LINE_STYLE:
-        {
-            aValue >>= m_nSepLineStyle;
-        }
-        break;
-        case WID_TXTCOL_LINE_REL_HGT:
-        {
-            sal_Int8 nTmp = 0;
-            aValue >>= nTmp;
-            if(nTmp < 0)
-                throw IllegalArgumentException();
-            m_nSepLineHeightRelative = nTmp;
-        }
-        break;
-        case WID_TXTCOL_LINE_ALIGN:
-        {
-            style::VerticalAlignment eAlign;
-            if(!(aValue >>= eAlign) )
-            {
-                sal_Int8 nTmp = 0;
-                if (! ( aValue >>= nTmp ) )
-                    throw IllegalArgumentException();
-                m_nSepLineVertAlign = static_cast<style::VerticalAlignment>(nTmp);
-            }
-            else
-                m_nSepLineVertAlign = eAlign;
-        }
-        break;
-        case WID_TXTCOL_LINE_IS_ON:
-            m_bSepLineIsOn = *o3tl::doAccess<bool>(aValue);
-        break;
-        case WID_TXTCOL_AUTO_DISTANCE:
-        {
-            sal_Int32 nTmp = 0;
-            aValue >>= nTmp;
-            if(nTmp < 0 || nTmp >= m_nReference)
-                throw IllegalArgumentException();
-            m_nAutoDistance = nTmp;
-            sal_Int32 nColumns = m_aTextColumns.getLength();
-            TextColumn* pCols = m_aTextColumns.getArray();
-            sal_Int32 nDist = m_nAutoDistance / 2;
-            for(sal_Int32 i = 0; i < nColumns; i++)
-            {
-                pCols[i].LeftMargin = i == 0 ? 0 : nDist;
-                pCols[i].RightMargin = i == nColumns - 1 ? 0 : nDist;
-            }
-        }
-        break;
-    }
-}
-
-Any SwXTextColumns::getPropertyValue( const OUString& rPropertyName )
-{
-    const SfxItemPropertySimpleEntry*  pEntry = m_pPropSet->getPropertyMap().getByName( rPropertyName );
-    if (!pEntry)
-        throw UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
-
-    Any aRet;
-    switch(pEntry->nWID)
-    {
-        case WID_TXTCOL_LINE_WIDTH:
-            aRet <<= static_cast < sal_Int32 >(convertTwipToMm100(m_nSepLineWidth));
-        break;
-        case WID_TXTCOL_LINE_COLOR:
-            aRet <<= m_nSepLineColor;
-        break;
-        case WID_TXTCOL_LINE_STYLE:
-            aRet <<= m_nSepLineStyle;
-        break;
-        case WID_TXTCOL_LINE_REL_HGT:
-            aRet <<= m_nSepLineHeightRelative;
-        break;
-        case WID_TXTCOL_LINE_ALIGN:
-            aRet <<= m_nSepLineVertAlign;
-        break;
-        case WID_TXTCOL_LINE_IS_ON:
-            aRet <<= m_bSepLineIsOn;
-        break;
-        case WID_TXTCOL_IS_AUTOMATIC :
-            aRet <<= m_bIsAutomaticWidth;
-        break;
-        case WID_TXTCOL_AUTO_DISTANCE:
-            aRet <<= m_nAutoDistance;
-        break;
-    }
-    return aRet;
-}
-
-void SwXTextColumns::addPropertyChangeListener(
-    const OUString& /*rPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ )
-{
-}
-
-void SwXTextColumns::removePropertyChangeListener(
-    const OUString& /*rPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ )
-{
-}
-
-void SwXTextColumns::addVetoableChangeListener(
-    const OUString& /*rPropertyName*/, const uno::Reference< XVetoableChangeListener >& /*xListener*/ )
-{
-}
-
-void SwXTextColumns::removeVetoableChangeListener(
-    const OUString& /*rPropertyName*/, const uno::Reference< XVetoableChangeListener >& /*xListener*/ )
-{
-}
-
-namespace
-{
-    class theSwXTextColumnsUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextColumnsUnoTunnelId > {};
-}
-
-const uno::Sequence< sal_Int8 > & SwXTextColumns::getUnoTunnelId()
-{
-    return theSwXTextColumnsUnoTunnelId::get().getSeq();
-}
-
-sal_Int64 SAL_CALL SwXTextColumns::getSomething( const uno::Sequence< sal_Int8 >& rId )
-{
-    if( isUnoTunnelId<SwXTextColumns>(rId) )
-    {
-        return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) );
-    }
-    return 0;
-}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/test/source/sheet/xsheetannotationshapesupplier.cxx b/test/source/sheet/xsheetannotationshapesupplier.cxx
index dac446b72b52..fe392fc83494 100644
--- a/test/source/sheet/xsheetannotationshapesupplier.cxx
+++ b/test/source/sheet/xsheetannotationshapesupplier.cxx
@@ -33,7 +33,7 @@ void XSheetAnnotationShapeSupplier::testGetAnnotationShape()
     CPPUNIT_ASSERT_EQUAL_MESSAGE("getAnnotationShape() wrong width",
                                  sal_Int32(11275), xShape->getSize().Width);
     CPPUNIT_ASSERT_EQUAL_MESSAGE("getAnnotationShape() wrong height",
-                                 sal_Int32(1386), xShape->getSize().Height);
+                                 sal_Int32(1387), xShape->getSize().Height);
 }

 }
diff --git a/uitest/uitest/uihelper/guarded.py b/uitest/uitest/uihelper/guarded.py
new file mode 100644
index 000000000000..b75aea332ff3
--- /dev/null
+++ b/uitest/uitest/uihelper/guarded.py
@@ -0,0 +1,51 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+from contextlib import contextmanager
+
+# Calls UITest.close_doc at exit
+@contextmanager
+def load_file(testCase, url):
+    component = testCase.ui_test.load_file(url)
+    try:
+        yield component
+    finally:
+        testCase.ui_test.close_doc()
+
+# Calls UITest.close_doc at exit
+@contextmanager
+def create_doc_in_start_center(testCase, app):
+    testCase.ui_test.create_doc_in_start_center(app)
+    component = testCase.ui_test.get_component()
+    try:
+        yield component
+    finally:
+        testCase.ui_test.close_doc()
+
+# Calls UITest.close_dialog_through_button at exit
+@contextmanager
+def execute_dialog_through_action(testCase, ui_object, action, parameters = None, event_name = "DialogExecute", close_button = "ok"):
+    testCase.ui_test.execute_dialog_through_action(ui_object, action, parameters, event_name)
+    xDialog = testCase.xUITest.getTopFocusWindow()
+    try:
+        yield xDialog
+    finally:
+        testCase.ui_test.close_dialog_through_button(xDialog.getChild(close_button))
+
+# Calls UITest.close_dialog_through_button at exit
+@contextmanager
+def execute_dialog_through_command(testCase, command, printNames=False, close_button = "ok"):
+    testCase.ui_test.execute_dialog_through_command(command, printNames)
+    xDialog = testCase.xUITest.getTopFocusWindow()
+    try:
+        yield xDialog
+    finally:
+        testCase.ui_test.close_dialog_through_button(xDialog.getChild(close_button))
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/xmloff/source/draw/XMLShapePropertySetContext.cxx b/xmloff/source/draw/XMLShapePropertySetContext.cxx
index b8bc00122044..355a67e4fa59 100644
--- a/xmloff/source/draw/XMLShapePropertySetContext.cxx
+++ b/xmloff/source/draw/XMLShapePropertySetContext.cxx
@@ -18,6 +18,7 @@
  */

 #include <XMLShapePropertySetContext.hxx>
+#include <XMLTextColumnsContext.hxx>
 #include <xmloff/xmlimp.hxx>
 #include <xmloff/xmlnumi.hxx>
 #include <xmltabi.hxx>
@@ -80,6 +81,8 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapePropertySetCon
                                                    rProp,
                                                    rProperties );
         break;
+    case CTF_TEXTCOLUMNS:
+        return new XMLTextColumnsContext(GetImport(), nElement, xAttrList, rProp, rProperties);
     }

     return SvXMLPropertySetContext::createFastChildContext( nElement,
diff --git a/xmloff/source/draw/sdpropls.cxx b/xmloff/source/draw/sdpropls.cxx
index 36a24e2f0d84..d358f7ba09d9 100644
--- a/xmloff/source/draw/sdpropls.cxx
+++ b/xmloff/source/draw/sdpropls.cxx
@@ -58,6 +58,7 @@
 #include <XMLClipPropertyHandler.hxx>
 #include <XMLIsPercentagePropertyHandler.hxx>
 #include <XMLPercentOrMeasurePropertyHandler.hxx>
+#include <XMLTextColumnsPropertyHandler.hxx>
 #include <animations.hxx>
 #include <sax/tools/converter.hxx>
 #include <xmlsdtypes.hxx>
@@ -145,6 +146,8 @@ const XMLPropertyMapEntry aXMLSDProperties[] =
     GMAP( "TextWordWrap",                   XML_NAMESPACE_FO,   XML_WRAP_OPTION,            XML_TYPE_WRAP_OPTION, 0 ),
     GMAP( "TextChainNextName",              XML_NAMESPACE_DRAW,   XML_CHAIN_NEXT_NAME,      XML_TYPE_STRING, 0 ),

+    GMAP( "TextColumns",                    XML_NAMESPACE_STYLE, XML_COLUMNS, XML_TYPE_TEXT_COLUMNS|MID_FLAG_ELEMENT_ITEM, CTF_TEXTCOLUMNS ),
+
     // shadow attributes
     GMAP( "Shadow",                         XML_NAMESPACE_DRAW, XML_SHADOW,                 XML_SD_TYPE_VISIBLE_HIDDEN, 0 ),
     GMAP( "ShadowXDistance",                    XML_NAMESPACE_DRAW, XML_SHADOW_OFFSET_X,        XML_TYPE_MEASURE, 0 ),
@@ -1285,6 +1288,9 @@ const XMLPropertyHandler* XMLSdPropHdlFactory::GetPropertyHandler( sal_Int32 nTy
             case XML_SD_TYPE_CELL_ROTATION_ANGLE:
                 pHdl = new XMLSdRotationAngleTypeHdl;
                 break;
+            case XML_TYPE_TEXT_COLUMNS:
+                pHdl = new XMLTextColumnsPropertyHandler;
+                break;
         }

         if(pHdl)
diff --git a/xmloff/source/text/XMLTextColumnsExport.cxx b/xmloff/source/text/XMLTextColumnsExport.cxx
index 13f06fde36e6..017045d5f635 100644
--- a/xmloff/source/text/XMLTextColumnsExport.cxx
+++ b/xmloff/source/text/XMLTextColumnsExport.cxx
@@ -61,6 +61,8 @@ void XMLTextColumnsExport::exportXML( const Any& rAny )
 {
     Reference < XTextColumns > xColumns;
     rAny >>= xColumns;
+    if (!xColumns)
+        return;

     const Sequence < TextColumn > aColumns = xColumns->getColumns();
     sal_Int32 nCount = aColumns.getLength();
diff --git a/xmloff/source/text/txtprhdl.cxx b/xmloff/source/text/txtprhdl.cxx
index 77dbcb1bdd27..e3eb823349b8 100644
--- a/xmloff/source/text/txtprhdl.cxx
+++ b/xmloff/source/text/txtprhdl.cxx
@@ -656,6 +656,9 @@ bool XMLTextColumnsPropertyHandler::equals(
     Reference < XTextColumns > xColumns2;
     r2 >>= xColumns2;

+    if (!xColumns1 || !xColumns2)
+        return (!xColumns1 && !xColumns2);
+
     if( xColumns1->getColumnCount() != xColumns2->getColumnCount() ||
           xColumns1->getReferenceValue() != xColumns2->getReferenceValue() )
         return false;
--
2.26.2

openSUSE Build Service is sponsored by