cui/source/tabpages/page.cxx                                        |   22 
 cui/source/tabpages/paragrph.cxx                                    |   39 
 cui/source/tabpages/tabstpge.cxx                                    |    3 
 editeng/source/editeng/editdbg.cxx                                  |    4 
 editeng/source/editeng/editdoc.cxx                                  |   11 
 editeng/source/editeng/impedit.hxx                                  |    3 
 editeng/source/editeng/impedit2.cxx                                 |    7 
 editeng/source/editeng/impedit3.cxx                                 |   37 
 editeng/source/editeng/impedit4.cxx                                 |    4 
 editeng/source/items/frmitems.cxx                                   |  880 
++++++----
 editeng/source/outliner/outliner.cxx                                |    2 
 editeng/source/rtf/rtfitem.cxx                                      |    4 
 filter/source/msfilter/svdfppt.cxx                                  |    2 
 include/editeng/lrspitem.hxx                                        |   83 
 include/editeng/memberids.h                                         |    2 
 include/editeng/unoprnms.hxx                                        |    2 
 include/editeng/unotext.hxx                                         |    2 
 reportdesign/source/ui/report/ReportController.cxx                  |    9 
 sc/source/core/data/docpool.cxx                                     |    4 
 sc/source/core/data/stlsheet.cxx                                    |    7 
 sc/source/filter/excel/xepage.cxx                                   |    4 
 sc/source/filter/excel/xipage.cxx                                   |    6 
 sc/source/filter/html/htmlimp.cxx                                   |    4 
 sc/source/ui/unoobj/docuno.cxx                                      |    2 
 sc/source/ui/view/preview.cxx                                       |   26 
 sc/source/ui/view/printfun.cxx                                      |    8 
 schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng         |   24 
 sd/source/core/sdpage.cxx                                           |    2 
 sd/source/core/stlpool.cxx                                          |    5 
 sd/source/core/stlsheet.cxx                                         |    8 
 sd/source/filter/xml/sdtransform.cxx                                |    4 
 sd/source/ui/func/fupage.cxx                                        |    8 
 sd/source/ui/func/fuparagr.cxx                                      |    2 
 sd/source/ui/view/drtxtob1.cxx                                      |    7 
 sd/source/ui/view/drviews3.cxx                                      |    9 
 sd/source/ui/view/outlview.cxx                                      |   20 
 svx/source/dialog/hdft.cxx                                          |   20 
 svx/source/dialog/svxruler.cxx                                      |   31 
 svx/source/sidebar/paragraph/ParaPropertyPanel.cxx                  |   11 
 svx/source/sidebar/paragraph/ParaSpacingWindow.cxx                  |    8 
 sw/inc/unoprnms.hxx                                                 |    2 
 sw/qa/extras/layout/layout3.cxx                                     |    4 
 sw/qa/extras/odfexport/data/tdf163913.fodt                          |  131 +
 sw/qa/extras/odfexport/odfexport2.cxx                               |   44 
 sw/qa/extras/uiwriter/uiwriter2.cxx                                 |    4 
 sw/qa/extras/uiwriter/uiwriter7.cxx                                 |   40 
 sw/qa/extras/uiwriter/uiwriter8.cxx                                 |   33 
 sw/qa/extras/ww8import/ww8import.cxx                                |    8 
 sw/source/core/attr/format.cxx                                      |    3 
 sw/source/core/crsr/crstrvl.cxx                                     |    2 
 sw/source/core/doc/DocumentStylePoolManager.cxx                     |   71 
 sw/source/core/doc/docdesc.cxx                                      |    4 
 sw/source/core/doc/docfmt.cxx                                       |    7 
 sw/source/core/doc/fmtcol.cxx                                       |   12 
 sw/source/core/doc/tblrwcl.cxx                                      |   33 
 sw/source/core/doc/textboxhelper.cxx                                |    4 
 sw/source/core/docnode/ndtbl.cxx                                    |    5 
 sw/source/core/edit/autofmt.cxx                                     |   25 
 sw/source/core/edit/edattr.cxx                                      |    2 
 sw/source/core/layout/anchoredobject.cxx                            |    4 
 sw/source/core/layout/colfrm.cxx                                    |   16 
 sw/source/core/layout/fly.cxx                                       |   10 
 sw/source/core/layout/frmtool.cxx                                   |   27 
 sw/source/core/layout/pagedesc.cxx                                  |    4 
 sw/source/core/layout/sectfrm.cxx                                   |    9 
 sw/source/core/objectpositioning/anchoredobjectposition.cxx         |   65 
 sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx   |   16 
 sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx  |   18 
 sw/source/core/objectpositioning/tolayoutanchoredobjectposition.cxx |    9 
 sw/source/core/table/swtable.cxx                                    |    4 
 sw/source/core/text/frmcrsr.cxx                                     |    8 
 sw/source/core/text/frmpaint.cxx                                    |    2 
 sw/source/core/text/itratr.cxx                                      |   20 
 sw/source/core/text/itrcrsr.cxx                                     |   64 
 sw/source/core/text/txtfly.cxx                                      |   12 
 sw/source/core/tox/ToxTabStopTokenHandler.cxx                       |   11 
 sw/source/core/txtnode/ndtxt.cxx                                    |   29 
 sw/source/core/txtnode/thints.cxx                                   |    3 
 sw/source/core/unocore/unomapproperties.hxx                         |    6 
 sw/source/filter/html/css1atr.cxx                                   |   34 
 sw/source/filter/html/htmlatr.cxx                                   |   25 
 sw/source/filter/html/htmlcss1.cxx                                  |    2 
 sw/source/filter/html/htmlctxt.cxx                                  |   21 
 sw/source/filter/html/htmldrawreader.cxx                            |    8 
 sw/source/filter/html/htmlflywriter.cxx                             |    8 
 sw/source/filter/html/htmlform.cxx                                  |    4 
 sw/source/filter/html/htmlplug.cxx                                  |    8 
 sw/source/filter/html/htmltab.cxx                                   |   11 
 sw/source/filter/html/htmltabw.cxx                                  |   20 
 sw/source/filter/html/svxcss1.cxx                                   |   13 
 sw/source/filter/html/swhtml.cxx                                    |   43 
 sw/source/filter/html/wrthtml.cxx                                   |    6 
 sw/source/filter/ww8/docxattributeoutput.cxx                        |   51 
 sw/source/filter/ww8/docxsdrexport.cxx                              |    4 
 sw/source/filter/ww8/docxtableexport.cxx                            |    6 
 sw/source/filter/ww8/rtfattributeoutput.cxx                         |   39 
 sw/source/filter/ww8/rtfexport.cxx                                  |    6 
 sw/source/filter/ww8/writerwordglue.cxx                             |   10 
 sw/source/filter/ww8/wrtw8esh.cxx                                   |    6 
 sw/source/filter/ww8/wrtw8nds.cxx                                   |   18 
 sw/source/filter/ww8/wrtw8sty.cxx                                   |   11 
 sw/source/filter/ww8/wrtww8.cxx                                     |   12 
 sw/source/filter/ww8/ww8atr.cxx                                     |   32 
 sw/source/filter/ww8/ww8graf.cxx                                    |   12 
 sw/source/filter/ww8/ww8par.cxx                                     |    8 
 sw/source/filter/ww8/ww8par2.cxx                                    |    2 
 sw/source/filter/ww8/ww8par3.cxx                                    |    6 
 sw/source/filter/ww8/ww8par6.cxx                                    |   42 
 sw/source/filter/xml/xmlexpit.cxx                                   |   24 
 sw/source/filter/xml/xmlimpit.cxx                                   |    6 
 sw/source/ui/dialog/uiregionsw.cxx                                  |   12 
 sw/source/ui/envelp/envfmt.cxx                                      |    2 
 sw/source/ui/frmdlg/column.cxx                                      |    7 
 sw/source/ui/frmdlg/wrap.cxx                                        |   10 
 sw/source/ui/misc/pggrid.cxx                                        |    2 
 sw/source/uibase/app/appenv.cxx                                     |    4 
 sw/source/uibase/app/applab.cxx                                     |    7 
 sw/source/uibase/app/docstyle.cxx                                   |    6 
 sw/source/uibase/frmdlg/colex.cxx                                   |   12 
 sw/source/uibase/frmdlg/colmgr.cxx                                  |    4 
 sw/source/uibase/frmdlg/frmmgr.cxx                                  |    8 
 sw/source/uibase/shells/drwtxtex.cxx                                |    3 
 sw/source/uibase/shells/tabsh.cxx                                   |   16 
 sw/source/uibase/shells/textsh1.cxx                                 |    6 
 sw/source/uibase/sidebar/WrapPropertyPanel.cxx                      |    7 
 sw/source/uibase/uiview/view2.cxx                                   |    2 
 sw/source/uibase/uiview/viewmdi.cxx                                 |    8 
 sw/source/uibase/uiview/viewtab.cxx                                 |  168 +
 sw/source/uibase/uno/unotxvw.cxx                                    |    2 
 sw/source/uibase/utlui/uitool.cxx                                   |    2 
 sw/source/uibase/wrtsh/delete.cxx                                   |    7 
 vcl/qa/cppunit/pdfexport/data/tdf163913.fodt                        |  147 +
 vcl/qa/cppunit/pdfexport/pdfexport2.cxx                             |   56 
 xmloff/inc/xmlprop.hxx                                              |    2 
 xmloff/source/text/txtprmap.cxx                                     |    9 
 135 files changed, 1981 insertions(+), 1133 deletions(-)

New commits:
commit 7e4f4a0ccd3c56093dec44c7dcdd14c8b34623c3
Author:     Jonathan Clark <[email protected]>
AuthorDate: Mon Nov 18 10:03:13 2024 -0700
Commit:     Jonathan Clark <[email protected]>
CommitDate: Thu Nov 28 22:10:05 2024 +0100

    tdf#163913 Implement font-relative margins
    
    This change adds loext:margin-left and loext:margin-right, which
    implement margins that support font-relative units.
    
    See tdf#36709 for additional details.
    
    Change-Id: I31b0dd2b6f98cb5b02fd4dca3608db6fdee4054c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177473
    Tested-by: Jenkins
    Reviewed-by: Jonathan Clark <[email protected]>

diff --git a/cui/source/tabpages/page.cxx b/cui/source/tabpages/page.cxx
index 809bd672817b..3f13a6bf6324 100644
--- a/cui/source/tabpages/page.cxx
+++ b/cui/source/tabpages/page.cxx
@@ -336,13 +336,13 @@ void SvxPageDescPage::Reset( const SfxItemSet* rSet )
     if ( pItem )
     {
         const SvxLRSpaceItem& rLRSpace = static_cast<const 
SvxLRSpaceItem&>(*pItem);
-        SetMetricValue( *m_xLeftMarginEdit, rLRSpace.GetLeft(), eUnit );
+        SetMetricValue(*m_xLeftMarginEdit, rLRSpace.ResolveLeft({}), eUnit);
         SetMetricValue(*m_xGutterMarginEdit, rLRSpace.GetGutterMargin(), 
eUnit);
         m_aBspWin.SetLeft(
-            static_cast<sal_uInt16>(ConvertLong_Impl( rLRSpace.GetLeft(), 
eUnit )) );
-        SetMetricValue( *m_xRightMarginEdit, rLRSpace.GetRight(), eUnit );
+            static_cast<sal_uInt16>(ConvertLong_Impl(rLRSpace.ResolveLeft({}), 
eUnit)));
+        SetMetricValue(*m_xRightMarginEdit, rLRSpace.ResolveRight({}), eUnit);
         m_aBspWin.SetRight(
-            static_cast<sal_uInt16>(ConvertLong_Impl( rLRSpace.GetRight(), 
eUnit )) );
+            
static_cast<sal_uInt16>(ConvertLong_Impl(rLRSpace.ResolveRight({}), eUnit)));
     }
 
     // adjust margins (top/bottom)
@@ -633,13 +633,15 @@ bool SvxPageDescPage::FillItemSet( SfxItemSet* rSet )
 
     if (m_xLeftMarginEdit->get_value_changed_from_saved())
     {
-        aMargin.SetLeft( static_cast<sal_uInt16>(GetCoreValue( 
*m_xLeftMarginEdit, eUnit )) );
+        aMargin.SetLeft(SvxIndentValue::twips(
+            static_cast<sal_uInt16>(GetCoreValue(*m_xLeftMarginEdit, eUnit))));
         bModified = true;
     }
 
     if (m_xRightMarginEdit->get_value_changed_from_saved())
     {
-        aMargin.SetRight( static_cast<sal_uInt16>(GetCoreValue( 
*m_xRightMarginEdit, eUnit )) );
+        aMargin.SetRight(SvxIndentValue::twips(
+            static_cast<sal_uInt16>(GetCoreValue(*m_xRightMarginEdit, 
eUnit))));
         bModified = true;
     }
 
@@ -1254,8 +1256,8 @@ void SvxPageDescPage::InitHeadFoot_Impl( const 
SfxItemSet& rSet )
             m_aBspWin.SetHdDist( nDist );
             const SvxLRSpaceItem& rLR =
                 rHeaderSet.Get( GetWhich( SID_ATTR_LRSPACE ) );
-            m_aBspWin.SetHdLeft( rLR.GetLeft() );
-            m_aBspWin.SetHdRight( rLR.GetRight() );
+            m_aBspWin.SetHdLeft(rLR.ResolveLeft({}));
+            m_aBspWin.SetHdRight(rLR.ResolveRight({}));
             m_aBspWin.SetHeader( true );
         }
         else
@@ -1309,8 +1311,8 @@ void SvxPageDescPage::InitHeadFoot_Impl( const 
SfxItemSet& rSet )
         m_aBspWin.SetFtDist( nDist );
         const SvxLRSpaceItem& rLR =
             rFooterSet.Get( GetWhich( SID_ATTR_LRSPACE ) );
-        m_aBspWin.SetFtLeft( rLR.GetLeft() );
-        m_aBspWin.SetFtRight( rLR.GetRight() );
+        m_aBspWin.SetFtLeft(rLR.ResolveLeft({}));
+        m_aBspWin.SetFtRight(rLR.ResolveRight({}));
         m_aBspWin.SetFooter( true );
     }
     else
diff --git a/cui/source/tabpages/paragrph.cxx b/cui/source/tabpages/paragrph.cxx
index a8f6150d0dab..ea8b6a4def38 100644
--- a/cui/source/tabpages/paragrph.cxx
+++ b/cui/source/tabpages/paragrph.cxx
@@ -381,12 +381,12 @@ bool SvxStdParagraphTabPage::FillItemSet( SfxItemSet* 
rOutSet )
             }
             else
             {
-                item.SetTextLeft(m_aLeftIndent.GetCoreValue(eUnit));
+                item.SetTextLeft(lcl_GetFontRelativeValue(m_aLeftIndent, 
eUnit));
             }
         }
         else
         {
-            item.SetTextLeft(m_aLeftIndent.GetCoreValue(eUnit));
+            item.SetTextLeft(lcl_GetFontRelativeValue(m_aLeftIndent, eUnit));
         }
         if (!pOld || *static_cast<const SvxTextLeftMarginItem*>(pOld) != item
             || SfxItemState::INVALID == GetItemSet().GetItemState(nWhich))
@@ -417,12 +417,12 @@ bool SvxStdParagraphTabPage::FillItemSet( SfxItemSet* 
rOutSet )
             }
             else
             {
-                item.SetRight(m_aRightIndent.GetCoreValue(eUnit));
+                item.SetRight(lcl_GetFontRelativeValue(m_aRightIndent, eUnit));
             }
         }
         else
         {
-            item.SetRight(m_aRightIndent.GetCoreValue(eUnit));
+            item.SetRight(lcl_GetFontRelativeValue(m_aRightIndent, eUnit));
         }
         if (!pOld || *static_cast<const SvxRightMarginItem*>(pOld) != item
             || SfxItemState::INVALID == GetItemSet().GetItemState(nWhich))
@@ -463,7 +463,7 @@ bool SvxStdParagraphTabPage::FillItemSet( SfxItemSet* 
rOutSet )
             
item.SetTextFirstLineOffset(lcl_GetFontRelativeValue(m_aFLineIndent, eUnit));
         }
         item.SetAutoFirst(m_xAutoCB->get_active());
-        if (item.GetTextFirstLineOffsetValue() < 0)
+        if (item.GetTextFirstLineOffset().m_dValue < 0.0)
         {
             bNullTab = true;
         }
@@ -498,13 +498,13 @@ bool SvxStdParagraphTabPage::FillItemSet( SfxItemSet* 
rOutSet )
                 aMargin.SetTextLeft( rOldItem.GetTextLeft(),
                                     
static_cast<sal_uInt16>(m_aLeftIndent.get_value(FieldUnit::NONE)) );
             else
-                aMargin.SetTextLeft(m_aLeftIndent.GetCoreValue(eUnit));
+                aMargin.SetTextLeft(lcl_GetFontRelativeValue(m_aLeftIndent, 
eUnit));
 
             if ( m_aRightIndent.IsRelative() )
                 aMargin.SetRight( rOldItem.GetRight(),
                                   
static_cast<sal_uInt16>(m_aRightIndent.get_value(FieldUnit::NONE)) );
             else
-                aMargin.SetRight(m_aRightIndent.GetCoreValue(eUnit));
+                aMargin.SetRight(lcl_GetFontRelativeValue(m_aRightIndent, 
eUnit));
 
             if ( m_aFLineIndent.IsRelative() )
                 aMargin.SetTextFirstLineOffset(
@@ -517,12 +517,12 @@ bool SvxStdParagraphTabPage::FillItemSet( SfxItemSet* 
rOutSet )
         }
         else
         {
-            aMargin.SetTextLeft(m_aLeftIndent.GetCoreValue(eUnit));
-            aMargin.SetRight(m_aRightIndent.GetCoreValue(eUnit));
+            aMargin.SetTextLeft(lcl_GetFontRelativeValue(m_aLeftIndent, 
eUnit));
+            aMargin.SetRight(lcl_GetFontRelativeValue(m_aRightIndent, eUnit));
             
aMargin.SetTextFirstLineOffset(lcl_GetFontRelativeValue(m_aFLineIndent, eUnit));
         }
         aMargin.SetAutoFirst(m_xAutoCB->get_active());
-        if ( aMargin.GetTextFirstLineOffsetValue() < 0.0 )
+        if (aMargin.GetTextFirstLineOffset().m_dValue < 0.0)
             bNullTab = true;
 
         if ( !pOld || *static_cast<const SvxLRSpaceItem*>(pOld) != aMargin ||
@@ -642,12 +642,12 @@ void SvxStdParagraphTabPage::Reset( const SfxItemSet* 
rSet )
             {
                 m_aLeftIndent.SetRelative(false);
                 m_aLeftIndent.SetFieldUnit(eFUnit);
-                m_aLeftIndent.SetMetricValue(rOldLeftMargin.GetTextLeft(), 
eUnit);
+                lcl_SetFontRelativeValue(m_aLeftIndent, 
rOldLeftMargin.GetTextLeft(), eUnit);
             }
         }
         else
         {
-            m_aLeftIndent.SetMetricValue(rOldLeftMargin.GetTextLeft(), eUnit);
+            lcl_SetFontRelativeValue(m_aLeftIndent, 
rOldLeftMargin.GetTextLeft(), eUnit);
         }
     }
     else if (m_bSplitLRSpace)
@@ -673,12 +673,12 @@ void SvxStdParagraphTabPage::Reset( const SfxItemSet* 
rSet )
             {
                 m_aRightIndent.SetRelative(false);
                 m_aRightIndent.SetFieldUnit(eFUnit);
-                m_aRightIndent.SetMetricValue(rOldRightMargin.GetRight(), 
eUnit);
+                lcl_SetFontRelativeValue(m_aRightIndent, 
rOldRightMargin.GetRight(), eUnit);
             }
         }
         else
         {
-            m_aRightIndent.SetMetricValue(rOldRightMargin.GetRight(), eUnit);
+            lcl_SetFontRelativeValue(m_aRightIndent, 
rOldRightMargin.GetRight(), eUnit);
         }
     }
     else if (m_bSplitLRSpace)
@@ -743,7 +743,7 @@ void SvxStdParagraphTabPage::Reset( const SfxItemSet* rSet )
             {
                 m_aLeftIndent.SetRelative(false);
                 m_aLeftIndent.SetFieldUnit(eFUnit);
-                m_aLeftIndent.SetMetricValue(rOldItem.GetTextLeft(), eUnit);
+                lcl_SetFontRelativeValue(m_aLeftIndent, 
rOldItem.GetTextLeft(), eUnit);
             }
 
             if ( rOldItem.GetPropRight() != 100 )
@@ -755,7 +755,7 @@ void SvxStdParagraphTabPage::Reset( const SfxItemSet* rSet )
             {
                 m_aRightIndent.SetRelative(false);
                 m_aRightIndent.SetFieldUnit(eFUnit);
-                m_aRightIndent.SetMetricValue(rOldItem.GetRight(), eUnit);
+                lcl_SetFontRelativeValue(m_aRightIndent, rOldItem.GetRight(), 
eUnit);
             }
 
             if ( rOldItem.GetPropTextFirstLineOffset() != 100 )
@@ -777,8 +777,8 @@ void SvxStdParagraphTabPage::Reset( const SfxItemSet* rSet )
             const SvxLRSpaceItem& rSpace =
                 static_cast<const SvxLRSpaceItem&>(rSet->Get( _nWhich ));
 
-            m_aLeftIndent.SetMetricValue(rSpace.GetTextLeft(), eUnit);
-            m_aRightIndent.SetMetricValue(rSpace.GetRight(), eUnit);
+            lcl_SetFontRelativeValue(m_aLeftIndent, rSpace.GetTextLeft(), 
eUnit);
+            lcl_SetFontRelativeValue(m_aRightIndent, rSpace.GetRight(), eUnit);
             lcl_SetFontRelativeValue(m_aFLineIndent, 
rSpace.GetTextFirstLineOffset(), eUnit);
             m_xAutoCB->set_active(rSpace.IsAutoFirst());
         }
@@ -979,6 +979,9 @@ 
SvxStdParagraphTabPage::SvxStdParagraphTabPage(weld::Container* pPage, weld::Dia
     Init_Impl();
     m_aFLineIndent.set_min(-9999, FieldUnit::NONE);    // is set to 0 on 
default
     m_aFLineIndent.EnableFontRelativeMode();
+
+    m_aLeftIndent.EnableFontRelativeMode();
+    m_aRightIndent.EnableFontRelativeMode();
 }
 
 SvxStdParagraphTabPage::~SvxStdParagraphTabPage()
diff --git a/cui/source/tabpages/tabstpge.cxx b/cui/source/tabpages/tabstpge.cxx
index 34b0b631af3a..78e9aec3b739 100644
--- a/cui/source/tabpages/tabstpge.cxx
+++ b/cui/source/tabpages/tabstpge.cxx
@@ -177,7 +177,8 @@ bool SvxTabulatorTabPage::FillItemSet(SfxItemSet* rSet)
             pLRSpace = GetOldItem(*rSet, SID_ATTR_LRSPACE);
 
         if (pLRSpace
-            && static_cast<const 
SvxLRSpaceItem*>(pLRSpace)->GetTextFirstLineOffsetValue() < 0.0)
+            && static_cast<const 
SvxLRSpaceItem*>(pLRSpace)->GetTextFirstLineOffset().m_dValue
+                   < 0.0)
         {
             SvxTabStop aNull(0, SvxTabAdjust::Default);
             aNewTabs->Insert(aNull);
diff --git a/editeng/source/editeng/editdbg.cxx 
b/editeng/source/editeng/editdbg.cxx
index 2b4d3956eefd..d2a9290dae00 100644
--- a/editeng/source/editeng/editdbg.cxx
+++ b/editeng/source/editeng/editdbg.cxx
@@ -71,8 +71,8 @@ struct DebOutBuffer
     {
         str.append(OString::Concat(descr)
                    + "FI=" + 
OString::number(rItem.ResolveTextFirstLineOffset({}))
-                   + ", LI=" + OString::number(rItem.GetTextLeft())
-                   + ", RI=" + OString::number(rItem.GetRight()));
+                   + ", LI=" + OString::number(rItem.ResolveTextLeft({}))
+                   + ", RI=" + OString::number(rItem.ResolveRight({})));
     }
     void append(std::string_view descr, const SvxNumBulletItem& rItem)
     {
diff --git a/editeng/source/editeng/editdoc.cxx 
b/editeng/source/editeng/editdoc.cxx
index 63961daefe27..d0e6d987b424 100644
--- a/editeng/source/editeng/editdoc.cxx
+++ b/editeng/source/editeng/editdoc.cxx
@@ -574,14 +574,19 @@ void ConvertItem( std::unique_ptr<SfxPoolItem>& 
rPoolItem, MapUnit eSourceUnit,
         {
             assert(dynamic_cast<const SvxLRSpaceItem *>(rPoolItem.get()) != 
nullptr);
             SvxLRSpaceItem& rItem = static_cast<SvxLRSpaceItem&>(*rPoolItem);
-            if (rItem.GetTextFirstLineOffsetUnit() == 
css::util::MeasureUnit::TWIP)
+            if (rItem.GetTextFirstLineOffset().m_nUnit == 
css::util::MeasureUnit::TWIP)
             {
                 rItem.SetTextFirstLineOffset(
                     
SvxIndentValue::twips(sal::static_int_cast<short>(OutputDevice::LogicToLogic(
                         rItem.ResolveTextFirstLineOffset({}), eSourceUnit, 
eDestUnit))));
             }
-            rItem.SetTextLeft( OutputDevice::LogicToLogic( 
rItem.GetTextLeft(), eSourceUnit, eDestUnit ) );
-            rItem.SetRight( OutputDevice::LogicToLogic( rItem.GetRight(), 
eSourceUnit, eDestUnit ) );
+            rItem.SetTextLeft(SvxIndentValue::twips(
+                OutputDevice::LogicToLogic(rItem.ResolveTextLeft({}), 
eSourceUnit, eDestUnit)));
+            if (rItem.GetRight().m_nUnit == css::util::MeasureUnit::TWIP)
+            {
+                rItem.SetRight(SvxIndentValue::twips(
+                    OutputDevice::LogicToLogic(rItem.ResolveRight({}), 
eSourceUnit, eDestUnit)));
+            }
         }
         break;
         case EE_PARA_ULSPACE:
diff --git a/editeng/source/editeng/impedit.hxx 
b/editeng/source/editeng/impedit.hxx
index 029ae6a9e223..24d30ba3b559 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -686,7 +686,8 @@ private:
     EditPaM             RemoveText();
 
     bool createLinesForEmptyParagraph(ParaPortion& rParaPortion);
-    tools::Long calculateMaxLineWidth(tools::Long nStartX, SvxLRSpaceItem 
const& rLRItem);
+    tools::Long calculateMaxLineWidth(tools::Long nStartX, SvxLRSpaceItem 
const& rLRItem,
+                                      const SvxFontUnitMetrics& rMetrics);
     bool CreateLines(sal_Int32 nPara, sal_uInt32 nStartPosY);
 
     void                CreateAndInsertEmptyLine(ParaPortion& rParaPortion);
diff --git a/editeng/source/editeng/impedit2.cxx 
b/editeng/source/editeng/impedit2.cxx
index 95ea82178989..4fcf6e142a7a 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -3473,7 +3473,8 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, 
bool bIgnoreExtraSpace
             // width, here not preferred. I general, it is best not leave it
             // to StartPosX, also the right indents have to be taken into
             // account!
-            tools::Long nCurWidth = scaleXSpacingValue(rLRItem.GetTextLeft() + 
nSpaceBeforeAndMinLabelWidth);
+            tools::Long nCurWidth
+                = scaleXSpacingValue(rLRItem.ResolveTextLeft({}) + 
nSpaceBeforeAndMinLabelWidth);
             if ( nLine == 0 )
             {
                 tools::Long nFI = 
scaleXSpacingValue(rLRItem.ResolveTextFirstLineOffset(stMetrics));
@@ -3485,7 +3486,7 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, 
bool bIgnoreExtraSpace
                         nCurWidth = pPortion->GetBulletX();
                 }
             }
-            nCurWidth += scaleXSpacingValue(rLRItem.GetRight());
+            nCurWidth += scaleXSpacingValue(rLRItem.ResolveRight({}));
             nCurWidth += CalcLineWidth(*pPortion, rLine, bIgnoreExtraSpace);
             if ( nCurWidth > nMaxWidth )
             {
@@ -3800,7 +3801,7 @@ Point ImpEditEngine::GetDocPosTopLeft( sal_Int32 
nParagraph )
             const SvxLRSpaceItem& rLRItem = 
GetLRSpaceItem(pPPortion->GetNode());
             sal_Int32 nSpaceBefore = 0;
             GetSpaceBeforeAndMinLabelWidth(pPPortion->GetNode(), 
&nSpaceBefore);
-            short nX = static_cast<short>(rLRItem.GetTextLeft()
+            short nX = static_cast<short>(rLRItem.ResolveTextLeft(stMetrics)
                                           + 
rLRItem.ResolveTextFirstLineOffset(stMetrics)
                                           + nSpaceBefore);
 
diff --git a/editeng/source/editeng/impedit3.cxx 
b/editeng/source/editeng/impedit3.cxx
index b060d35fbc0a..068a6b56aa0f 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -605,18 +605,20 @@ bool 
ImpEditEngine::createLinesForEmptyParagraph(ParaPortion& rParaPortion)
     return FinishCreateLines(rParaPortion);
 }
 
-tools::Long ImpEditEngine::calculateMaxLineWidth(tools::Long nStartX, 
SvxLRSpaceItem const& rLRItem)
+tools::Long ImpEditEngine::calculateMaxLineWidth(tools::Long nStartX, 
SvxLRSpaceItem const& rLRItem,
+                                                 const SvxFontUnitMetrics& 
rMetrics)
 {
     const bool bAutoSize = IsEffectivelyVertical() ? maStatus.AutoPageHeight() 
: maStatus.AutoPageWidth();
     tools::Long nMaxLineWidth = GetColumnWidth(bAutoSize ? maMaxAutoPaperSize 
: maPaperSize);
 
-    nMaxLineWidth -= scaleXSpacingValue(rLRItem.GetRight());
+    nMaxLineWidth -= scaleXSpacingValue(rLRItem.ResolveRight(rMetrics));
     nMaxLineWidth -= nStartX;
 
     // If PaperSize == long_max, one cannot take away any negative
     // first line indent. (Overflow)
     if (nMaxLineWidth < 0 && nStartX < 0)
-        nMaxLineWidth = GetColumnWidth(maPaperSize) - 
scaleXSpacingValue(rLRItem.GetRight());
+        nMaxLineWidth
+            = GetColumnWidth(maPaperSize) - 
scaleXSpacingValue(rLRItem.ResolveRight(rMetrics));
 
     // If still less than 0, it may be just the right edge.
     if (nMaxLineWidth <= 0)
@@ -810,12 +812,13 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
         sal_Int32 nPortionStart = 0;
         sal_Int32 nPortionEnd = 0;
 
-        tools::Long nStartX = scaleXSpacingValue(rLRItem.GetTextLeft() + 
nSpaceBeforeAndMinLabelWidth);
+        auto stMetrics = GetFontUnitMetrics(pNode);
+        tools::Long nStartX
+            = scaleXSpacingValue(rLRItem.ResolveTextLeft(stMetrics) + 
nSpaceBeforeAndMinLabelWidth);
         // Multiline hyperlink may need to know if the next line is bigger.
         tools::Long nStartXNextLine = nStartX;
         if ( nIndex == 0 )
         {
-            auto stMetrics = GetFontUnitMetrics(pNode);
             tools::Long nFI = 
scaleXSpacingValue(rLRItem.ResolveTextFirstLineOffset(stMetrics));
             nStartX += nFI;
 
@@ -827,7 +830,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
 
         nStartX += nStartNextLineAfterMultiLineField;
         nStartNextLineAfterMultiLineField = 0;
-        tools::Long nMaxLineWidth = calculateMaxLineWidth(nStartX, rLRItem);
+        tools::Long nMaxLineWidth = calculateMaxLineWidth(nStartX, rLRItem, 
stMetrics);
 
         // Problem:
         // Since formatting starts a line _before_ the invalid position,
@@ -905,8 +908,9 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
                     }
                 }
                 nXWidth = nMaxRangeWidth;
-                if ( nXWidth )
-                    nMaxLineWidth = nXWidth - nStartX - 
scaleXSpacingValue(rLRItem.GetRight());
+                if (nXWidth)
+                    nMaxLineWidth
+                        = nXWidth - nStartX - 
scaleXSpacingValue(rLRItem.ResolveRight(stMetrics));
                 else
                 {
                     // Try further down in the polygon.
@@ -1002,7 +1006,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, 
sal_uInt32 nStartPosY )
                         if (maStatus.DoStretch() && (fFontScalingX != 1.0))
                             nCurPos = 
basegfx::fround<tools::Long>(double(nCurPos) / std::max(fFontScalingX, 0.01));
 
-                        short nAllSpaceBeforeText = 
short(rLRItem.GetTextLeft());
+                        short nAllSpaceBeforeText = 
short(rLRItem.ResolveTextLeft({}));
                         aCurrentTab.aTabStop = 
pNode->GetContentAttribs().FindTabStop( nCurPos - nAllSpaceBeforeText , 
maEditDoc.GetDefTab() );
                         aCurrentTab.nTabPos = 
tools::Long(aCurrentTab.aTabStop.GetTabPos() + nAllSpaceBeforeText);
                         aCurrentTab.bValid = false;
@@ -1575,7 +1579,9 @@ 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 = GetColumnWidth(maPaperSize) - 
scaleXSpacingValue(rLRItem.GetRight()) - nStartX;
+            tools::Long nMaxLineWidthFix = GetColumnWidth(maPaperSize)
+                                           - 
scaleXSpacingValue(rLRItem.ResolveRight(stMetrics))
+                                           - nStartX;
             if ( aTextSize.Width() < nMaxLineWidthFix )
                 nMaxLineWidth = nMaxLineWidthFix;
         }
@@ -1799,13 +1805,14 @@ void 
ImpEditEngine::CreateAndInsertEmptyLine(ParaPortion& rParaPortion)
     sal_Int32 nSpaceBeforeAndMinLabelWidth = 
GetSpaceBeforeAndMinLabelWidth(rParaPortion.GetNode(), &nSpaceBefore);
     const SvxLRSpaceItem& rLRItem = GetLRSpaceItem(rParaPortion.GetNode());
     const SvxLineSpacingItem& rLSItem = 
rParaPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
-    tools::Long nStartX = scaleXSpacingValue(
-        rLRItem.GetTextLeft() + rLRItem.ResolveTextFirstLineOffset(stMetrics) 
+ nSpaceBefore);
+    tools::Long nStartX
+        = scaleXSpacingValue(rLRItem.ResolveTextLeft(stMetrics)
+                             + rLRItem.ResolveTextFirstLineOffset(stMetrics) + 
nSpaceBefore);
 
     tools::Rectangle aBulletArea { Point(), Point() };
     if ( bLineBreak )
     {
-        nStartX = scaleXSpacingValue(rLRItem.GetTextLeft()
+        nStartX = scaleXSpacingValue(rLRItem.ResolveTextLeft(stMetrics)
                                      + 
rLRItem.ResolveTextFirstLineOffset(stMetrics)
                                      + nSpaceBeforeAndMinLabelWidth);
     }
@@ -1818,7 +1825,7 @@ void ImpEditEngine::CreateAndInsertEmptyLine(ParaPortion& 
rParaPortion)
             rParaPortion.SetBulletX( 0 ); // If Bullet set incorrectly.
         if (rParaPortion.GetBulletX() > nStartX)
         {
-            nStartX = scaleXSpacingValue(rLRItem.GetTextLeft()
+            nStartX = scaleXSpacingValue(rLRItem.ResolveTextLeft(stMetrics)
                                          + 
rLRItem.ResolveTextFirstLineOffset(stMetrics)
                                          + nSpaceBeforeAndMinLabelWidth);
             if (rParaPortion.GetBulletX() > nStartX)
@@ -1848,7 +1855,7 @@ void ImpEditEngine::CreateAndInsertEmptyLine(ParaPortion& 
rParaPortion)
         sal_Int32 nPara = GetParaPortions().GetPos(&rParaPortion);
         SvxAdjust eJustification = GetJustification( nPara );
         tools::Long nMaxLineWidth = GetColumnWidth(maPaperSize);
-        nMaxLineWidth -= scaleXSpacingValue(rLRItem.GetRight());
+        nMaxLineWidth -= scaleXSpacingValue(rLRItem.ResolveRight(stMetrics));
         if ( nMaxLineWidth < 0 )
             nMaxLineWidth = 1;
         if ( eJustification ==  SvxAdjust::Center )
diff --git a/editeng/source/editeng/impedit4.cxx 
b/editeng/source/editeng/impedit4.cxx
index 50d7f6fe9669..e6730a64ef86 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -780,11 +780,11 @@ void ImpEditEngine::WriteItemAsRTF( const SfxPoolItem& 
rItem, SvStream& rOutput,
             nTxtFirst = LogicToTwips( nTxtFirst );
             rOutput.WriteNumberAsString( nTxtFirst );
             rOutput.WriteOString( OOO_STRING_SVTOOLS_RTF_LI );
-            sal_uInt32 nTxtLeft = static_cast< sal_uInt32 >(static_cast<const 
SvxLRSpaceItem&>(rItem).GetTextLeft());
+            sal_uInt32 nTxtLeft = static_cast<const 
SvxLRSpaceItem&>(rItem).ResolveTextLeft({});
             nTxtLeft = static_cast<sal_uInt32>(LogicToTwips( nTxtLeft ));
             rOutput.WriteNumberAsString( nTxtLeft );
             rOutput.WriteOString( OOO_STRING_SVTOOLS_RTF_RI );
-            sal_uInt32 nTxtRight = static_cast<const 
SvxLRSpaceItem&>(rItem).GetRight();
+            sal_uInt32 nTxtRight = static_cast<const 
SvxLRSpaceItem&>(rItem).ResolveRight({});
             nTxtRight = LogicToTwips( nTxtRight);
             rOutput.WriteNumberAsString( nTxtRight );
         }
diff --git a/editeng/source/items/frmitems.cxx 
b/editeng/source/items/frmitems.cxx
index 8b4e10e25c83..924ce4b50ece 100644
--- a/editeng/source/items/frmitems.cxx
+++ b/editeng/source/items/frmitems.cxx
@@ -288,11 +288,124 @@ bool SvxSizeItem::HasMetrics() const
     return true;
 }
 
+double SvxIndentValue::ResolveDouble(const SvxFontUnitMetrics& rMetrics) const
+{
+    if (m_nUnit == css::util::MeasureUnit::TWIP)
+        return m_dValue;
+
+    SAL_WARN_IF(!rMetrics.m_bInitialized, "editeng", "font-relative 
indentation lost");
+
+    switch (m_nUnit)
+    {
+        case css::util::MeasureUnit::FONT_EM:
+            return m_dValue * rMetrics.m_dEmTwips;
+
+        case css::util::MeasureUnit::FONT_CJK_ADVANCE:
+            return m_dValue * rMetrics.m_dIcTwips;
+
+        default:
+            SAL_WARN("editeng", "unhandled type conversion");
+            return 0.0;
+    }
+}
+
+sal_Int32 SvxIndentValue::Resolve(const SvxFontUnitMetrics& rMetrics) const
+{
+    return static_cast<sal_Int32>(std::llround(ResolveDouble(rMetrics)));
+}
+
+sal_Int32 SvxIndentValue::ResolveFixedPart() const
+{
+    if (m_nUnit == css::util::MeasureUnit::TWIP)
+        return Resolve({});
+
+    return 0;
+}
+
+sal_Int32 SvxIndentValue::ResolveVariablePart(const SvxFontUnitMetrics& 
rMetrics) const
+{
+    if (m_nUnit == css::util::MeasureUnit::TWIP)
+        return 0;
+
+    return Resolve(rMetrics);
+}
+
+void SvxIndentValue::ScaleMetrics(tools::Long const nMult, tools::Long const 
nDiv)
+{
+    m_dValue = (m_dValue * static_cast<double>(nMult)) / 
static_cast<double>(nDiv);
+}
+
+size_t SvxIndentValue::hashCode() const
+{
+    std::size_t seed(0);
+    o3tl::hash_combine(seed, m_dValue);
+    o3tl::hash_combine(seed, m_nUnit);
+    return seed;
+}
+
+namespace
+{
+
+boost::property_tree::ptree lcl_IndentValueToJson(const char* aName, 
SvxIndentValue stValue)
+{
+    boost::property_tree::ptree aState;
+
+    switch (stValue.m_nUnit)
+    {
+        case css::util::MeasureUnit::TWIP:
+        {
+            OUString sValue
+                = GetMetricText(stValue.m_dValue, MapUnit::MapTwip, 
MapUnit::MapInch, nullptr);
+            aState.put(aName, sValue);
+            aState.put("unit", "inch");
+        }
+        break;
+
+        case css::util::MeasureUnit::FONT_EM:
+            aState.put(aName, stValue.m_dValue);
+            aState.put("unit", "em");
+            break;
+
+        case css::util::MeasureUnit::FONT_CJK_ADVANCE:
+            aState.put(aName, stValue.m_dValue);
+            aState.put("unit", "ic");
+            break;
+
+        default:
+            SAL_WARN("editeng", "unhandled type conversion");
+            break;
+    }
+
+    return aState;
+}
+
+bool lcl_FillAbsoluteMeasureAny(const SvxIndentValue& rIndent, uno::Any& rVal, 
bool bConvert)
+{
+    if (rIndent.m_nUnit == css::util::MeasureUnit::TWIP)
+    {
+        auto nConvOffset = (bConvert ? convertTwipToMm100(rIndent.m_dValue) : 
rIndent.m_dValue);
+        rVal <<= static_cast<sal_Int32>(std::llround(nConvOffset));
+        return true;
+    }
+
+    return false;
+}
+
+bool lcl_FillRelativeMeasureAny(const SvxIndentValue& rIndent, uno::Any& rVal)
+{
+    if (rIndent.m_nUnit != css::util::MeasureUnit::TWIP)
+    {
+        rVal <<= css::beans::Pair<double, sal_Int16>{ rIndent.m_dValue, 
rIndent.m_nUnit };
+        return true;
+    }
+
+    return false;
+}
+
+}
 
 SvxLRSpaceItem::SvxLRSpaceItem(const sal_uInt16 nId)
     : SfxPoolItem(nId, SfxItemType::SvxLRSpaceItemType)
-    , nLeftMargin(0)
-    , nRightMargin(0)
     , m_nGutterMargin(0)
     , m_nRightGutterMargin(0),
     nPropFirstLineOffset( 100 ),
@@ -304,11 +417,9 @@ SvxLRSpaceItem::SvxLRSpaceItem(const sal_uInt16 nId)
 {
 }
 
-SvxLRSpaceItem::SvxLRSpaceItem(const tools::Long nLeft, const tools::Long 
nRight,
+SvxLRSpaceItem::SvxLRSpaceItem(SvxIndentValue stLeft, SvxIndentValue stRight,
                                SvxIndentValue stOffset, const sal_uInt16 nId)
     : SfxPoolItem(nId, SfxItemType::SvxLRSpaceItemType)
-    , nLeftMargin(nLeft)
-    , nRightMargin(nRight)
     , m_nGutterMargin(0)
     , m_nRightGutterMargin(0)
     , nPropFirstLineOffset(100)
@@ -318,6 +429,8 @@ SvxLRSpaceItem::SvxLRSpaceItem(const tools::Long nLeft, 
const tools::Long nRight
     , bExplicitZeroMarginValRight(false)
     , bExplicitZeroMarginValLeft(false)
 {
+    SetLeft(stLeft);
+    SetRight(stRight);
     SetTextFirstLineOffset(stOffset);
 }
 
@@ -333,9 +446,19 @@ bool SvxLRSpaceItem::QueryValue( uno::Any& rVal, sal_uInt8 
nMemberId ) const
         case 0:
         {
             css::frame::status::LeftRightMarginScale aLRSpace;
-            aLRSpace.Left = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(nLeftMargin) : nLeftMargin);
-            aLRSpace.TextLeft = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(GetTextLeft()) : GetTextLeft());
-            aLRSpace.Right = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(nRightMargin) : nRightMargin);
+
+            auto nLeftTwips = ResolveLeft({});
+            aLRSpace.Left
+                = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(nLeftTwips) : nLeftTwips);
+
+            auto nTextLeftTwips = ResolveTextLeft({});
+            aLRSpace.TextLeft = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(nTextLeftTwips)
+                                                                : 
nTextLeftTwips);
+
+            auto nRightTwips = ResolveRight({});
+            aLRSpace.Right
+                = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(nRightTwips) : nRightTwips);
+
             aLRSpace.ScaleLeft = static_cast<sal_Int16>(nPropLeftMargin);
             aLRSpace.ScaleRight = static_cast<sal_Int16>(nPropRightMargin);
 
@@ -348,15 +471,24 @@ bool SvxLRSpaceItem::QueryValue( uno::Any& rVal, 
sal_uInt8 nMemberId ) const
             break;
         }
         case MID_L_MARGIN:
-            rVal <<= static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(nLeftMargin) : nLeftMargin);
+            bRet = lcl_FillAbsoluteMeasureAny(GetLeft(), rVal, bConvert);
+            break;
+
+        case MID_TXT_LMARGIN:
+            bRet = lcl_FillAbsoluteMeasureAny(GetTextLeft(), rVal, bConvert);
+            break;
+
+        case MID_L_UNIT_MARGIN:
+            bRet = lcl_FillRelativeMeasureAny(GetTextLeft(), rVal);
             break;
 
-        case MID_TXT_LMARGIN :
-            rVal <<= static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(GetTextLeft()) : GetTextLeft());
-        break;
         case MID_R_MARGIN:
-            rVal <<= static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(nRightMargin) : nRightMargin);
+            bRet = lcl_FillAbsoluteMeasureAny(m_stRightMargin, rVal, bConvert);
+            break;
+        case MID_R_UNIT_MARGIN:
+            bRet = lcl_FillRelativeMeasureAny(m_stRightMargin, rVal);
             break;
+
         case MID_L_REL_MARGIN:
             rVal <<= static_cast<sal_Int16>(nPropLeftMargin);
         break;
@@ -365,38 +497,16 @@ bool SvxLRSpaceItem::QueryValue( uno::Any& rVal, 
sal_uInt8 nMemberId ) const
         break;
 
         case MID_FIRST_LINE_INDENT:
-            // MID_FIRST_LINE_INDENT only supports statically-convertible 
measures.
-            // In practice, these are always stored here in twips.
-            if (m_nFirstLineUnit == css::util::MeasureUnit::TWIP)
-            {
-                auto nConvOffset
-                    = (bConvert ? convertTwipToMm100(m_dFirstLineOffset) : 
m_dFirstLineOffset);
-                rVal <<= static_cast<sal_Int32>(std::llround(nConvOffset));
-            }
-            else
-            {
-                bRet = false;
-            }
-        break;
+            bRet = lcl_FillAbsoluteMeasureAny(m_stFirstLineOffset, rVal, 
bConvert);
+            break;
 
         case MID_FIRST_LINE_REL_INDENT:
             rVal <<= static_cast<sal_Int16>(nPropFirstLineOffset);
             break;
 
         case MID_FIRST_LINE_UNIT_INDENT:
-            // MID_FIRST_LINE_UNIT_INDENT is used for any values that must be 
serialized
-            // as a unit-value pair. In practice, this will be limited to 
font-relative
-            // units (e.g. em, ic), and all other units will be pre-converted 
to twips.
-            if (m_nFirstLineUnit != css::util::MeasureUnit::TWIP)
-            {
-                rVal
-                    <<= css::beans::Pair<double, sal_Int16>{ 
m_dFirstLineOffset, m_nFirstLineUnit };
-            }
-            else
-            {
-                bRet = false;
-            }
-        break;
+            bRet = lcl_FillRelativeMeasureAny(m_stFirstLineOffset, rVal);
+            break;
 
         case MID_FIRST_AUTO:
             rVal <<= IsAutoFirst();
@@ -422,8 +532,9 @@ bool SvxLRSpaceItem::PutValue( const uno::Any& rVal, 
sal_uInt8 nMemberId )
     nMemberId &= ~CONVERT_TWIPS;
     sal_Int32 nVal = 0;
     if (nMemberId != 0 && nMemberId != MID_FIRST_AUTO && nMemberId != 
MID_L_REL_MARGIN
-        && nMemberId != MID_R_REL_MARGIN && nMemberId != 
MID_FIRST_LINE_UNIT_INDENT)
-        if(!(rVal >>= nVal))
+        && nMemberId != MID_R_REL_MARGIN && nMemberId != 
MID_FIRST_LINE_UNIT_INDENT
+        && nMemberId != MID_L_UNIT_MARGIN && nMemberId != MID_R_UNIT_MARGIN)
+        if (!(rVal >>= nVal))
             return false;
 
     switch( nMemberId )
@@ -434,9 +545,13 @@ bool SvxLRSpaceItem::PutValue( const uno::Any& rVal, 
sal_uInt8 nMemberId )
             if(!(rVal >>= aLRSpace))
                 return false;
 
-            SetLeft( bConvert ? o3tl::toTwips(aLRSpace.Left, 
o3tl::Length::mm100) : aLRSpace.Left );
-            SetTextLeft( bConvert ? o3tl::toTwips(aLRSpace.TextLeft, 
o3tl::Length::mm100) : aLRSpace.TextLeft );
-            SetRight(bConvert ? o3tl::toTwips(aLRSpace.Right, 
o3tl::Length::mm100) : aLRSpace.Right);
+            SetLeft(SvxIndentValue::twips(
+                bConvert ? o3tl::toTwips(aLRSpace.Left, o3tl::Length::mm100) : 
aLRSpace.Left));
+            SetTextLeft(SvxIndentValue::twips(
+                bConvert ? o3tl::toTwips(aLRSpace.TextLeft, 
o3tl::Length::mm100)
+                         : aLRSpace.TextLeft));
+            SetRight(SvxIndentValue::twips(
+                bConvert ? o3tl::toTwips(aLRSpace.Right, o3tl::Length::mm100) 
: aLRSpace.Right));
             nPropLeftMargin = aLRSpace.ScaleLeft;
             nPropRightMargin = aLRSpace.ScaleRight;
             SetTextFirstLineOffset(SvxIndentValue::twips(
@@ -447,16 +562,44 @@ bool SvxLRSpaceItem::PutValue( const uno::Any& rVal, 
sal_uInt8 nMemberId )
             break;
         }
         case MID_L_MARGIN:
-            SetLeft( bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : 
nVal );
+            SetLeft(
+                SvxIndentValue::twips(bConvert ? o3tl::toTwips(nVal, 
o3tl::Length::mm100) : nVal));
             break;
 
-        case MID_TXT_LMARGIN :
-            SetTextLeft( bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : 
nVal );
-        break;
+        case MID_TXT_LMARGIN:
+            SetTextLeft(
+                SvxIndentValue::twips(bConvert ? o3tl::toTwips(nVal, 
o3tl::Length::mm100) : nVal));
+            break;
+
+        case MID_L_UNIT_MARGIN:
+        {
+            css::beans::Pair<double, sal_Int16> stVal;
+            if (!(rVal >>= stVal))
+            {
+                return false;
+            }
+
+            SetTextLeft(SvxIndentValue{ stVal.First, stVal.Second });
+            break;
+        }
 
         case MID_R_MARGIN:
-            SetRight(bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : 
nVal);
+            SetRight(
+                SvxIndentValue::twips(bConvert ? o3tl::toTwips(nVal, 
o3tl::Length::mm100) : nVal));
             break;
+
+        case MID_R_UNIT_MARGIN:
+        {
+            css::beans::Pair<double, sal_Int16> stVal;
+            if (!(rVal >>= stVal))
+            {
+                return false;
+            }
+
+            SetRight(SvxIndentValue{ stVal.First, stVal.Second });
+            break;
+        }
+
         case MID_L_REL_MARGIN:
         case MID_R_REL_MARGIN:
         {
@@ -472,7 +615,7 @@ bool SvxLRSpaceItem::PutValue( const uno::Any& rVal, 
sal_uInt8 nMemberId )
                 return false;
         }
         break;
-        case MID_FIRST_LINE_INDENT     :
+        case MID_FIRST_LINE_INDENT:
             SetTextFirstLineOffset(
                 SvxIndentValue::twips(bConvert ? o3tl::toTwips(nVal, 
o3tl::Length::mm100) : nVal));
             break;
@@ -514,147 +657,226 @@ void SvxLeftMarginItem::SetLeft(const tools::Long nL, 
const sal_uInt16 nProp)
     m_nPropLeftMargin = nProp;
 }
 
-void SvxLRSpaceItem::SetLeft(const tools::Long nL, const sal_uInt16 nProp)
+void SvxLRSpaceItem::SetLeft(SvxIndentValue stL, const sal_uInt16 nProp)
 {
-    nLeftMargin = (nL * nProp) / 100;
-    SAL_WARN_IF(m_dFirstLineOffset != 0.0, "editeng",
+    SAL_WARN_IF(m_stFirstLineOffset.m_dValue != 0.0, "editeng",
                 "probably call SetTextLeft instead? looks inconsistent 
otherwise");
+
+    m_stLeftMargin = stL;
     nPropLeftMargin = nProp;
+
+    if (nProp != 100)
+    {
+        m_stLeftMargin.m_dValue = (stL.m_dValue * static_cast<double>(nProp)) 
/ 100.0;
+    }
 }
 
-void SvxRightMarginItem::SetRight(const tools::Long nR, const sal_uInt16 nProp)
+SvxIndentValue SvxLRSpaceItem::GetLeft() const { return m_stLeftMargin; }
+
+sal_Int32 SvxLRSpaceItem::ResolveLeft(const SvxFontUnitMetrics& rMetrics) const
+{
+    return m_stLeftMargin.Resolve(rMetrics);
+}
+
+void SvxRightMarginItem::SetRight(SvxIndentValue stR, const sal_uInt16 nProp)
 {
     ASSERT_CHANGE_REFCOUNTED_ITEM;
-    m_nRightMargin = (nR * nProp) / 100;
+
+    m_stRightMargin = stR;
     m_nPropRightMargin = nProp;
+
+    if (nProp != 100)
+    {
+        m_stRightMargin.m_dValue = (stR.m_dValue * static_cast<double>(nProp)) 
/ 100.0;
+    }
 }
 
-void SvxLRSpaceItem::SetRight(const tools::Long nR, const sal_uInt16 nProp)
+SvxIndentValue SvxRightMarginItem::GetRight() const { return m_stRightMargin; }
+
+SvxIndentValue SvxLRSpaceItem::GetRight() const { return m_stRightMargin; }
+
+sal_Int32 SvxRightMarginItem::ResolveRight(const SvxFontUnitMetrics& rMetrics) 
const
 {
-    if (0 == nR)
+    return m_stRightMargin.Resolve(rMetrics);
+}
+
+sal_Int32 SvxLRSpaceItem::ResolveRight(const SvxFontUnitMetrics& rMetrics) 
const
+{
+    return m_stRightMargin.Resolve(rMetrics);
+}
+
+sal_Int32 SvxRightMarginItem::ResolveRightFixedPart() const
+{
+    return m_stRightMargin.ResolveFixedPart();
+}
+
+sal_Int32 SvxRightMarginItem::ResolveRightVariablePart(const 
SvxFontUnitMetrics& rMetrics) const
+{
+    return m_stRightMargin.ResolveVariablePart(rMetrics);
+}
+
+sal_uInt16 SvxRightMarginItem::GetPropRight() const { return 
m_nPropRightMargin; }
+
+void SvxLRSpaceItem::SetRight(SvxIndentValue stR, const sal_uInt16 nProp)
+{
+    if (0.0 == stR.m_dValue)
     {
         SetExplicitZeroMarginValRight(true);
     }
-    nRightMargin = (nR * nProp) / 100;
+
+    m_stRightMargin = stR;
     nPropRightMargin = nProp;
+
+    if (nProp != 100)
+    {
+        m_stRightMargin.m_dValue = (stR.m_dValue * static_cast<double>(nProp)) 
/ 100.0;
+    }
 }
 
 void SvxLRSpaceItem::SetTextFirstLineOffset(SvxIndentValue stValue, sal_uInt16 
nProp)
 {
     // note: left margin contains any negative first line offset - preserve it!
-    if (m_dFirstLineOffset < 0.0)
+    if (m_stFirstLineOffset.m_dValue < 0.0)
     {
-        nLeftMargin -= ResolveTextFirstLineOffset({});
+        m_stLeftMargin
+            = SvxIndentValue::twips(m_stLeftMargin.Resolve({}) - 
ResolveTextFirstLineOffset({}));
     }
 
-    m_dFirstLineOffset = stValue.m_dValue;
-    m_nFirstLineUnit = stValue.m_nUnit;
+    m_stFirstLineOffset = stValue;
     nPropFirstLineOffset = nProp;
 
     if (nProp != 100)
     {
-        m_dFirstLineOffset = (stValue.m_dValue * static_cast<double>(nProp)) / 
100.0;
+        m_stFirstLineOffset.m_dValue = (stValue.m_dValue * 
static_cast<double>(nProp)) / 100.0;
     }
 
-    if (m_dFirstLineOffset < 0.0)
+    if (m_stFirstLineOffset.m_dValue < 0.0)
     {
-        nLeftMargin += ResolveTextFirstLineOffset({});
+        m_stLeftMargin
+            = SvxIndentValue::twips(m_stLeftMargin.Resolve({}) + 
ResolveTextFirstLineOffset({}));
     }
 }
 
-#if 0
-void SvxTextLeftMarginItem::SetLeft(SvxFirstLineIndentItem const& rFirstLine,
-        const tools::Long nL, const sal_uInt16 nProp)
+void SvxTextLeftMarginItem::SetTextLeft(SvxIndentValue stL, const sal_uInt16 
nProp)
 {
-    m_nTextLeftMargin = (nL * nProp) / 100;
+    ASSERT_CHANGE_REFCOUNTED_ITEM;
+
+    m_stTextLeftMargin = stL;
     m_nPropLeftMargin = nProp;
-    // note: text left margin contains any negative first line offset
-    if (rFirstLine.GetTextFirstLineOffset() < 0)
+
+    if (nProp != 100)
     {
-        m_nTextLeftMargin += rFirstLine.GetTextFirstLineOffset();
+        m_stTextLeftMargin.m_dValue = (stL.m_dValue * 
static_cast<double>(nProp)) / 100.0;
     }
 }
-#endif
 
-void SvxTextLeftMarginItem::SetTextLeft(const tools::Long nL, const sal_uInt16 
nProp)
+void SvxLRSpaceItem::SetTextLeft(SvxIndentValue stL, const sal_uInt16 nProp)
 {
-    ASSERT_CHANGE_REFCOUNTED_ITEM;
-    m_nTextLeftMargin = (nL * nProp) / 100;
-    m_nPropLeftMargin = nProp;
-}
-
-void SvxLRSpaceItem::SetTextLeft(const tools::Long nL, const sal_uInt16 nProp)
-{
-    if (0 == nL)
+    if (0.0 == stL.m_dValue)
     {
         SetExplicitZeroMarginValLeft(true);
     }
-    auto const nTxtLeft = (nL * nProp) / 100;
+
+    m_stLeftMargin = stL;
     nPropLeftMargin = nProp;
+
+    if (nProp != 100)
+    {
+        m_stLeftMargin.m_dValue = (stL.m_dValue * static_cast<double>(nProp)) 
/ 100.0;
+    }
+
     // note: left margin contains any negative first line offset
-    if (0.0 > m_dFirstLineOffset)
-        nLeftMargin = nTxtLeft + ResolveTextFirstLineOffset({});
-    else
-        nLeftMargin = nTxtLeft;
+    if (0.0 > m_stFirstLineOffset.m_dValue)
+    {
+        m_stLeftMargin
+            = SvxIndentValue::twips(m_stLeftMargin.Resolve({}) + 
ResolveTextFirstLineOffset({}));
+    }
 }
 
 SvxIndentValue SvxLRSpaceItem::GetTextFirstLineOffset() const
 {
-    return { m_dFirstLineOffset, m_nFirstLineUnit };
+    return m_stFirstLineOffset;
 }
 
-double SvxLRSpaceItem::GetTextFirstLineOffsetValue() const { return 
m_dFirstLineOffset; }
+sal_Int32 SvxLRSpaceItem::ResolveTextFirstLineOffset(const SvxFontUnitMetrics& 
rMetrics) const
+{
+    return m_stFirstLineOffset.Resolve(rMetrics);
+}
 
-sal_Int16 SvxLRSpaceItem::GetTextFirstLineOffsetUnit() const { return 
m_nFirstLineUnit; }
+SvxIndentValue SvxTextLeftMarginItem::GetTextLeft() const { return 
m_stTextLeftMargin; }
 
-double SvxLRSpaceItem::ResolveTextFirstLineOffsetDouble(const 
SvxFontUnitMetrics& rMetrics) const
+sal_Int32 SvxTextLeftMarginItem::ResolveTextLeft(const SvxFontUnitMetrics& 
rMetrics) const
 {
-    if (m_nFirstLineUnit == css::util::MeasureUnit::TWIP)
-        return m_dFirstLineOffset;
+    return m_stTextLeftMargin.Resolve(rMetrics);
+}
 
-    SAL_WARN_IF(!rMetrics.m_bInitialized, "editeng", "font-relative 
indentation lost");
+sal_Int32 SvxTextLeftMarginItem::ResolveLeft(const SvxFirstLineIndentItem& 
rFirstLine,
+                                             const SvxFontUnitMetrics& 
rMetrics) const
+{
+    auto nLeft = m_stTextLeftMargin.Resolve(rMetrics);
 
-    switch (m_nFirstLineUnit)
+    // add any negative first line offset to text left margin to get left
+    auto nFirstLine = rFirstLine.GetTextFirstLineOffset().Resolve(rMetrics);
+    if (nFirstLine < 0)
     {
-        case css::util::MeasureUnit::FONT_EM:
-            return m_dFirstLineOffset * rMetrics.m_dEmTwips;
-
-        case css::util::MeasureUnit::FONT_CJK_ADVANCE:
-            return m_dFirstLineOffset * rMetrics.m_dIcTwips;
-
-        default:
-            SAL_WARN("editeng", "unhandled type conversion");
-            return 0.0;
+        nLeft += nFirstLine;
     }
+
+    return nLeft;
 }
 
-sal_Int32 SvxLRSpaceItem::ResolveTextFirstLineOffset(const SvxFontUnitMetrics& 
rMetrics) const
+sal_Int32
+SvxTextLeftMarginItem::ResolveLeftFixedPart(const SvxFirstLineIndentItem& 
rFirstLine) const
 {
-    return 
static_cast<sal_Int32>(std::llround(ResolveTextFirstLineOffsetDouble(rMetrics)));
+    auto nLeft = m_stTextLeftMargin.ResolveFixedPart();
+
+    // add any negative first line offset to text left margin to get left
+    auto nFirstLine = rFirstLine.GetTextFirstLineOffset().ResolveFixedPart();
+    if (nFirstLine < 0)
+    {
+        nLeft += nFirstLine;
+    }
+
+    return nLeft;
 }
 
-tools::Long SvxTextLeftMarginItem::GetTextLeft() const
+sal_Int32 SvxTextLeftMarginItem::ResolveLeftVariablePart(const 
SvxFirstLineIndentItem& rFirstLine,
+                                                         const 
SvxFontUnitMetrics& rMetrics) const
 {
-    return m_nTextLeftMargin;
+    auto nLeft = m_stTextLeftMargin.ResolveVariablePart(rMetrics);
+
+    // add any negative first line offset to text left margin to get left
+    auto nFirstLine = 
rFirstLine.GetTextFirstLineOffset().ResolveVariablePart(rMetrics);
+    if (nFirstLine < 0)
+    {
+        nLeft += nFirstLine;
+    }
+
+    return nLeft;
 }
 
-tools::Long SvxTextLeftMarginItem::GetLeft(const SvxFirstLineIndentItem& 
rFirstLine,
-                                           const SvxFontUnitMetrics& rMetrics) 
const
+sal_uInt16 SvxTextLeftMarginItem::GetPropLeft() const { return 
m_nPropLeftMargin; }
+
+SvxIndentValue SvxLRSpaceItem::GetTextLeft() const
 {
-    // add any negative first line offset to text left margin to get left
-    if (rFirstLine.GetTextFirstLineOffsetValue() < 0.0)
+    // remove any negative first line offset from left margin to get text-left
+    if (m_stFirstLineOffset.m_dValue < 0.0)
     {
-        auto nFirstLineOffset = 
rFirstLine.ResolveTextFirstLineOffset(rMetrics);
-        return m_nTextLeftMargin + nFirstLineOffset;
+        return SvxIndentValue::twips(m_stLeftMargin.Resolve({}) - 
ResolveTextFirstLineOffset({}));
     }
 
-    return m_nTextLeftMargin;
+    return m_stLeftMargin;
 }
 
-tools::Long SvxLRSpaceItem::GetTextLeft() const
+sal_Int32 SvxLRSpaceItem::ResolveTextLeft(const SvxFontUnitMetrics& rMetrics) 
const
 {
     // remove any negative first line offset from left margin to get text-left
-    return (m_dFirstLineOffset < 0) ? nLeftMargin - 
ResolveTextFirstLineOffset({}) : nLeftMargin;
+    if (m_stFirstLineOffset.m_dValue < 0.0)
+    {
+        return m_stLeftMargin.Resolve(rMetrics) - 
ResolveTextFirstLineOffset(rMetrics);
+    }
+
+    return m_stLeftMargin.Resolve(rMetrics);
 }
 
 SvxLeftMarginItem::SvxLeftMarginItem(const sal_uInt16 nId)
@@ -830,15 +1052,15 @@ SvxTextLeftMarginItem::SvxTextLeftMarginItem(const 
sal_uInt16 nId)
 {
 }
 
-SvxTextLeftMarginItem::SvxTextLeftMarginItem(const tools::Long nLeft, const 
sal_uInt16 nId)
+SvxTextLeftMarginItem::SvxTextLeftMarginItem(SvxIndentValue stLeft, const 
sal_uInt16 nId)
     : SfxPoolItem(nId, SfxItemType::SvxTextLeftMarginItemType)
-    , m_nTextLeftMargin(nLeft)
 {
+    SetTextLeft(stLeft);
 }
 
 bool SvxTextLeftMarginItem::QueryValue(uno::Any& rVal, sal_uInt8 nMemberId) 
const
 {
-    bool bRet = true;
+    bool bRet = false;
     bool bConvert = 0 != (nMemberId & CONVERT_TWIPS);
     nMemberId &= ~CONVERT_TWIPS;
     switch (nMemberId)
@@ -847,17 +1069,25 @@ bool SvxTextLeftMarginItem::QueryValue(uno::Any& rVal, 
sal_uInt8 nMemberId) cons
         case 0:
         {
             css::frame::status::LeftRightMarginScale aLRSpace;
-            aLRSpace.TextLeft = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(GetTextLeft()) : GetTextLeft());
+
+            auto nLeftTwips = m_stTextLeftMargin.Resolve({});
+            aLRSpace.TextLeft
+                = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(nLeftTwips) : nLeftTwips);
             aLRSpace.ScaleLeft = static_cast<sal_Int16>(m_nPropLeftMargin);
             rVal <<= aLRSpace;
+            bRet = true;
             break;
         }
         case MID_TXT_LMARGIN :
-            rVal <<= static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(GetTextLeft()) : GetTextLeft());
-        break;
+            bRet = lcl_FillAbsoluteMeasureAny(m_stTextLeftMargin, rVal, 
bConvert);
+            break;
         case MID_L_REL_MARGIN:
             rVal <<= static_cast<sal_Int16>(m_nPropLeftMargin);
-        break;
+            bRet = true;
+            break;
+        case MID_L_UNIT_MARGIN:
+            bRet = lcl_FillRelativeMeasureAny(m_stTextLeftMargin, rVal);
+            break;
         default:
             assert(false);
             bRet = false;
@@ -882,9 +1112,10 @@ bool SvxTextLeftMarginItem::PutValue(const uno::Any& 
rVal, sal_uInt8 nMemberId)
             {
                 return false;
             }
-            SetTextLeft(bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : 
nVal);
+            SetTextLeft(
+                SvxIndentValue::twips(bConvert ? o3tl::toTwips(nVal, 
o3tl::Length::mm100) : nVal));
+            break;
         }
-        break;
         case MID_L_REL_MARGIN:
         {
             sal_Int32 nRel = 0;
@@ -896,8 +1127,19 @@ bool SvxTextLeftMarginItem::PutValue(const uno::Any& 
rVal, sal_uInt8 nMemberId)
             {
                 return false;
             }
+            break;
+        }
+        case MID_L_UNIT_MARGIN:
+        {
+            css::beans::Pair<double, sal_Int16> stVal;
+            if (!(rVal >>= stVal))
+            {
+                return false;
+            }
+
+            SetTextLeft(SvxIndentValue{ stVal.First, stVal.Second });
+            break;
         }
-        break;
         default:
             assert(false);
             OSL_FAIL("unknown MemberId");
@@ -912,14 +1154,14 @@ bool SvxTextLeftMarginItem::operator==(const 
SfxPoolItem& rAttr) const
 
     const SvxTextLeftMarginItem& rOther = static_cast<const 
SvxTextLeftMarginItem&>(rAttr);
 
-    return (m_nTextLeftMargin == rOther.GetTextLeft()
-        && m_nPropLeftMargin == rOther.GetPropLeft());
+    return std::tie(m_stTextLeftMargin, m_nPropLeftMargin)
+           == std::tie(rOther.m_stTextLeftMargin, rOther.m_nPropLeftMargin);
 }
 
 size_t SvxTextLeftMarginItem::hashCode() const
 {
     std::size_t seed(0);
-    o3tl::hash_combine(seed, m_nTextLeftMargin);
+    o3tl::hash_combine(seed, m_stTextLeftMargin.hashCode());
     o3tl::hash_combine(seed, m_nPropLeftMargin);
     return seed;
 }
@@ -947,10 +1189,16 @@ bool SvxTextLeftMarginItem::GetPresentation
                 rText = unicode::formatPercent(m_nPropLeftMargin,
                     Application::GetSettings().GetUILanguageTag());
             }
+            else if (m_stTextLeftMargin.m_nUnit != 
css::util::MeasureUnit::TWIP)
+            {
+                OUStringBuffer stBuf;
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stTextLeftMargin.m_dValue,
+                                                   m_stTextLeftMargin.m_nUnit);
+                rText += stBuf.makeStringAndClear();
+            }
             else
             {
-                rText = GetMetricText(m_nTextLeftMargin,
-                                      eCoreUnit, ePresUnit, &rIntl);
+                rText = GetMetricText(m_stTextLeftMargin.m_dValue, eCoreUnit, 
ePresUnit, &rIntl);
             }
             return true;
         }
@@ -962,9 +1210,16 @@ bool SvxTextLeftMarginItem::GetPresentation
                 rText += unicode::formatPercent(m_nPropLeftMargin,
                     Application::GetSettings().GetUILanguageTag());
             }
+            else if (m_stTextLeftMargin.m_nUnit != 
css::util::MeasureUnit::TWIP)
+            {
+                OUStringBuffer stBuf;
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stTextLeftMargin.m_dValue,
+                                                   m_stTextLeftMargin.m_nUnit);
+                rText += stBuf.makeStringAndClear();
+            }
             else
             {
-                rText += GetMetricText(m_nTextLeftMargin, eCoreUnit, 
ePresUnit, &rIntl)
+                rText += GetMetricText(m_stTextLeftMargin.m_dValue, eCoreUnit, 
ePresUnit, &rIntl)
                     + " " + EditResId(GetMetricId(ePresUnit));
             }
             return true;
@@ -977,7 +1232,7 @@ bool SvxTextLeftMarginItem::GetPresentation
 void SvxTextLeftMarginItem::ScaleMetrics(tools::Long const nMult, tools::Long 
const nDiv)
 {
     ASSERT_CHANGE_REFCOUNTED_ITEM;
-    m_nTextLeftMargin = BigInt::Scale(m_nTextLeftMargin, nMult, nDiv);
+    m_stTextLeftMargin.ScaleMetrics(nMult, nDiv);
 }
 
 bool SvxTextLeftMarginItem::HasMetrics() const
@@ -989,7 +1244,12 @@ void SvxTextLeftMarginItem::dumpAsXml(xmlTextWriterPtr 
pWriter) const
 {
     (void)xmlTextWriterStartElement(pWriter, 
BAD_CAST("SvxTextLeftMarginItem"));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), 
BAD_CAST(OString::number(Which()).getStr()));
-    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nTextLeftMargin"), 
BAD_CAST(OString::number(m_nTextLeftMargin).getStr()));
+    (void)xmlTextWriterWriteAttribute(
+        pWriter, BAD_CAST("m_dTextLeftMargin"),
+        BAD_CAST(OString::number(m_stTextLeftMargin.m_dValue).getStr()));
+    (void)xmlTextWriterWriteAttribute(
+        pWriter, BAD_CAST("m_nUnit"),
+        BAD_CAST(OString::number(m_stTextLeftMargin.m_nUnit).getStr()));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nPropLeftMargin"), 
BAD_CAST(OString::number(m_nPropLeftMargin).getStr()));
     (void)xmlTextWriterEndElement(pWriter);
 }
@@ -998,16 +1258,7 @@ boost::property_tree::ptree 
SvxTextLeftMarginItem::dumpAsJSON() const
 {
     boost::property_tree::ptree aTree = SfxPoolItem::dumpAsJSON();
 
-    boost::property_tree::ptree aState;
-
-    MapUnit eTargetUnit = MapUnit::MapInch;
-
-    OUString sLeft = GetMetricText(GetTextLeft(),
-                        MapUnit::MapTwip, eTargetUnit, nullptr);
-
-    aState.put("left", sLeft);
-    aState.put("unit", "inch");
-
+    auto aState = lcl_IndentValueToJson("left", m_stTextLeftMargin);
     aTree.push_back(std::make_pair("state", aState));
 
     return aTree;
@@ -1046,51 +1297,24 @@ sal_uInt16 
SvxFirstLineIndentItem::GetPropTextFirstLineOffset() const
 void SvxFirstLineIndentItem::SetTextFirstLineOffset(SvxIndentValue stValue, 
sal_uInt16 nProp)
 {
     ASSERT_CHANGE_REFCOUNTED_ITEM;
-    m_dFirstLineOffset = stValue.m_dValue;
-    m_nUnit = stValue.m_nUnit;
+    m_stFirstLineOffset = stValue;
     m_nPropFirstLineOffset = nProp;
 
     if (nProp != 100)
     {
-        m_dFirstLineOffset = (stValue.m_dValue * static_cast<double>(nProp)) / 
100.0;
+        m_stFirstLineOffset.m_dValue = (stValue.m_dValue * 
static_cast<double>(nProp)) / 100.0;
     }
 }
 
 SvxIndentValue SvxFirstLineIndentItem::GetTextFirstLineOffset() const
 {
-    return { m_dFirstLineOffset, m_nUnit };
-}
-
-double SvxFirstLineIndentItem::GetTextFirstLineOffsetValue() const { return 
m_dFirstLineOffset; }
-
-sal_Int16 SvxFirstLineIndentItem::GetTextFirstLineOffsetUnit() const { return 
m_nUnit; }
-
-double
-SvxFirstLineIndentItem::ResolveTextFirstLineOffsetDouble(const 
SvxFontUnitMetrics& rMetrics) const
-{
-    if(m_nUnit == css::util::MeasureUnit::TWIP)
-        return m_dFirstLineOffset;
-
-    SAL_WARN_IF(!rMetrics.m_bInitialized, "editeng", "font-relative 
indentation lost");
-
-    switch (m_nUnit)
-    {
-        case css::util::MeasureUnit::FONT_EM:
-            return m_dFirstLineOffset * rMetrics.m_dEmTwips;
-
-        case css::util::MeasureUnit::FONT_CJK_ADVANCE:
-            return m_dFirstLineOffset * rMetrics.m_dIcTwips;
-
-        default:
-            SAL_WARN("editeng", "unhandled type conversion");
-            return 0.0;
-    }
+    return m_stFirstLineOffset;
 }
 
 sal_Int32
 SvxFirstLineIndentItem::ResolveTextFirstLineOffset(const SvxFontUnitMetrics& 
rMetrics) const
 {
-    return 
static_cast<sal_Int32>(std::llround(ResolveTextFirstLineOffsetDouble(rMetrics)));
+    return m_stFirstLineOffset.Resolve(rMetrics);
 }
 
 bool SvxFirstLineIndentItem::QueryValue(uno::Any& rVal, sal_uInt8 nMemberId) 
const
@@ -1101,16 +1325,8 @@ bool SvxFirstLineIndentItem::QueryValue(uno::Any& rVal, 
sal_uInt8 nMemberId) con
     switch (nMemberId)
     {
         case MID_FIRST_LINE_INDENT:
-            // MID_FIRST_LINE_INDENT only supports statically-convertible 
measures.
-            // In practice, these are always stored here in twips.
-            if (m_nUnit == css::util::MeasureUnit::TWIP)
-            {
-                auto nConvOffset
-                    = (bConvert ? convertTwipToMm100(m_dFirstLineOffset) : 
m_dFirstLineOffset);
-                rVal <<= static_cast<sal_Int32>(std::llround(nConvOffset));
-                bRet = true;
-            }
-        break;
+            bRet = lcl_FillAbsoluteMeasureAny(m_stFirstLineOffset, rVal, 
bConvert);
+            break;
 
         case MID_FIRST_LINE_REL_INDENT:
             rVal <<= static_cast<sal_Int16>(m_nPropFirstLineOffset);
@@ -1118,15 +1334,8 @@ bool SvxFirstLineIndentItem::QueryValue(uno::Any& rVal, 
sal_uInt8 nMemberId) con
             break;
 
         case MID_FIRST_LINE_UNIT_INDENT:
-            // MID_FIRST_LINE_UNIT_INDENT is used for any values that must be 
serialized
-            // as a unit-value pair. In practice, this will be limited to 
font-relative
-            // units (e.g. em, ic), and all other units will be pre-converted 
to twips.
-            if (m_nUnit != css::util::MeasureUnit::TWIP)
-            {
-                rVal <<= css::beans::Pair<double, sal_Int16>{ 
m_dFirstLineOffset, m_nUnit };
-                bRet = true;
-            }
-        break;
+            bRet = lcl_FillRelativeMeasureAny(m_stFirstLineOffset, rVal);
+            break;
 
         case MID_FIRST_AUTO:
             rVal <<= IsAutoFirst();
@@ -1158,8 +1367,8 @@ bool SvxFirstLineIndentItem::PutValue(const uno::Any& 
rVal, sal_uInt8 nMemberId)
                 return false;
             }
 
-            m_dFirstLineOffset = bConvert ? o3tl::toTwips(nVal, 
o3tl::Length::mm100) : nVal;
-            m_nUnit = css::util::MeasureUnit::TWIP;
+            m_stFirstLineOffset
+                = SvxIndentValue::twips(bConvert ? o3tl::toTwips(nVal, 
o3tl::Length::mm100) : nVal);
             m_nPropFirstLineOffset = 100;
             break;
         }
@@ -1204,16 +1413,15 @@ bool SvxFirstLineIndentItem::operator==(const 
SfxPoolItem& rAttr) const
 
     const SvxFirstLineIndentItem& rOther = static_cast<const 
SvxFirstLineIndentItem&>(rAttr);
 
-    return std::tie(m_dFirstLineOffset, m_nUnit, m_nPropFirstLineOffset, 
m_bAutoFirst)
-           == std::tie(rOther.m_dFirstLineOffset, rOther.m_nUnit, 
rOther.m_nPropFirstLineOffset,
+    return std::tie(m_stFirstLineOffset, m_nPropFirstLineOffset, m_bAutoFirst)
+           == std::tie(rOther.m_stFirstLineOffset, 
rOther.m_nPropFirstLineOffset,
                        rOther.m_bAutoFirst);
 }
 
 size_t SvxFirstLineIndentItem::hashCode() const
 {
     std::size_t seed(0);
-    o3tl::hash_combine(seed, m_dFirstLineOffset);
-    o3tl::hash_combine(seed, m_nUnit);
+    o3tl::hash_combine(seed, m_stFirstLineOffset.hashCode());
     o3tl::hash_combine(seed, m_nPropFirstLineOffset);
     o3tl::hash_combine(seed, m_bAutoFirst);
     return seed;
@@ -1241,15 +1449,16 @@ bool SvxFirstLineIndentItem::GetPresentation
                 rText += unicode::formatPercent(m_nPropFirstLineOffset,
                     Application::GetSettings().GetUILanguageTag());
             }
-            else if (m_nUnit != css::util::MeasureUnit::TWIP)
+            else if (m_stFirstLineOffset.m_nUnit != 
css::util::MeasureUnit::TWIP)
             {
                 OUStringBuffer stBuf;
-                sax::Converter::convertMeasureUnit(stBuf, m_dFirstLineOffset, 
m_nUnit);
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stFirstLineOffset.m_dValue,
+                                                   
m_stFirstLineOffset.m_nUnit);
                 rText += stBuf.makeStringAndClear();
             }
             else
             {
-                rText += GetMetricText(m_dFirstLineOffset, eCoreUnit, 
ePresUnit, &rIntl);
+                rText += GetMetricText(m_stFirstLineOffset.m_dValue, 
eCoreUnit, ePresUnit, &rIntl);
             }
             return true;
         }
@@ -1261,16 +1470,17 @@ bool SvxFirstLineIndentItem::GetPresentation
                 rText += unicode::formatPercent(m_nPropFirstLineOffset,
                             Application::GetSettings().GetUILanguageTag());
             }
-            else if (m_nUnit != css::util::MeasureUnit::TWIP)
+            else if (m_stFirstLineOffset.m_nUnit != 
css::util::MeasureUnit::TWIP)
             {
                 OUStringBuffer stBuf;
-                sax::Converter::convertMeasureUnit(stBuf, m_dFirstLineOffset, 
m_nUnit);
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stFirstLineOffset.m_dValue,
+                                                   
m_stFirstLineOffset.m_nUnit);
                 rText += stBuf.makeStringAndClear();
             }
             else
             {
-                rText += GetMetricText(m_dFirstLineOffset, eCoreUnit, 
ePresUnit, &rIntl) + " "
-                         + EditResId(GetMetricId(ePresUnit));
+                rText += GetMetricText(m_stFirstLineOffset.m_dValue, 
eCoreUnit, ePresUnit, &rIntl)
+                         + " " + EditResId(GetMetricId(ePresUnit));
             }
             return true;
         }
@@ -1282,8 +1492,7 @@ bool SvxFirstLineIndentItem::GetPresentation
 void SvxFirstLineIndentItem::ScaleMetrics(tools::Long const nMult, tools::Long 
const nDiv)
 {
     ASSERT_CHANGE_REFCOUNTED_ITEM;
-    m_dFirstLineOffset
-        = (m_dFirstLineOffset * static_cast<double>(nMult)) / 
static_cast<double>(nDiv);
+    m_stFirstLineOffset.ScaleMetrics(nMult, nDiv);
 }
 
 bool SvxFirstLineIndentItem::HasMetrics() const
@@ -1295,9 +1504,12 @@ void SvxFirstLineIndentItem::dumpAsXml(xmlTextWriterPtr 
pWriter) const
 {
     (void)xmlTextWriterStartElement(pWriter, 
BAD_CAST("SvxFirstLineIndentItem"));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), 
BAD_CAST(OString::number(Which()).getStr()));
-    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_dFirstLineOffset"),
-                                      
BAD_CAST(OString::number(m_dFirstLineOffset).getStr()));
-    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nUnit"), 
BAD_CAST(OString::number(m_nUnit).getStr()));
+    (void)xmlTextWriterWriteAttribute(
+        pWriter, BAD_CAST("m_dFirstLineOffset"),
+        BAD_CAST(OString::number(m_stFirstLineOffset.m_dValue).getStr()));
+    (void)xmlTextWriterWriteAttribute(
+        pWriter, BAD_CAST("m_nUnit"),
+        BAD_CAST(OString::number(m_stFirstLineOffset.m_nUnit).getStr()));
     (void)xmlTextWriterWriteAttribute(pWriter, 
BAD_CAST("m_nPropFirstLineOffset"), 
BAD_CAST(OString::number(m_nPropFirstLineOffset).getStr()));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_bAutoFirst"), 
BAD_CAST(OString::number(int(m_bAutoFirst)).getStr()));
     (void)xmlTextWriterEndElement(pWriter);
@@ -1307,36 +1519,7 @@ boost::property_tree::ptree 
SvxFirstLineIndentItem::dumpAsJSON() const
 {
     boost::property_tree::ptree aTree = SfxPoolItem::dumpAsJSON();
 
-    boost::property_tree::ptree aState;
-
-    switch (m_nUnit)
-    {
-        case css::util::MeasureUnit::TWIP:
-        {
-            MapUnit eTargetUnit = MapUnit::MapInch;
-
-            OUString sFirstline
-                = GetMetricText(m_dFirstLineOffset, MapUnit::MapTwip, 
eTargetUnit, nullptr);
-
-            aState.put("firstline", sFirstline);
-            aState.put("unit", "inch");
-        }
-        break;
-
-        case css::util::MeasureUnit::FONT_EM:
-            aState.put("firstline", m_dFirstLineOffset);
-            aState.put("unit", "em");
-            break;
-
-        case css::util::MeasureUnit::FONT_CJK_ADVANCE:
-            aState.put("firstline", m_dFirstLineOffset);
-            aState.put("unit", "ic");
-            break;
-
-        default:
-            SAL_WARN("editeng", "unhandled type conversion");
-            break;
-    }
+    auto aState = lcl_IndentValueToJson("firstline", m_stFirstLineOffset);
 
     aTree.push_back(std::make_pair("state", aState));
 
@@ -1348,15 +1531,15 @@ SvxRightMarginItem::SvxRightMarginItem(const sal_uInt16 
nId)
 {
 }
 
-SvxRightMarginItem::SvxRightMarginItem(const tools::Long nRight, const 
sal_uInt16 nId)
+SvxRightMarginItem::SvxRightMarginItem(SvxIndentValue stRight, const 
sal_uInt16 nId)
     : SfxPoolItem(nId, SfxItemType::SvxRightMarginItemType)
-    , m_nRightMargin(nRight)
 {
+    SetRight(stRight);
 }
 
 bool SvxRightMarginItem::QueryValue(uno::Any& rVal, sal_uInt8 nMemberId) const
 {
-    bool bRet = true;
+    bool bRet = false;
     bool bConvert = 0 != (nMemberId & CONVERT_TWIPS);
     nMemberId &= ~CONVERT_TWIPS;
     switch (nMemberId)
@@ -1365,17 +1548,25 @@ bool SvxRightMarginItem::QueryValue(uno::Any& rVal, 
sal_uInt8 nMemberId) const
         case 0:
         {
             css::frame::status::LeftRightMarginScale aLRSpace;
-            aLRSpace.Right = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(m_nRightMargin) : m_nRightMargin);
+
+            auto nRightTwips = ResolveRight({});
+            aLRSpace.Right
+                = static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(nRightTwips) : nRightTwips);
             aLRSpace.ScaleRight = static_cast<sal_Int16>(m_nPropRightMargin);
             rVal <<= aLRSpace;
+            bRet = true;
             break;
         }
         case MID_R_MARGIN:
-            rVal <<= static_cast<sal_Int32>(bConvert ? 
convertTwipToMm100(m_nRightMargin) : m_nRightMargin);
+            bRet = lcl_FillAbsoluteMeasureAny(m_stRightMargin, rVal, bConvert);
             break;
         case MID_R_REL_MARGIN:
             rVal <<= static_cast<sal_Int16>(m_nPropRightMargin);
-        break;
+            bRet = true;
+            break;
+        case MID_R_UNIT_MARGIN:
+            bRet = lcl_FillRelativeMeasureAny(m_stRightMargin, rVal);
+            break;
         default:
             assert(false);
             bRet = false;
@@ -1400,7 +1591,8 @@ bool SvxRightMarginItem::PutValue(const uno::Any& rVal, 
sal_uInt8 nMemberId)
             {
                 return false;
             }
-            SetRight(bConvert ? o3tl::toTwips(nVal, o3tl::Length::mm100) : 
nVal);
+            SetRight(
+                SvxIndentValue::twips(bConvert ? o3tl::toTwips(nVal, 
o3tl::Length::mm100) : nVal));
             break;
         }
         case MID_R_REL_MARGIN:
@@ -1414,8 +1606,19 @@ bool SvxRightMarginItem::PutValue(const uno::Any& rVal, 
sal_uInt8 nMemberId)
             {
                 return false;
             }
+            break;
+        }
+        case MID_R_UNIT_MARGIN:
+        {
+            css::beans::Pair<double, sal_Int16> stVal;
+            if (!(rVal >>= stVal))
+            {
+                return false;
+            }
+
+            SetRight(SvxIndentValue{ stVal.First, stVal.Second });
+            break;
         }
-        break;
         default:
             assert(false);
             OSL_FAIL("unknown MemberId");
@@ -1430,14 +1633,14 @@ bool SvxRightMarginItem::operator==(const SfxPoolItem& 
rAttr) const
 
     const SvxRightMarginItem& rOther = static_cast<const 
SvxRightMarginItem&>(rAttr);
 
-    return (m_nRightMargin == rOther.GetRight()
-        && m_nPropRightMargin == rOther.GetPropRight());
+    return std::tie(m_stRightMargin, m_nPropRightMargin)
+           == std::tie(rOther.m_stRightMargin, rOther.m_nPropRightMargin);
 }
 
 size_t SvxRightMarginItem::hashCode() const
 {
     std::size_t seed(0);
-    o3tl::hash_combine(seed, m_nRightMargin);
+    o3tl::hash_combine(seed, m_stRightMargin.hashCode());
     o3tl::hash_combine(seed, m_nPropRightMargin);
     return seed;
 }
@@ -1459,15 +1662,21 @@ bool SvxRightMarginItem::GetPresentation
     {
         case SfxItemPresentation::Nameless:
         {
-            if (100 != m_nRightMargin)
+            if (100 != m_nPropRightMargin)
             {
-                rText += unicode::formatPercent(m_nRightMargin,
-                    Application::GetSettings().GetUILanguageTag());
+                rText += unicode::formatPercent(m_nPropRightMargin,
+                                                
Application::GetSettings().GetUILanguageTag());
+            }
+            else if (m_stRightMargin.m_nUnit != css::util::MeasureUnit::TWIP)
+            {
+                OUStringBuffer stBuf;
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stRightMargin.m_dValue,
+                                                   m_stRightMargin.m_nUnit);
+                rText += stBuf.makeStringAndClear();
             }
             else
             {
-                rText += GetMetricText(m_nRightMargin,
-                                       eCoreUnit, ePresUnit, &rIntl);
+                rText += GetMetricText(m_stRightMargin.m_dValue, eCoreUnit, 
ePresUnit, &rIntl);
             }
             return true;
         }
@@ -1479,11 +1688,17 @@ bool SvxRightMarginItem::GetPresentation
                 rText += unicode::formatPercent(m_nPropRightMargin,
                     Application::GetSettings().GetUILanguageTag());
             }
+            else if (m_stRightMargin.m_nUnit != css::util::MeasureUnit::TWIP)
+            {
+                OUStringBuffer stBuf;
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stRightMargin.m_dValue,
+                                                   m_stRightMargin.m_nUnit);
+                rText += stBuf.makeStringAndClear();
+            }
             else
             {
-                rText += GetMetricText(m_nRightMargin,
-                                       eCoreUnit, ePresUnit, &rIntl)
-                    + " " + EditResId(GetMetricId(ePresUnit));
+                rText += GetMetricText(m_stRightMargin.m_dValue, eCoreUnit, 
ePresUnit, &rIntl) + " "
+                         + EditResId(GetMetricId(ePresUnit));
             }
             return true;
         }
@@ -1495,7 +1710,7 @@ bool SvxRightMarginItem::GetPresentation
 void SvxRightMarginItem::ScaleMetrics(tools::Long const nMult, tools::Long 
const nDiv)
 {
     ASSERT_CHANGE_REFCOUNTED_ITEM;
-    m_nRightMargin = BigInt::Scale(m_nRightMargin, nMult, nDiv);
+    m_stRightMargin.ScaleMetrics(nMult, nDiv);
 }
 
 bool SvxRightMarginItem::HasMetrics() const
@@ -1507,7 +1722,10 @@ void SvxRightMarginItem::dumpAsXml(xmlTextWriterPtr 
pWriter) const
 {
     (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxRightMarginItem"));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), 
BAD_CAST(OString::number(Which()).getStr()));
-    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nRightMargin"), 
BAD_CAST(OString::number(m_nRightMargin).getStr()));
+    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_dRightMargin"),
+                                      
BAD_CAST(OString::number(m_stRightMargin.m_dValue).getStr()));
+    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nUnit"),
+                                      
BAD_CAST(OString::number(m_stRightMargin.m_nUnit).getStr()));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nPropRightMargin"), 
BAD_CAST(OString::number(m_nPropRightMargin).getStr()));
     (void)xmlTextWriterEndElement(pWriter);
 }
@@ -1516,16 +1734,7 @@ boost::property_tree::ptree 
SvxRightMarginItem::dumpAsJSON() const
 {
     boost::property_tree::ptree aTree = SfxPoolItem::dumpAsJSON();
 
-    boost::property_tree::ptree aState;
-
-    MapUnit eTargetUnit = MapUnit::MapInch;
-
-    OUString sRight = GetMetricText(GetRight(),
-                        MapUnit::MapTwip, eTargetUnit, nullptr);
-
-    aState.put("right", sRight);
-    aState.put("unit", "inch");
-
+    auto aState = lcl_IndentValueToJson("right", m_stRightMargin);
     aTree.push_back(std::make_pair("state", aState));
 
     return aTree;
@@ -1753,12 +1962,11 @@ bool SvxLRSpaceItem::operator==( const SfxPoolItem& 
rAttr ) const
 
     const SvxLRSpaceItem& rOther = static_cast<const SvxLRSpaceItem&>(rAttr);
 
-    return std::tie(m_dFirstLineOffset, m_nFirstLineUnit, m_nGutterMargin, 
m_nRightGutterMargin,
-                    nLeftMargin, nRightMargin, nPropFirstLineOffset, 
nPropLeftMargin,
-                    nPropRightMargin, bAutoFirst, bExplicitZeroMarginValRight,
-                    bExplicitZeroMarginValLeft)
-           == std::tie(rOther.m_dFirstLineOffset, rOther.m_nFirstLineUnit, 
rOther.m_nGutterMargin,
-                       rOther.m_nRightGutterMargin, rOther.nLeftMargin, 
rOther.nRightMargin,
+    return std::tie(m_stFirstLineOffset, m_nGutterMargin, 
m_nRightGutterMargin, m_stLeftMargin,
+                    m_stRightMargin, nPropFirstLineOffset, nPropLeftMargin, 
nPropRightMargin,
+                    bAutoFirst, bExplicitZeroMarginValRight, 
bExplicitZeroMarginValLeft)
+           == std::tie(rOther.m_stFirstLineOffset, rOther.m_nGutterMargin,
+                       rOther.m_nRightGutterMargin, rOther.m_stLeftMargin, 
rOther.m_stRightMargin,
                        rOther.nPropFirstLineOffset, rOther.nPropLeftMargin, 
rOther.nPropRightMargin,
                        rOther.bAutoFirst, rOther.bExplicitZeroMarginValRight,
                        rOther.bExplicitZeroMarginValLeft);
@@ -1786,33 +1994,48 @@ bool SvxLRSpaceItem::GetPresentation
                 rText = unicode::formatPercent(nPropLeftMargin,
                     Application::GetSettings().GetUILanguageTag());
             }
+            else if (m_stLeftMargin.m_nUnit != css::util::MeasureUnit::TWIP)
+            {
+                OUStringBuffer stBuf;
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stLeftMargin.m_dValue,
+                                                   m_stLeftMargin.m_nUnit);
+                rText += stBuf.makeStringAndClear();
+            }
             else
-                rText = GetMetricText( nLeftMargin,
-                                       eCoreUnit, ePresUnit, &rIntl );
+                rText = 
GetMetricText(static_cast<tools::Long>(m_stLeftMargin.m_dValue), eCoreUnit,
+                                      ePresUnit, &rIntl);
             rText += cpDelim;
             if ( 100 != nPropFirstLineOffset )
             {
                 rText += unicode::formatPercent(nPropFirstLineOffset,
                     Application::GetSettings().GetUILanguageTag());
             }
-            else if (m_nFirstLineUnit != css::util::MeasureUnit::TWIP)
+            else if (m_stFirstLineOffset.m_nUnit != 
css::util::MeasureUnit::TWIP)
             {
                 OUStringBuffer stBuf;
-                sax::Converter::convertMeasureUnit(stBuf, m_dFirstLineOffset, 
m_nFirstLineUnit);
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stFirstLineOffset.m_dValue,
+                                                   
m_stFirstLineOffset.m_nUnit);
                 rText += stBuf.makeStringAndClear();
             }
             else
-                rText += 
GetMetricText(static_cast<tools::Long>(m_dFirstLineOffset), eCoreUnit,
-                                       ePresUnit, &rIntl);
+                rText += 
GetMetricText(static_cast<tools::Long>(m_stFirstLineOffset.m_dValue),
+                                       eCoreUnit, ePresUnit, &rIntl);
             rText += cpDelim;
-            if ( 100 != nRightMargin )
+            if (100 != nPropRightMargin)
             {
-                rText += unicode::formatPercent(nRightMargin,
-                    Application::GetSettings().GetUILanguageTag());
+                rText += unicode::formatPercent(nPropRightMargin,
+                                                
Application::GetSettings().GetUILanguageTag());
+            }
+            else if (m_stRightMargin.m_nUnit != css::util::MeasureUnit::TWIP)
+            {
+                OUStringBuffer stBuf;
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stRightMargin.m_dValue,
+                                                   m_stRightMargin.m_nUnit);
+                rText += stBuf.makeStringAndClear();
             }
             else
-                rText += GetMetricText( nRightMargin,
-                                        eCoreUnit, ePresUnit, &rIntl );
+                rText += 
GetMetricText(static_cast<tools::Long>(m_stRightMargin.m_dValue),
+                                       eCoreUnit, ePresUnit, &rIntl);
             return true;
         }
         case SfxItemPresentation::Complete:
@@ -1821,41 +2044,59 @@ bool SvxLRSpaceItem::GetPresentation
             if ( 100 != nPropLeftMargin )
                 rText += unicode::formatPercent(nPropLeftMargin,
                     Application::GetSettings().GetUILanguageTag());
+            else if (m_stLeftMargin.m_nUnit != css::util::MeasureUnit::TWIP)
+            {
+                OUStringBuffer stBuf;
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stLeftMargin.m_dValue,
+                                                   m_stLeftMargin.m_nUnit);
+                rText += stBuf.makeStringAndClear();
+            }
             else
             {
-                rText += GetMetricText( nLeftMargin, eCoreUnit, ePresUnit, 
&rIntl ) +
-                        " " + EditResId(GetMetricId(ePresUnit));
+                rText += 
GetMetricText(static_cast<tools::Long>(m_stLeftMargin.m_dValue), eCoreUnit,
+                                       ePresUnit, &rIntl)
+                         + " " + EditResId(GetMetricId(ePresUnit));
             }
             rText += cpDelim;
-            if (100 != nPropFirstLineOffset || m_dFirstLineOffset != 0.0)
+            if (100 != nPropFirstLineOffset || m_stFirstLineOffset.m_dValue != 
0.0)
             {
                 rText += EditResId(RID_SVXITEMS_LRSPACE_FLINE);
                 if ( 100 != nPropFirstLineOffset )
                     rText += unicode::formatPercent(nPropFirstLineOffset,
                                 Application::GetSettings().GetUILanguageTag());
-                else if (m_nFirstLineUnit != css::util::MeasureUnit::TWIP)
+                else if (m_stFirstLineOffset.m_nUnit != 
css::util::MeasureUnit::TWIP)
                 {
                     OUStringBuffer stBuf;
-                    sax::Converter::convertMeasureUnit(stBuf, 
m_dFirstLineOffset, m_nFirstLineUnit);
+                    sax::Converter::convertMeasureUnit(stBuf, 
m_stFirstLineOffset.m_dValue,
+                                                       
m_stFirstLineOffset.m_nUnit);
                     rText += stBuf.makeStringAndClear();
                 }
                 else
                 {
-                    rText += 
GetMetricText(static_cast<tools::Long>(m_dFirstLineOffset), eCoreUnit,
-                                           ePresUnit, &rIntl)
+                    rText += 
GetMetricText(static_cast<tools::Long>(m_stFirstLineOffset.m_dValue),
+                                           eCoreUnit, ePresUnit, &rIntl)
                              + " " + EditResId(GetMetricId(ePresUnit));
                 }
                 rText += cpDelim;
             }
             rText += EditResId(RID_SVXITEMS_LRSPACE_RIGHT);
-            if ( 100 != nPropRightMargin )
+            if (100 != nPropRightMargin)
+            {
                 rText += unicode::formatPercent(nPropRightMargin,
-                    Application::GetSettings().GetUILanguageTag());
+                                                
Application::GetSettings().GetUILanguageTag());
+            }
+            else if (m_stRightMargin.m_nUnit != css::util::MeasureUnit::TWIP)
+            {
+                OUStringBuffer stBuf;
+                sax::Converter::convertMeasureUnit(stBuf, 
m_stRightMargin.m_dValue,
+                                                   m_stRightMargin.m_nUnit);
+                rText += stBuf.makeStringAndClear();
+            }
             else
             {
-                rText += GetMetricText( nRightMargin,
-                                       eCoreUnit, ePresUnit, &rIntl ) +
-                        " " + EditResId(GetMetricId(ePresUnit));
+                rText += 
GetMetricText(static_cast<tools::Long>(m_stRightMargin.m_dValue),
+                                       eCoreUnit, ePresUnit, &rIntl)
+                         + " " + EditResId(GetMetricId(ePresUnit));
             }
             return true;
         }
@@ -1867,10 +2108,9 @@ bool SvxLRSpaceItem::GetPresentation
 
 void SvxLRSpaceItem::ScaleMetrics( tools::Long nMult, tools::Long nDiv )
 {
-    m_dFirstLineOffset
-        = (m_dFirstLineOffset * static_cast<double>(nMult)) / 
static_cast<double>(nDiv);
-    nLeftMargin = BigInt::Scale( nLeftMargin, nMult, nDiv );
-    nRightMargin = BigInt::Scale( nRightMargin, nMult, nDiv );
+    m_stFirstLineOffset.ScaleMetrics(nMult, nDiv);
+    m_stLeftMargin.ScaleMetrics(nMult, nDiv);
+    m_stRightMargin.ScaleMetrics(nMult, nDiv);
 }
 
 
@@ -1884,12 +2124,20 @@ void SvxLRSpaceItem::dumpAsXml(xmlTextWriterPtr 
pWriter) const
 {
     (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SvxLRSpaceItem"));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("whichId"), 
BAD_CAST(OString::number(Which()).getStr()));
-    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_dFirstLineOffset"),
-                                      
BAD_CAST(OString::number(m_dFirstLineOffset).getStr()));
-    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nFirstLineUnit"),
-                                      
BAD_CAST(OString::number(m_nFirstLineUnit).getStr()));
-    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nLeftMargin"), 
BAD_CAST(OString::number(nLeftMargin).getStr()));
-    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("nRightMargin"), 
BAD_CAST(OString::number(nRightMargin).getStr()));
+    (void)xmlTextWriterWriteAttribute(
+        pWriter, BAD_CAST("m_dFirstLineOffset"),
+        BAD_CAST(OString::number(m_stFirstLineOffset.m_dValue).getStr()));
+    (void)xmlTextWriterWriteAttribute(
+        pWriter, BAD_CAST("m_nFirstLineUnit"),
+        BAD_CAST(OString::number(m_stFirstLineOffset.m_nUnit).getStr()));
+    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_dLeftMargin"),
+                                      
BAD_CAST(OString::number(m_stLeftMargin.m_dValue).getStr()));
+    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nLeftMarginUnit"),
+                                      
BAD_CAST(OString::number(m_stLeftMargin.m_nUnit).getStr()));
+    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_dRightMargin"),
+                                      
BAD_CAST(OString::number(m_stRightMargin.m_dValue).getStr()));
+    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nRightMarginUnit"),
+                                      
BAD_CAST(OString::number(m_stRightMargin.m_nUnit).getStr()));
     (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("m_nGutterMargin"),
                                 
BAD_CAST(OString::number(m_nGutterMargin).getStr()));
     (void)xmlTextWriterWriteAttribute(pWriter, 
BAD_CAST("m_nRightGutterMargin"),
@@ -1912,11 +2160,9 @@ boost::property_tree::ptree SvxLRSpaceItem::dumpAsJSON() 
const
 
     MapUnit eTargetUnit = MapUnit::MapInch;
 
-    OUString sLeft = GetMetricText(GetLeft(),
-                        MapUnit::MapTwip, eTargetUnit, nullptr);
+    OUString sLeft = GetMetricText(ResolveLeft({}), MapUnit::MapTwip, 
eTargetUnit, nullptr);
 
-    OUString sRight = GetMetricText(GetRight(),
-                        MapUnit::MapTwip, eTargetUnit, nullptr);
+    OUString sRight = GetMetricText(ResolveRight({}), MapUnit::MapTwip, 
eTargetUnit, nullptr);
 
     OUString sFirstline
         = GetMetricText(ResolveTextFirstLineOffset({}), MapUnit::MapTwip, 
eTargetUnit, nullptr);
diff --git a/editeng/source/outliner/outliner.cxx 
b/editeng/source/outliner/outliner.cxx
index e23ee74ff09f..4ff4c5a46751 100644
--- a/editeng/source/outliner/outliner.cxx
+++ b/editeng/source/outliner/outliner.cxx
@@ -1492,7 +1492,7 @@ tools::Rectangle Outliner::ImpCalcBulletArea( sal_Int32 
nPara, bool bAdjust, boo
         const auto nSpaceBefore = pFmt->GetAbsLSpace() + 
pFmt->GetFirstLineOffset();
 
         const SvxLRSpaceItem& rLR = pEditEngine->GetParaAttrib( nPara, 
bOutlineMode ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE );
-        aTopLeft.setX(rLR.GetTextLeft() + rLR.ResolveTextFirstLineOffset({}) + 
nSpaceBefore);
+        aTopLeft.setX(rLR.ResolveTextLeft({}) + 
rLR.ResolveTextFirstLineOffset({}) + nSpaceBefore);
 
         tools::Long nBulletWidth = std::max(
             static_cast<tools::Long>(-rLR.ResolveTextFirstLineOffset({})),
diff --git a/editeng/source/rtf/rtfitem.cxx b/editeng/source/rtf/rtfitem.cxx
index 129e43ebc33c..17aafa8a558e 100644
--- a/editeng/source/rtf/rtfitem.cxx
+++ b/editeng/source/rtf/rtfitem.cxx
@@ -342,7 +342,7 @@ void SvxRTFParser::ReadAttr( int nToken, SfxItemSet* pSet )
                             CalcValue();
                         nSz = sal_uInt16(nTokenValue);
                     }
-                    aLR.SetTextLeft( nSz );
+                    aLR.SetTextLeft(SvxIndentValue::twips(nSz));
                     pSet->Put( aLR );
                 }
                 break;
@@ -359,7 +359,7 @@ void SvxRTFParser::ReadAttr( int nToken, SfxItemSet* pSet )
                             CalcValue();
                         nSz = sal_uInt16(nTokenValue);
                     }
-                    aLR.SetRight( nSz );
+                    aLR.SetRight(SvxIndentValue::twips(nSz));
                     pSet->Put( aLR );
                 }
                 break;
diff --git a/filter/source/msfilter/svdfppt.cxx 
b/filter/source/msfilter/svdfppt.cxx
index d4bcc197d2e2..8ec7567edb37 100644
--- a/filter/source/msfilter/svdfppt.cxx
+++ b/filter/source/msfilter/svdfppt.cxx
@@ -6187,7 +6187,7 @@ void PPTParagraphObj::ApplyTo( SfxItemSet& rSet,  
std::optional< sal_Int16 >& rS
         auto const nAbsLSpace = convertMasterUnitToMm100(_nTextOfs);
         auto const nFirstLineOffset = nAbsLSpace - 
convertMasterUnitToMm100(_nBulletOfs);
         
aLRSpaceItem.SetTextFirstLineOffset(SvxIndentValue::twips(-nFirstLineOffset));
-        aLRSpaceItem.SetTextLeft( nAbsLSpace );
+        aLRSpaceItem.SetTextLeft(SvxIndentValue::twips(nAbsLSpace));
     }
     rSet.Put( aLRSpaceItem );
 
diff --git a/include/editeng/lrspitem.hxx b/include/editeng/lrspitem.hxx
index c47f9a8f29cf..f5b4d1054056 100644
--- a/include/editeng/lrspitem.hxx
+++ b/include/editeng/lrspitem.hxx
@@ -79,6 +79,16 @@ struct SvxIndentValue
     static SvxIndentValue twips(double dValue) { return { dValue, 
css::util::MeasureUnit::TWIP }; }
 
     static SvxIndentValue zero() { return twips(0.0); }
+
+    double ResolveDouble(const SvxFontUnitMetrics& rMetrics) const;
+    sal_Int32 Resolve(const SvxFontUnitMetrics& rMetrics) const;
+    sal_Int32 ResolveFixedPart() const;
+    sal_Int32 ResolveVariablePart(const SvxFontUnitMetrics& rMetrics) const;
+
+    void ScaleMetrics(tools::Long nMult, tools::Long nDiv);
+
+    size_t hashCode() const;
+    bool operator==(SvxIndentValue const&) const = default;
 };
 
 /// GetLeft() - for everything that's not applied to a paragraph
@@ -127,22 +137,24 @@ class EDITENG_DLLPUBLIC SvxTextLeftMarginItem final : 
public SfxPoolItem
 private:
     friend class SvxFirstLineIndentItem;
     /// left margin including negative first-line indent
-    tools::Long m_nTextLeftMargin = 0;
+    SvxIndentValue m_stTextLeftMargin = SvxIndentValue::zero();
     sal_uInt16 m_nPropLeftMargin = 100;
 
 public:
-    //TODO: need this?
-    //void SetLeft(SvxFirstLineIndentItem const& rFirstLine, const tools::Long 
nL, const sal_uInt16 nProp = 100);
     /// get left margin without negative first-line indent
-    tools::Long GetLeft(const SvxFirstLineIndentItem& rFirstLine,
-                        const SvxFontUnitMetrics& rMetrics) const;
-    sal_uInt16 GetPropLeft() const { return m_nPropLeftMargin; }
+    sal_Int32 ResolveLeft(const SvxFirstLineIndentItem& rFirstLine,
+                          const SvxFontUnitMetrics& rMetrics) const;
+    sal_Int32 ResolveLeftFixedPart(const SvxFirstLineIndentItem& rFirstLine) 
const;
+    sal_Int32 ResolveLeftVariablePart(const SvxFirstLineIndentItem& rFirstLine,
+                                      const SvxFontUnitMetrics& rMetrics) 
const;
+    sal_uInt16 GetPropLeft() const;
 
-    void SetTextLeft(const tools::Long nL, const sal_uInt16 nProp = 100);
-    tools::Long GetTextLeft() const;
+    void SetTextLeft(SvxIndentValue stL, const sal_uInt16 nProp = 100);
+    sal_Int32 ResolveTextLeft(const SvxFontUnitMetrics& rMetrics) const;
+    SvxIndentValue GetTextLeft() const;
 
     explicit SvxTextLeftMarginItem(const sal_uInt16 nId);
-    SvxTextLeftMarginItem(const tools::Long nLeft, const sal_uInt16 nId);
+    SvxTextLeftMarginItem(SvxIndentValue stLeft, const sal_uInt16 nId);
     SvxTextLeftMarginItem(SvxTextLeftMarginItem const &) = default; // 
SfxPoolItem copy function dichotomy
 
     // "pure virtual Methods" from SfxPoolItem
@@ -171,8 +183,7 @@ class EDITENG_DLLPUBLIC SvxFirstLineIndentItem final : 
public SfxPoolItem
 {
 private:
     /// First-line indent always relative to GetTextLeft()
-    double m_dFirstLineOffset = 0.0;
-    sal_Int16 m_nUnit = css::util::MeasureUnit::TWIP;
+    SvxIndentValue m_stFirstLineOffset = SvxIndentValue::zero();
     sal_uInt16 m_nPropFirstLineOffset = 100;
     /// Automatic calculation of the first line indent
     bool m_bAutoFirst = false;
@@ -186,9 +197,6 @@ public:
 
     void SetTextFirstLineOffset(SvxIndentValue stValue, sal_uInt16 nProp = 
100);
     SvxIndentValue GetTextFirstLineOffset() const;
-    double GetTextFirstLineOffsetValue() const;
-    sal_Int16 GetTextFirstLineOffsetUnit() const;
-    double ResolveTextFirstLineOffsetDouble(const SvxFontUnitMetrics& 
rMetrics) const;
     sal_Int32 ResolveTextFirstLineOffset(const SvxFontUnitMetrics& rMetrics) 
const;
 
     explicit SvxFirstLineIndentItem(const sal_uInt16 nId);
@@ -220,20 +228,23 @@ class EDITENG_DLLPUBLIC SvxRightMarginItem final : public 
SfxPoolItem
 {
 private:
     /// right margin: nothing special
-    tools::Long m_nRightMargin = 0;
+    SvxIndentValue m_stRightMargin = SvxIndentValue::zero();
     sal_uInt16 m_nPropRightMargin = 100;
 
 public:
     // The "layout interface":
-    void SetRight(const tools::Long nR, const sal_uInt16 nProp = 100);
+    void SetRight(SvxIndentValue stR, const sal_uInt16 nProp = 100);
 
     // Query/direct setting of the absolute values
-    tools::Long GetRight() const { return m_nRightMargin;}
+    SvxIndentValue GetRight() const;
+    sal_Int32 ResolveRight(const SvxFontUnitMetrics& rMetrics) const;
+    sal_Int32 ResolveRightFixedPart() const;
+    sal_Int32 ResolveRightVariablePart(const SvxFontUnitMetrics& rMetrics) 
const;
 
-    sal_uInt16 GetPropRight() const { return m_nPropRightMargin; }
+    sal_uInt16 GetPropRight() const;
 
     explicit SvxRightMarginItem(const sal_uInt16 nId);
-    SvxRightMarginItem(const tools::Long nRight, const sal_uInt16 nId);
+    SvxRightMarginItem(SvxIndentValue stRight, const sal_uInt16 nId);
     SvxRightMarginItem(SvxRightMarginItem const &) = default; // SfxPoolItem 
copy function dichotomy
 
     // "pure virtual Methods" from SfxPoolItem
@@ -325,10 +336,10 @@ public:
 class EDITENG_DLLPUBLIC SvxLRSpaceItem final : public SfxPoolItem
 {
     /// First-line indent always relative to GetTextLeft()
-    double m_dFirstLineOffset = 0.0;
-    sal_Int16 m_nFirstLineUnit = css::util::MeasureUnit::TWIP;
-    tools::Long    nLeftMargin;        // nLeft or the negative first-line 
indent
-    tools::Long    nRightMargin;       // The unproblematic right edge
+    SvxIndentValue m_stFirstLineOffset = SvxIndentValue::zero();
+    SvxIndentValue m_stLeftMargin
+        = SvxIndentValue::zero(); // nLeft or the negative first-line indent
+    SvxIndentValue m_stRightMargin = SvxIndentValue::zero();
     /// The amount of extra space added to the left margin.
     tools::Long    m_nGutterMargin;
     /// The amount of extra space added to the right margin, on mirrored pages.
@@ -344,7 +355,7 @@ public:
     static SfxPoolItem* CreateDefault();
 
     explicit SvxLRSpaceItem( const sal_uInt16 nId  );
-    SvxLRSpaceItem(const tools::Long nLeft, const tools::Long nRight, 
SvxIndentValue stValue,
+    SvxLRSpaceItem(SvxIndentValue stLeft, SvxIndentValue stRight, 
SvxIndentValue stValue,
                    const sal_uInt16 nId);
     SvxLRSpaceItem(SvxLRSpaceItem const &) = default; // SfxPoolItem copy 
function dichotomy
 
@@ -364,18 +375,14 @@ public:
     virtual bool                 HasMetrics() const override;
 
     // The "layout interface":
-    void   SetLeft (const tools::Long nL, const sal_uInt16 nProp = 100);
-    void   SetRight(const tools::Long nR, const sal_uInt16 nProp = 100);
+    void SetLeft(SvxIndentValue stL, const sal_uInt16 nProp = 100);
+    void SetRight(SvxIndentValue stR, const sal_uInt16 nProp = 100);
 
     // Query/direct setting of the absolute values
-    tools::Long GetLeft()  const { return nLeftMargin; }
-    tools::Long GetRight() const { return nRightMargin;}
-    void SetLeftValue(const tools::Long nL)
-    {
-        assert(m_dFirstLineOffset == 0.0);
-        nLeftMargin = nL;
-    }
-    void SetRightValue( const tools::Long nR ) { nRightMargin = nR; }
+    SvxIndentValue GetLeft() const;
+    sal_Int32 ResolveLeft(const SvxFontUnitMetrics& rMetrics) const;
+    SvxIndentValue GetRight() const;
+    sal_Int32 ResolveRight(const SvxFontUnitMetrics& rMetrics) const;
     bool IsAutoFirst()  const { return bAutoFirst; }
     void SetAutoFirst( const bool bNew ) { bAutoFirst = bNew; }
 
@@ -387,14 +394,12 @@ public:
     sal_uInt16 GetPropRight() const { return nPropRightMargin;}
 
     // The UI/text interface:
-    void SetTextLeft(const tools::Long nL, const sal_uInt16 nProp = 100);
-    tools::Long GetTextLeft() const;
+    void SetTextLeft(SvxIndentValue stL, const sal_uInt16 nProp = 100);
+    SvxIndentValue GetTextLeft() const;
+    sal_Int32 ResolveTextLeft(const SvxFontUnitMetrics& rMetrics) const;
 
     void SetTextFirstLineOffset(SvxIndentValue stValue, sal_uInt16 nProp = 
100);
     SvxIndentValue GetTextFirstLineOffset() const;
-    double GetTextFirstLineOffsetValue() const;
-    sal_Int16 GetTextFirstLineOffsetUnit() const;
-    double ResolveTextFirstLineOffsetDouble(const SvxFontUnitMetrics& 
rMetrics) const;
     sal_Int32 ResolveTextFirstLineOffset(const SvxFontUnitMetrics& rMetrics) 
const;
 
     void SetPropTextFirstLineOffset( const sal_uInt16 nProp )
diff --git a/include/editeng/memberids.h b/include/editeng/memberids.h
index 195eccce41c8..82a1fe65e9bf 100644
--- a/include/editeng/memberids.h
+++ b/include/editeng/memberids.h
@@ -139,6 +139,8 @@
 #define MID_TXT_LMARGIN             11
 #define MID_GUTTER_MARGIN 12
 #define MID_FIRST_LINE_UNIT_INDENT 13
+#define MID_R_UNIT_MARGIN 14
+#define MID_L_UNIT_MARGIN 15
 
 //ProtectItem
 #define MID_PROTECT_CONTENT     0
diff --git a/include/editeng/unoprnms.hxx b/include/editeng/unoprnms.hxx
index 0ba35cbee24a..b42c03bca762 100644
--- a/include/editeng/unoprnms.hxx
+++ b/include/editeng/unoprnms.hxx
@@ -295,8 +295,10 @@ inline constexpr OUString UNO_NAME_EDIT_PARA_ADJUST = 
u"ParaAdjust"_ustr;
 inline constexpr OUString UNO_NAME_EDIT_PARA_BMARGIN = 
u"ParaBottomMargin"_ustr;
 inline constexpr OUString UNO_NAME_EDIT_PARA_LASTLINEADJ = 
u"ParaLastLineAdjust"_ustr;
 inline constexpr OUString UNO_NAME_EDIT_PARA_LMARGIN = u"ParaLeftMargin"_ustr;
+inline constexpr OUString UNO_NAME_EDIT_PARA_LMARGIN_UNIT = 
u"ParaLeftMarginUnit"_ustr;
 inline constexpr OUString UNO_NAME_EDIT_PARA_LINESPACING = 
u"ParaLineSpacing"_ustr;
 inline constexpr OUString UNO_NAME_EDIT_PARA_RMARGIN = u"ParaRightMargin"_ustr;
+inline constexpr OUString UNO_NAME_EDIT_PARA_RMARGIN_UNIT = 
u"ParaRightMarginUnit"_ustr;
 inline constexpr OUString UNO_NAME_EDIT_PARA_TABSTOPS = u"ParaTabStops"_ustr;
 inline constexpr OUString UNO_NAME_EDIT_PARA_TABSTOP_DEFAULT_DISTANCE = 
u"ParaTabStopDefaultDistance"_ustr;
 inline constexpr OUString UNO_NAME_EDIT_PARA_TMARGIN = u"ParaTopMargin"_ustr;
diff --git a/include/editeng/unotext.hxx b/include/editeng/unotext.hxx
index 4011fac9d479..168b9ce063ee 100644
--- a/include/editeng/unotext.hxx
+++ b/include/editeng/unotext.hxx
@@ -148,8 +148,10 @@ struct SfxItemPropertyMapEntry;
     {u"ParaHyphenationNoLastWord"_ustr, EE_PARA_HYPHENATE_NO_LAST_WORD, 
::cppu::UnoType<bool>::get(),       0, 0 }, \
     { UNO_NAME_EDIT_PARA_LASTLINEADJ,  EE_PARA_JUST,               
::cppu::UnoType<sal_Int16>::get(),            0, MID_LAST_LINE_ADJUST }, \
     { UNO_NAME_EDIT_PARA_LMARGIN,      EE_PARA_LRSPACE,    
::cppu::UnoType<sal_Int32>::get(),            0, MID_TXT_LMARGIN, 
PropertyMoreFlags::METRIC_ITEM }, \
+    { UNO_NAME_EDIT_PARA_LMARGIN_UNIT, EE_PARA_LRSPACE, 
::cppu::UnoType<css::beans::Pair<double, sal_Int16>>::get(), 0, 
MID_L_UNIT_MARGIN }, \
     { UNO_NAME_EDIT_PARA_LINESPACING,  EE_PARA_SBL,                
cppu::UnoType<css::style::LineSpacing>::get(),     0, CONVERT_TWIPS}, \
     { UNO_NAME_EDIT_PARA_RMARGIN,      EE_PARA_LRSPACE,    
::cppu::UnoType<sal_Int32>::get(),            0, MID_R_MARGIN, 
PropertyMoreFlags::METRIC_ITEM }, \
+    { UNO_NAME_EDIT_PARA_RMARGIN_UNIT, EE_PARA_LRSPACE, 
::cppu::UnoType<css::beans::Pair<double, sal_Int16>>::get(), 0, 
MID_R_UNIT_MARGIN }, \
     { UNO_NAME_EDIT_PARA_TABSTOPS,     EE_PARA_TABS,               
cppu::UnoType<css::uno::Sequence< css::style::TabStop >>::get(), 0, 0 }, \
     { UNO_NAME_EDIT_PARA_TABSTOP_DEFAULT_DISTANCE, EE_PARA_TABS, 
::cppu::UnoType<sal_Int32>::get(), 0, MID_TABSTOP_DEFAULT_DISTANCE }, \
     { UNO_NAME_EDIT_PARA_TMARGIN,      EE_PARA_ULSPACE,            
::cppu::UnoType<sal_Int32>::get(),            0, MID_UP_MARGIN, 
PropertyMoreFlags::METRIC_ITEM },\
diff --git a/reportdesign/source/ui/report/ReportController.cxx 
b/reportdesign/source/ui/report/ReportController.cxx
index 41914a33ca7a..149b43d5efe2 100644
--- a/reportdesign/source/ui/report/ReportController.cxx
+++ b/reportdesign/source/ui/report/ReportController.cxx
@@ -2415,10 +2415,11 @@ void OReportController::openPageDialog(const 
uno::Reference<report::XSection>& _
         {
             aDescriptor.Put(SvxSizeItem(RPTUI_ID_SIZE,
                                         
VCLUnoHelper::ConvertToVCLSize(getStyleProperty<awt::Size>(m_xReportDefinition,PROPERTY_PAPERSIZE))));
-            aDescriptor.Put(SvxLRSpaceItem(
-                getStyleProperty<sal_Int32>(m_xReportDefinition, 
PROPERTY_LEFTMARGIN),
-                getStyleProperty<sal_Int32>(m_xReportDefinition, 
PROPERTY_RIGHTMARGIN),
-                SvxIndentValue::zero(), RPTUI_ID_LRSPACE));
+            
aDescriptor.Put(SvxLRSpaceItem(SvxIndentValue::twips(getStyleProperty<sal_Int32>(
+                                               m_xReportDefinition, 
PROPERTY_LEFTMARGIN)),
+                                           
SvxIndentValue::twips(getStyleProperty<sal_Int32>(
+                                               m_xReportDefinition, 
PROPERTY_RIGHTMARGIN)),
+                                           SvxIndentValue::zero(), 
RPTUI_ID_LRSPACE));
             
aDescriptor.Put(SvxULSpaceItem(static_cast<sal_uInt16>(getStyleProperty<sal_Int32>(m_xReportDefinition,PROPERTY_TOPMARGIN))
-e 
... etc. - the rest is truncated

Reply via email to