cui/source/inc/paragrph.hxx                                             |    1 
 cui/source/tabpages/paragrph.cxx                                        |   23 
+
 cui/uiconfig/ui/paragalignpage.ui                                       |   60 
++--
 editeng/source/editeng/editdoc.cxx                                      |   16 
+
 editeng/source/editeng/eerdll.cxx                                       |    2 
 editeng/source/editeng/impedit.hxx                                      |    1 
 editeng/source/editeng/impedit2.cxx                                     |   59 
++++
 editeng/source/items/paraitem.cxx                                       |   20 
+
 i18nutil/CppunitTest_i18nutil.mk                                        |    1 
 i18nutil/Library_i18nutil.mk                                            |    1 
 i18nutil/qa/cppunit/test_guessparadirection.cxx                         |   75 
+++++
 i18nutil/source/utility/guessparadirection.cxx                          |   65 
++++
 include/editeng/autodiritem.hxx                                         |   37 
++
 include/editeng/editids.hrc                                             |    1 
 include/editeng/editrids.hrc                                            |    2 
 include/editeng/eeitem.hxx                                              |    4 
 include/editeng/unotext.hxx                                             |    3 
 include/i18nutil/guessparadirection.hxx                                 |   30 
++
 include/svl/poolitem.hxx                                                |    1 
 include/xmloff/xmltoken.hxx                                             |    1 
 sw/inc/editsh.hxx                                                       |    2 
 sw/inc/hintids.hxx                                                      |   11 
 sw/inc/inspectorproperties.hrc                                          |    1 
 sw/inc/paratr.hxx                                                       |    3 
 sw/inc/swatrset.hxx                                                     |    2 
 sw/inc/unoprnms.hxx                                                     |    1 
 sw/qa/extras/odfexport/data/tdf162120-style-writing-mode-automatic.fodt |  147 
++++++++++
 sw/qa/extras/odfexport/odfexport4.cxx                                   |   13 
 sw/qa/extras/uiwriter/data/tdf162120-auto-rtl.fodt                      |  122 
++++++++
 sw/qa/extras/uiwriter/uiwriter11.cxx                                    |   23 
+
 sw/qa/uitest/styleInspector/styleInspector.py                           |   20 
-
 sw/qa/uitest/styleInspector/tdf137513.py                                |    2 
 sw/source/core/bastyp/init.cxx                                          |    2 
 sw/source/core/doc/dbgoutsw.cxx                                         |    1 
 sw/source/core/edit/eddel.cxx                                           |    3 
 sw/source/core/edit/editsh.cxx                                          |   64 
++++
 sw/source/core/unocore/unomapproperties.hxx                             |    4 
 sw/source/filter/html/css1atr.cxx                                       |    1 
 sw/source/filter/html/htmlatr.cxx                                       |    1 
 sw/source/uibase/shells/txtattr.cxx                                     |    6 
 sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx                   |    1 
 xmloff/inc/xmlprop.hxx                                                  |    1 
 xmloff/source/core/xmltoken.cxx                                         |    1 
 xmloff/source/text/txtprmap.cxx                                         |    3 
 xmloff/source/token/tokens.txt                                          |    1 
 45 files changed, 804 insertions(+), 35 deletions(-)

New commits:
commit 69e902d0855d236aa12ec3105d9947ab6cd1d6c7
Author:     Jonathan Clark <[email protected]>
AuthorDate: Thu Oct 30 04:07:13 2025 -0600
Commit:     Jonathan Clark <[email protected]>
CommitDate: Thu Nov 13 04:45:50 2025 +0100

    tdf#162120 Implement style:writing-mode-automatic
    
    Implements the ODF 1.2 paragraph attribute style:writing-mode-automatic,
    and supporting runtime features. When set, this attribute allows
    programs to automatically recompute the paragraph writing mode when the
    contents of the paragraph have been edited.
    
    The ODF standard does not suggest any particular algorithm for
    automatically determining paragraph direction. This implementation uses
    the rules from Unicode UAX #9 3.3.1.
    
    Currently, LO will only automatically change the writing direction when
    new text is typed or deleted. Other known interesting cases are already
    tracked as separate enhancement requests.
    
    Change-Id: I49eecea36952588dc98f2a98ebce712cd2846c0c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193547
    Reviewed-by: Jonathan Clark <[email protected]>
    Tested-by: Jenkins

diff --git a/cui/source/inc/paragrph.hxx b/cui/source/inc/paragrph.hxx
index ff6482526ed3..9d95e1adfa9b 100644
--- a/cui/source/inc/paragrph.hxx
+++ b/cui/source/inc/paragrph.hxx
@@ -151,6 +151,7 @@ class SvxParaAlignTabPage : public SfxTabPage
     std::unique_ptr<weld::Label> m_xVertAlignSdr;
 
     std::unique_ptr<svx::FrameDirectionListBox>  m_xTextDirectionLB;
+    std::unique_ptr<weld::CheckButton> m_xAutoTextDirectionCB;
 
     /// word spacing
     std::unique_ptr<weld::Label> m_xLabelWordSpacing;
diff --git a/cui/source/tabpages/paragrph.cxx b/cui/source/tabpages/paragrph.cxx
index 978c4811b8cf..427fb7356654 100644
--- a/cui/source/tabpages/paragrph.cxx
+++ b/cui/source/tabpages/paragrph.cxx
@@ -32,6 +32,7 @@
 #include <svx/strings.hrc>
 #include <svx/dialmgr.hxx>
 #include <paragrph.hxx>
+#include <editeng/autodiritem.hxx>
 #include <editeng/frmdiritem.hxx>
 #include <editeng/lspcitem.hxx>
 #include <editeng/adjustitem.hxx>
@@ -77,7 +78,8 @@ const WhichRangesContainer 
SvxParaAlignTabPage::pSdrAlignRanges(
     svl::Items<
     SDRATTR_TEXT_VERTADJUST, SDRATTR_TEXT_VERTADJUST, // 1076
     SID_ATTR_PARA_ADJUST, SID_ATTR_PARA_ADJUST ,      // 10027
-    SID_ATTR_FRAMEDIRECTION, SID_ATTR_FRAMEDIRECTION  // 10944
+    SID_ATTR_FRAMEDIRECTION, SID_ATTR_FRAMEDIRECTION, // 10944
+    SID_ATTR_PARA_AUTOFRAMEDIRECTION, SID_ATTR_PARA_AUTOFRAMEDIRECTION
     >);
 
 const WhichRangesContainer SvxExtParagraphTabPage::pExtRanges(svl::Items<
@@ -1282,6 +1284,7 @@ SvxParaAlignTabPage::SvxParaAlignTabPage(weld::Container* 
pPage, weld::DialogCon
     , m_xVertAlign(m_xBuilder->weld_label(u"labelFL_VERTALIGN"_ustr))
     , m_xVertAlignSdr(m_xBuilder->weld_label(u"labelST_VERTALIGN_SDR"_ustr))
     , m_xTextDirectionLB(new 
svx::FrameDirectionListBox(m_xBuilder->weld_combo_box(u"comboLB_TEXTDIRECTION"_ustr)))
+    , 
m_xAutoTextDirectionCB(m_xBuilder->weld_check_button(u"checkCB_AUTOTEXTDIRECTION"_ustr))
     , m_xLabelWordSpacing(m_xBuilder->weld_label(u"labelWordSpacing"_ustr))
     , m_xLabelMinimum(m_xBuilder->weld_label(u"labelMinimum"_ustr))
     , m_xLabelDesired(m_xBuilder->weld_label(u"labelDesired"_ustr))
@@ -1458,6 +1461,13 @@ bool SvxParaAlignTabPage::FillItemSet( SfxItemSet* 
rOutSet )
         }
     }
 
+    if (m_xAutoTextDirectionCB->get_state_changed_from_saved())
+    {
+        
rOutSet->Put(SvxAutoFrameDirectionItem(m_xAutoTextDirectionCB->get_active(),
+                                               
GetWhich(SID_ATTR_PARA_AUTOFRAMEDIRECTION)));
+        bModified = true;
+    }
+
     return bModified;
 }
 
@@ -1618,6 +1628,16 @@ void SvxParaAlignTabPage::Reset( const SfxItemSet* rSet )
         m_xTextDirectionLB->save_value();
     }
 
+    _nWhich = GetWhich(SID_ATTR_PARA_AUTOFRAMEDIRECTION);
+    eItemState = rSet->GetItemState(_nWhich);
+    if (eItemState >= SfxItemState::DEFAULT)
+    {
+        const SvxAutoFrameDirectionItem& rSnap
+            = static_cast<const 
SvxAutoFrameDirectionItem&>(rSet->Get(_nWhich));
+        m_xAutoTextDirectionCB->set_active(rSnap.GetValue());
+    }
+
+    m_xAutoTextDirectionCB->save_state();
     m_xSnapToGridCB->save_state();
     m_xVertAlignLB->save_value();
     m_xLeft->save_state();
@@ -1642,6 +1662,7 @@ void SvxParaAlignTabPage::Reset( const SfxItemSet* rSet )
 void SvxParaAlignTabPage::ChangesApplied()
 {
     m_xTextDirectionLB->save_value();
+    m_xAutoTextDirectionCB->save_state();
     m_xSnapToGridCB->save_state();
     m_xVertAlignLB->save_value();
     m_xLeft->save_state();
diff --git a/cui/uiconfig/ui/paragalignpage.ui 
b/cui/uiconfig/ui/paragalignpage.ui
index 46644dba15bf..4f0a095d9ef7 100644
--- a/cui/uiconfig/ui/paragalignpage.ui
+++ b/cui/uiconfig/ui/paragalignpage.ui
@@ -418,36 +418,62 @@
             <property name="label-xalign">0</property>
             <property name="shadow-type">none</property>
             <child>
-              <object class="GtkBox" id="box3">
+              <!-- n-columns=1 n-rows=2 -->
+              <object class="GtkGrid" id="grid3">
                 <property name="visible">True</property>
                 <property name="can-focus">False</property>
-                <property name="margin-start">12</property>
-                <property name="margin-top">6</property>
-                <property name="spacing">6</property>
                 <child>
-                  <object class="GtkLabel" id="label2">
+                  <object class="GtkBox" id="box3">
                     <property name="visible">True</property>
                     <property name="can-focus">False</property>
-                    <property name="label" translatable="yes" 
context="paragalignpage|label2">_Text direction:</property>
-                    <property name="use-underline">True</property>
-                    <property 
name="mnemonic-widget">comboLB_TEXTDIRECTION</property>
-                    <property name="xalign">0</property>
+                    <property name="margin-start">12</property>
+                    <property name="margin-top">6</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="label" translatable="yes" 
context="paragalignpage|label2">_Text direction:</property>
+                        <property name="use-underline">True</property>
+                        <property 
name="mnemonic-widget">comboLB_TEXTDIRECTION</property>
+                        <property name="xalign">0</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkComboBoxText" 
id="comboLB_TEXTDIRECTION">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
+                    <property name="left-attach">0</property>
+                    <property name="top-attach">0</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkComboBoxText" id="comboLB_TEXTDIRECTION">
+                  <object class="GtkCheckButton" 
id="checkCB_AUTOTEXTDIRECTION">
+                    <property name="label" translatable="yes" 
context="paragalignpage|checkCB_AUTOTEXTDIRECTION">Automatically set 
direction</property>
                     <property name="visible">True</property>
-                    <property name="can-focus">False</property>
+                    <property name="can-focus">True</property>
+                    <property name="receives-default">False</property>
+                    <property name="margin-start">22</property>
+                    <property name="use-underline">True</property>
+                    <property name="draw-indicator">True</property>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
+                    <property name="left-attach">0</property>
+                    <property name="top-attach">1</property>
                   </packing>
                 </child>
               </object>
diff --git a/editeng/source/editeng/editdoc.cxx 
b/editeng/source/editeng/editdoc.cxx
index 05d7084a278b..581a22a88d30 100644
--- a/editeng/source/editeng/editdoc.cxx
+++ b/editeng/source/editeng/editdoc.cxx
@@ -19,6 +19,7 @@
 
 #include <editdoc.hxx>
 
+#include <editeng/autodiritem.hxx>
 #include <editeng/tstpitem.hxx>
 #include <editeng/colritem.hxx>
 #include <editeng/fontitem.hxx>
@@ -1031,6 +1032,14 @@ void YrsInsertAttribImplImpl(YrsWrite const& yw, 
SfxPoolItem const& rItm,
             attrName = "EE_PARA_WRITINGDIR";
             break;
         }
+        case EE_PARA_AUTOWRITINGDIR:
+        {
+            SvxAutoFrameDirectionItem const& rItem{ 
static_cast<SvxAutoFrameDirectionItem const&>(
+                rItm) };
+            attr = yinput_bool(rItem.GetValue() ? Y_TRUE : Y_FALSE);
+            attrName = "EE_PARA_AUTOWRITINGDIR";
+            break;
+        }
         case EE_PARA_HANGINGPUNCTUATION:
         {
             SvxHangingPunctuationItem const& 
rItem{static_cast<SvxHangingPunctuationItem const&>(rItm)};
@@ -2118,6 +2127,13 @@ void YrsImplInsertAttr(SfxItemSet & rSet, 
::std::vector<sal_uInt16> *const pRemo
             rSet.Put(item);
             break;
         }
+        case EE_PARA_AUTOWRITINGDIR:
+        {
+            yvalidate(rValue.tag == Y_JSON_BOOL);
+            SvxAutoFrameDirectionitem const item{ rValue.value.flag == Y_TRUE, 
nWhich };
+            rSet.Put(item);
+            break;
+        }
         case EE_PARA_HANGINGPUNCTUATION:
         {
             yvalidate(rValue.tag == Y_JSON_BOOL);
diff --git a/editeng/source/editeng/eerdll.cxx 
b/editeng/source/editeng/eerdll.cxx
index e828897160e1..bd154781d87b 100644
--- a/editeng/source/editeng/eerdll.cxx
+++ b/editeng/source/editeng/eerdll.cxx
@@ -40,6 +40,7 @@
 #include <vcl/svapp.hxx>
 #include <vcl/virdev.hxx>
 
+#include <editeng/autodiritem.hxx>
 #include <editeng/autokernitem.hxx>
 #include <editeng/contouritem.hxx>
 #include <editeng/colritem.hxx>
@@ -118,6 +119,7 @@ ItemInfoPackage& getItemInfoPackageEditEngine()
             { EE_PARA_TABS, new SvxTabStopItem( 0, 0, SvxTabAdjust::Left, 
EE_PARA_TABS ), SID_ATTR_TABSTOP, SFX_ITEMINFOFLAG_NONE  },
             { EE_PARA_JUST_METHOD, new SvxJustifyMethodItem( 
SvxCellJustifyMethod::Auto, EE_PARA_JUST_METHOD ), 
SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD, SFX_ITEMINFOFLAG_NONE  },
             { EE_PARA_VER_JUST, new SvxVerJustifyItem( 
SvxCellVerJustify::Standard, EE_PARA_VER_JUST ), SID_ATTR_ALIGN_VER_JUSTIFY, 
SFX_ITEMINFOFLAG_NONE  },
+            { EE_PARA_AUTOWRITINGDIR, new SvxAutoFrameDirectionItem( false, 
EE_PARA_AUTOWRITINGDIR ), SID_ATTR_PARA_AUTOFRAMEDIRECTION, 
SFX_ITEMINFOFLAG_NONE },
             { EE_CHAR_COLOR, new SvxColorItem( COL_AUTO, EE_CHAR_COLOR ), 
SID_ATTR_CHAR_COLOR, SFX_ITEMINFOFLAG_SUPPORT_SURROGATE  },
 
             // EE_CHAR_FONTINFO, EE_CHAR_FONTINFO_CJK and EE_CHAR_FONTINFO_CTL 
need on-demand initialization
diff --git a/editeng/source/editeng/impedit.hxx 
b/editeng/source/editeng/impedit.hxx
index 72eadc1b79ac..aba08ab2f2ba 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -1044,6 +1044,7 @@ public:
     EditPaM         InsertLineBreak(const EditSelection& aEditSelection);
     EditPaM         InsertTab(const EditSelection& rEditSelection);
     EditPaM         InsertField(const EditSelection& rCurSel, const 
SvxFieldItem& rFld);
+    void            UpdateAutoParaDirection(const EditSelection& rCurSel);
     bool            UpdateFields();
 
     ErrCode         Read( SvStream& rInput, const OUString& rBaseURL, 
EETextFormat eFormat, SvKeyValueIterator* pHTTPHeaderAttrs = nullptr );
diff --git a/editeng/source/editeng/impedit2.cxx 
b/editeng/source/editeng/impedit2.cxx
index c72239dedc11..6d64243e1ffe 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -39,6 +39,7 @@
 #include <editeng/ulspitem.hxx>
 #include <editeng/adjustitem.hxx>
 #include <editeng/frmdiritem.hxx>
+#include <editeng/autodiritem.hxx>
 #include <editeng/justifyitem.hxx>
 #include <editeng/scripthintitem.hxx>
 
@@ -63,6 +64,7 @@
 #include <svl/voiditem.hxx>
 #include <i18nutil/unicode.hxx>
 #include <i18nutil/scriptchangescanner.hxx>
+#include <i18nutil/guessparadirection.hxx>
 #include <comphelper/diagnose_ex.hxx>
 #include <comphelper/flagguard.hxx>
 #include <comphelper/lok.hxx>
@@ -466,6 +468,9 @@ bool ImpEditEngine::Command( const CommandEvent& rCEvt, 
EditView* pView )
                     mpIMEInfos->nLen = pData->GetText().getLength();
                 }
 
+                // tdf#162120: Automatically adjust paragraph directions after 
edit
+                UpdateAutoParaDirection(EditSelection{ mpIMEInfos->aPos });
+
                 ParaPortion* pPortion = FindParaPortion( 
mpIMEInfos->aPos.GetNode() );
                 pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );
                 FormatAndLayout( pView );
@@ -2532,6 +2537,10 @@ EditPaM ImpEditEngine::ImpDeleteSelection(const 
EditSelection& rCurSel)
 
     UpdateSelectionsDelete(deleted);
     UpdateSelections();
+
+    // tdf#162120: Automatically adjust paragraph directions after edit
+    UpdateAutoParaDirection(rCurSel);
+
     TextModified();
     return aStartPaM;
 }
@@ -2763,6 +2772,9 @@ EditPaM ImpEditEngine::InsertTextUserInput( const 
EditSelection& rCurSel,
         aPaM.SetIndex( aPaM.GetIndex()+1 );   // does not do EditDoc-Method 
anymore
     }
 
+    // tdf#162120: Automatically adjust paragraph direction after edit
+    UpdateAutoParaDirection(EditSelection{ aPaM });
+
     TextModified();
 
     if ( bUndoAction )
@@ -2771,6 +2783,53 @@ EditPaM ImpEditEngine::InsertTextUserInput( const 
EditSelection& rCurSel,
     return aPaM;
 }
 
+void ImpEditEngine::UpdateAutoParaDirection(const EditSelection& rCurSel)
+{
+    EditPaM aPaM(rCurSel.Min());
+
+    auto nPara = maEditDoc.GetPos(aPaM.GetNode());
+    if (nPara >= GetParaPortions().Count() || !HasParaAttrib(nPara, 
EE_PARA_AUTOWRITINGDIR))
+    {
+        return;
+    }
+
+    const SvxAutoFrameDirectionItem& rItem = GetParaAttrib(nPara, 
EE_PARA_AUTOWRITINGDIR);
+    if (!rItem.GetValue())
+    {
+        return;
+    }
+
+    bool bIsAlreadyRtl = IsRightToLeft(nPara);
+
+    bool bShouldBeRtl = bIsAlreadyRtl;
+    switch (i18nutil::GuessParagraphDirection(aPaM.GetNode()->GetString()))
+    {
+        case i18nutil::ParagraphDirection::Ambiguous:
+            bShouldBeRtl = bIsAlreadyRtl;
+            break;
+
+        case i18nutil::ParagraphDirection::LeftToRight:
+            bShouldBeRtl = false;
+            break;
+
+        case i18nutil::ParagraphDirection::RightToLeft:
+            bShouldBeRtl = true;
+            break;
+    }
+
+    if (bShouldBeRtl == bIsAlreadyRtl)
+    {
+        return;
+    }
+
+    SvxFrameDirection eNeeded
+        = bShouldBeRtl ? SvxFrameDirection::Horizontal_RL_TB : 
SvxFrameDirection::Horizontal_LR_TB;
+
+    SfxItemSet aSet{ GetParaAttribs(nPara) };
+    aSet.Put(SvxFrameDirectionItem{ eNeeded, EE_PARA_WRITINGDIR });
+    SetParaAttribs(nPara, aSet);
+}
+
 EditPaM ImpEditEngine::ImpInsertText(const EditSelection& aCurSel, const 
OUString& rStr)
 {
     UndoActionStart( EDITUNDO_INSERT );
diff --git a/editeng/source/items/paraitem.cxx 
b/editeng/source/items/paraitem.cxx
index 9c16c3f78dca..f49b1f986717 100644
--- a/editeng/source/items/paraitem.cxx
+++ b/editeng/source/items/paraitem.cxx
@@ -43,6 +43,7 @@
 #include <editeng/forbiddenruleitem.hxx>
 #include <editeng/paravertalignitem.hxx>
 #include <editeng/pgrditem.hxx>
+#include <editeng/autodiritem.hxx>
 #include <rtl/ustring.hxx>
 #include <sal/log.hxx>
 #include <editeng/memberids.h>
@@ -1514,5 +1515,24 @@ bool SvxParaGridItem::GetPresentation(
     return true;
 }
 
+SvxAutoFrameDirectionItem::SvxAutoFrameDirectionItem(bool bValue, const 
sal_uInt16 nId)
+    : SfxBoolItem(nId, bValue)
+{
+}
+
+SvxAutoFrameDirectionItem* SvxAutoFrameDirectionItem::Clone(SfxItemPool*) const
+{
+    return new SvxAutoFrameDirectionItem(*this);
+}
+
+bool SvxAutoFrameDirectionItem::GetPresentation(SfxItemPresentation /*ePres*/,
+                                                MapUnit /*eCoreMetric*/, 
MapUnit /*ePresMetric*/,
+                                                OUString& rText, const 
IntlWrapper& /*rIntl*/) const
+{
+    rText = GetValue() ? EditResId(RID_SVXITEMS_AUTOFRAMEDIRECTION_ON)
+                       : EditResId(RID_SVXITEMS_AUTOFRAMEDIRECTION_OFF);
+
+    return true;
+}
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/i18nutil/CppunitTest_i18nutil.mk b/i18nutil/CppunitTest_i18nutil.mk
index cdf79a2d2268..56cf5889f9ef 100644
--- a/i18nutil/CppunitTest_i18nutil.mk
+++ b/i18nutil/CppunitTest_i18nutil.mk
@@ -14,6 +14,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,i18nutil))
 $(eval $(call gb_CppunitTest_use_sdk_api,i18nutil))
 
 $(eval $(call gb_CppunitTest_add_exception_objects,i18nutil,\
+       i18nutil/qa/cppunit/test_guessparadirection \
        i18nutil/qa/cppunit/test_kashida \
        i18nutil/qa/cppunit/test_scriptchangescanner \
 ))
diff --git a/i18nutil/Library_i18nutil.mk b/i18nutil/Library_i18nutil.mk
index 8e68c3ba00c2..cf166a476401 100644
--- a/i18nutil/Library_i18nutil.mk
+++ b/i18nutil/Library_i18nutil.mk
@@ -44,6 +44,7 @@ $(eval $(call gb_Library_use_libraries,i18nutil,\
 
 $(eval $(call gb_Library_add_exception_objects,i18nutil,\
        i18nutil/source/utility/casefolding \
+       i18nutil/source/utility/guessparadirection \
        i18nutil/source/utility/kashida \
        i18nutil/source/utility/oneToOneMapping \
        i18nutil/source/utility/paper \
diff --git a/i18nutil/qa/cppunit/test_guessparadirection.cxx 
b/i18nutil/qa/cppunit/test_guessparadirection.cxx
new file mode 100644
index 000000000000..1995fc18dbf4
--- /dev/null
+++ b/i18nutil/qa/cppunit/test_guessparadirection.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/types.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <i18nutil/guessparadirection.hxx>
+
+using namespace i18nutil;
+
+namespace
+{
+class GuessParagraphDirectionTest : public CppUnit::TestFixture
+{
+public:
+    void testEmpty();
+    void testFirstStrongLTR();
+    void testFirstStrongRTL();
+    void testFirstStrongAR();
+    void testIsolate();
+
+    CPPUNIT_TEST_SUITE(GuessParagraphDirectionTest);
+    CPPUNIT_TEST(testEmpty);
+    CPPUNIT_TEST(testFirstStrongLTR);
+    CPPUNIT_TEST(testFirstStrongRTL);
+    CPPUNIT_TEST(testFirstStrongAR);
+    CPPUNIT_TEST(testIsolate);
+    CPPUNIT_TEST_SUITE_END();
+};
+
+void GuessParagraphDirectionTest::testEmpty()
+{
+    auto aText = u""_ustr;
+    CPPUNIT_ASSERT_EQUAL(ParagraphDirection::Ambiguous, 
GuessParagraphDirection(aText));
+}
+
+void GuessParagraphDirectionTest::testFirstStrongLTR()
+{
+    auto aText = u"..aاא.."_ustr;
+    CPPUNIT_ASSERT_EQUAL(ParagraphDirection::LeftToRight, 
GuessParagraphDirection(aText));
+}
+
+void GuessParagraphDirectionTest::testFirstStrongRTL()
+{
+    auto aText = u"..אaا.."_ustr;
+    CPPUNIT_ASSERT_EQUAL(ParagraphDirection::RightToLeft, 
GuessParagraphDirection(aText));
+}
+
+void GuessParagraphDirectionTest::testFirstStrongAR()
+{
+    auto aText = u"..اaא.."_ustr;
+    CPPUNIT_ASSERT_EQUAL(ParagraphDirection::RightToLeft, 
GuessParagraphDirection(aText));
+}
+
+void GuessParagraphDirectionTest::testIsolate()
+{
+    // U+2066: LRI
+    // U+2067: RLI
+    // U+2069: PDI
+    auto aText = u"...\u2069.\u2067aaa\u2066אאא\u2069.\u2069.."_ustr;
+    CPPUNIT_ASSERT_EQUAL(ParagraphDirection::Ambiguous, 
GuessParagraphDirection(aText));
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(GuessParagraphDirectionTest);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/i18nutil/source/utility/guessparadirection.cxx 
b/i18nutil/source/utility/guessparadirection.cxx
new file mode 100644
index 000000000000..f882b2a6c928
--- /dev/null
+++ b/i18nutil/source/utility/guessparadirection.cxx
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <i18nutil/guessparadirection.hxx>
+#include <i18nutil/unicode.hxx>
+#include <unicode/uchar.h>
+#include <unicode/ubidi.h>
+
+i18nutil::ParagraphDirection i18nutil::GuessParagraphDirection(const OUString& 
rText)
+{
+    // tdf#162120: This algorithm implements Unicode UAX #9 3.3.1
+    // for automatically determining the paragraph level without
+    // override from a higher-level protocol.
+    // The algorithm has been extended to explicitly communicate
+    // an ambiguous case, rather than defaulting to LTR.
+
+    sal_Int32 nBase = 0;
+
+    sal_Int32 nIsolateLevel = 0;
+    while (nBase < rText.getLength())
+    {
+        auto nChar = rText.iterateCodePoints(&nBase);
+        auto nCharDir = u_charDirection(nChar);
+
+        switch (nCharDir)
+        {
+            case U_POP_DIRECTIONAL_ISOLATE:
+                nIsolateLevel = std::max(sal_Int32{ 0 }, nIsolateLevel - 1);
+                break;
+
+            case U_LEFT_TO_RIGHT_ISOLATE:
+            case U_RIGHT_TO_LEFT_ISOLATE:
+                ++nIsolateLevel;
+                break;
+
+            case U_LEFT_TO_RIGHT:
+                if (nIsolateLevel == 0)
+                {
+                    return ParagraphDirection::LeftToRight;
+                }
+                break;
+
+            case U_RIGHT_TO_LEFT:
+            case U_RIGHT_TO_LEFT_ARABIC:
+                if (nIsolateLevel == 0)
+                {
+                    return ParagraphDirection::RightToLeft;
+                }
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    return ParagraphDirection::Ambiguous;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/include/editeng/autodiritem.hxx b/include/editeng/autodiritem.hxx
new file mode 100644
index 000000000000..2b3cf3c4715a
--- /dev/null
+++ b/include/editeng/autodiritem.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <svl/eitem.hxx>
+#include <editeng/editengdllapi.h>
+
+class EDITENG_DLLPUBLIC SvxAutoFrameDirectionItem final : public SfxBoolItem
+{
+public:
+    DECLARE_ITEM_TYPE_FUNCTION(SvxAutoFrameDirectionItem)
+    SvxAutoFrameDirectionItem(const bool bValue, const sal_uInt16 nId);
+
+    virtual SvxAutoFrameDirectionItem* Clone(SfxItemPool* pPool = nullptr) 
const override;
+
+    virtual bool GetPresentation(SfxItemPresentation ePres, MapUnit 
eCoreMetric,
+                                 MapUnit ePresMetric, OUString& rText,
+                                 const IntlWrapper&) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/editeng/editids.hrc b/include/editeng/editids.hrc
index 6a1a0e81f339..72b4a5a6d8ad 100644
--- a/include/editeng/editids.hrc
+++ b/include/editeng/editids.hrc
@@ -160,6 +160,7 @@ class SvxScriptHintItem;
 #define SID_PARA_VERTALIGN                              
TypedWhichId<SvxParaVertAlignItem>( SID_SVX_START + 925 )
 #define SID_ATTR_FRAMEDIRECTION                         
TypedWhichId<SvxFrameDirectionItem>( SID_SVX_START + 944 )
 #define SID_ATTR_PARA_SNAPTOGRID                        
TypedWhichId<SvxParaGridItem>( SID_SVX_START + 945 )
+#define SID_ATTR_PARA_AUTOFRAMEDIRECTION                
TypedWhichId<SvxAutoFrameDirectionItem>( SID_SVX_START + 946 )
 #define SID_ATTR_PARA_LRSPACE_VERTICAL                  ( SID_SVX_START + 947 )
 #define SID_ATTR_PARA_LEFT_TO_RIGHT                     ( SID_SVX_START + 950 )
 #define SID_ATTR_PARA_RIGHT_TO_LEFT                     ( SID_SVX_START + 951 )
diff --git a/include/editeng/editrids.hrc b/include/editeng/editrids.hrc
index fa82e0d90f33..a257b9004b58 100644
--- a/include/editeng/editrids.hrc
+++ b/include/editeng/editrids.hrc
@@ -301,6 +301,8 @@
 #define RID_SVXITEMS_FRMDIR_VERT_TOP_RIGHT90     
NC_("RID_SVXITEMS_FRMDIR_Vert_TOP_RIGHT90", "Text direction right-to-left 
(vertical, all characters rotated)")
 #define RID_SVXITEMS_PARASNAPTOGRID_ON          
NC_("RID_SVXITEMS_PARASNAPTOGRID_ON", "Paragraph snaps to text grid (if 
active)")
 #define RID_SVXITEMS_PARASNAPTOGRID_OFF         
NC_("RID_SVXITEMS_PARASNAPTOGRID_OFF", "Paragraph does not snap to text grid")
+#define RID_SVXITEMS_AUTOFRAMEDIRECTION_ON      
NC_("RID_SVXITEMS_AUTOFRAMEDIRECTION_ON", "Text direction is automatically 
updated")
+#define RID_SVXITEMS_AUTOFRAMEDIRECTION_OFF     
NC_("RID_SVXITEMS_AUTOFRAMEDIRECTION_OFF", "Text direction is not automatically 
updated")
 #define RID_SVXITEMS_CHARHIDDEN_FALSE           
NC_("RID_SVXITEMS_CHARHIDDEN_FALSE", "Not hidden")
 #define RID_SVXITEMS_CHARHIDDEN_TRUE            
NC_("RID_SVXITEMS_CHARHIDDEN_TRUE", "Hidden")
 
diff --git a/include/editeng/eeitem.hxx b/include/editeng/eeitem.hxx
index ce8315ec4e27..89b85207a24a 100644
--- a/include/editeng/eeitem.hxx
+++ b/include/editeng/eeitem.hxx
@@ -27,6 +27,7 @@ class SfxBoolItem;
 class SfxGrabBagItem;
 class SfxInt16Item;
 class SvxAdjustItem;
+class SvxAutoFrameDirectionItem;
 class SvxAutoKernItem;
 class SvxCaseMapItem;
 class SvxCharReliefItem;
@@ -93,7 +94,8 @@ inline constexpr TypedWhichId<SvxAdjustItem>             
EE_PARA_JUST
 inline constexpr TypedWhichId<SvxTabStopItem>            EE_PARA_TABS          
     (EE_PARA_START+17);
 inline constexpr TypedWhichId<SvxJustifyMethodItem>      EE_PARA_JUST_METHOD   
     (EE_PARA_START+18);
 inline constexpr TypedWhichId<SvxVerJustifyItem>         EE_PARA_VER_JUST      
     (EE_PARA_START+19);
-inline constexpr sal_uInt16                              EE_PARA_END           
     (EE_PARA_START + 19);
+inline constexpr TypedWhichId<SvxAutoFrameDirectionItem> 
EE_PARA_AUTOWRITINGDIR     (EE_PARA_START+20);
+inline constexpr sal_uInt16                              EE_PARA_END           
     (EE_PARA_START + 20);
 
 // Character attributes:
 inline constexpr sal_uInt16                           EE_CHAR_START          
(EE_PARA_END + 1);
diff --git a/include/editeng/unotext.hxx b/include/editeng/unotext.hxx
index f2bc22fd4dba..37e82293dbb3 100644
--- a/include/editeng/unotext.hxx
+++ b/include/editeng/unotext.hxx
@@ -170,7 +170,8 @@ struct SfxItemPropertyMapEntry;
     {u"ParaLetterSpacingMaximum"_ustr, EE_PARA_JUST,               
::cppu::UnoType<sal_Int16>::get(),            0, MID_LETTER_SPACING_MAX }, \
     {u"ParaScaleWidthMinimum"_ustr,    EE_PARA_JUST,               
::cppu::UnoType<sal_Int16>::get(),            0, MID_SCALE_WIDTH_MIN }, \
     {u"ParaScaleWidthMaximum"_ustr,    EE_PARA_JUST,               
::cppu::UnoType<sal_Int16>::get(),            0, MID_SCALE_WIDTH_MAX }, \
-    {u"WritingMode"_ustr,              EE_PARA_WRITINGDIR, 
::cppu::UnoType<sal_Int16>::get(),            0, 0 }
+    {u"WritingMode"_ustr,              EE_PARA_WRITINGDIR, 
::cppu::UnoType<sal_Int16>::get(),            0, 0 }, \
+    {u"WritingModeAutomatic"_ustr,     EE_PARA_AUTOWRITINGDIR, 
::cppu::UnoType<bool>::get(), 0, 0 }
 
 class SvxFieldData;
 
diff --git a/include/i18nutil/guessparadirection.hxx 
b/include/i18nutil/guessparadirection.hxx
new file mode 100644
index 000000000000..6ad5a5d8d04d
--- /dev/null
+++ b/include/i18nutil/guessparadirection.hxx
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <i18nutil/i18nutildllapi.h>
+#include <com/sun/star/text/ScriptHintType.hpp>
+#include <rtl/ustring.hxx>
+#include <optional>
+#include <memory>
+#include <vector>
+
+namespace i18nutil
+{
+enum class ParagraphDirection
+{
+    Ambiguous,
+    LeftToRight,
+    RightToLeft
+};
+
+I18NUTIL_DLLPUBLIC ParagraphDirection GuessParagraphDirection(const OUString& 
rText);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/include/svl/poolitem.hxx b/include/svl/poolitem.hxx
index ceebf33f24f3..fbe4b6a62336 100644
--- a/include/svl/poolitem.hxx
+++ b/include/svl/poolitem.hxx
@@ -309,6 +309,7 @@ enum class SfxItemType : sal_uInt16
     Svx3DTextureProjectionXItemType,
     Svx3DTextureProjectionYItemType,
     SvxAdjustItemType,
+    SvxAutoFrameDirectionItemType,
     SvxAutoKernItemType,
     SvxB3DVectorItemType,
     SvxBitmapListItemType,
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 828de31eb2aa..cd1cb76a3cd7 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -2214,6 +2214,7 @@ namespace xmloff::token {
         XML_WRAP_CONTOUR_MODE,
         XML_WRAP_OPTION,
         XML_WRITING_MODE,
+        XML_WRITING_MODE_AUTOMATIC,
         XML_WWW,
         XML_X,
         XML_X1,
diff --git a/sw/inc/editsh.hxx b/sw/inc/editsh.hxx
index a44b9e78eb73..aaa90df40c6c 100644
--- a/sw/inc/editsh.hxx
+++ b/sw/inc/editsh.hxx
@@ -161,6 +161,8 @@ class SAL_DLLPUBLIC_RTTI SwEditShell : public SwCursorShell
     using SwViewShell::UpdateFields;
     using sw::BroadcastingModify::GetInfo;
 
+    void UpdateSelectionAutoParaDirection();
+
 public:
     /// Edit (all selected ranges).
     void Insert( sal_Unicode, bool bOnlyCurrCursor = false );
diff --git a/sw/inc/hintids.hxx b/sw/inc/hintids.hxx
index 9636779a1cc6..39676270559c 100644
--- a/sw/inc/hintids.hxx
+++ b/sw/inc/hintids.hxx
@@ -35,6 +35,7 @@ class SwFormatContentControl;
 class SvXMLAttrContainerItem;
 class SwMsgPoolItem;
 class SfxBoolItem;
+class SvxAutoFrameDirectionItem;
 class SvxColorItem;
 class SvxLeftMarginItem;
 class SvxTextLeftMarginItem;
@@ -314,9 +315,13 @@ inline constexpr TypedWhichId<SvxParaGridItem> 
RES_PARATR_SNAPTOGRID(RES_PARATR_
 inline constexpr TypedWhichId<SwParaConnectBorderItem> 
RES_PARATR_CONNECT_BORDER(RES_PARATR_BEGIN
                                                                                
  + 15);
 inline constexpr TypedWhichId<SfxUInt16Item> 
RES_PARATR_OUTLINELEVEL(RES_PARATR_BEGIN + 16);
-inline constexpr TypedWhichId<SvxRsidItem> RES_PARATR_RSID(RES_PARATR_BEGIN + 
17);
-inline constexpr TypedWhichId<SfxGrabBagItem> 
RES_PARATR_GRABBAG(RES_PARATR_BEGIN + 18);
-inline constexpr sal_uInt16 RES_PARATR_END(RES_PARATR_BEGIN + 19);
+inline constexpr TypedWhichId<SvxAutoFrameDirectionItem> 
RES_PARATR_AUTOFRAMEDIR(RES_PARATR_BEGIN
+                                                                               
  + 17);
+// DocumentRedlineManager assumes RSID and GRABBAG are the last paragraph 
attributes.
+// Insert new paragraph attributes before them.
+inline constexpr TypedWhichId<SvxRsidItem> RES_PARATR_RSID(RES_PARATR_BEGIN + 
18);
+inline constexpr TypedWhichId<SfxGrabBagItem> 
RES_PARATR_GRABBAG(RES_PARATR_BEGIN + 19);
+inline constexpr sal_uInt16 RES_PARATR_END(RES_PARATR_BEGIN + 20);
 
 // list attributes for paragraphs.
 // intentionally these list attributes are not contained in paragraph styles
diff --git a/sw/inc/inspectorproperties.hrc b/sw/inc/inspectorproperties.hrc
index 5c7d5f2c62cd..d6dedab2f9f3 100644
--- a/sw/inc/inspectorproperties.hrc
+++ b/sw/inc/inspectorproperties.hrc
@@ -275,6 +275,7 @@
 #define RID_UNVISITED_CHAR_STYLE_NAME                       
NC_("RID_ATTRIBUTE_NAMES_MAP", "Unvisited Char Style Name")
 #define RID_VISITED_CHAR_STYLE_NAME                         
NC_("RID_ATTRIBUTE_NAMES_MAP", "Visited Char Style Name")
 #define RID_WRITING_MODE                                    
NC_("RID_ATTRIBUTE_NAMES_MAP", "Writing Mode")
+#define RID_WRITING_MODE_AUTOMATIC                          
NC_("RID_ATTRIBUTE_NAMES_MAP", "Para Auto Writing Mode")
 
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/inc/paratr.hxx b/sw/inc/paratr.hxx
index ae222249fe70..947e9a7c665e 100644
--- a/sw/inc/paratr.hxx
+++ b/sw/inc/paratr.hxx
@@ -26,6 +26,7 @@
 #include "swatrset.hxx"
 #include "format.hxx"
 #include "charfmt.hxx"
+#include <editeng/autodiritem.hxx>
 #include <editeng/adjustitem.hxx>
 #include <editeng/lspcitem.hxx>
 #include <editeng/spltitem.hxx>
@@ -232,6 +233,8 @@ inline const SvxParaGridItem &SwAttrSet::GetParaGrid(bool 
bInP) const
     {   return Get( RES_PARATR_SNAPTOGRID, bInP ); }
 inline const SwParaConnectBorderItem &SwAttrSet::GetParaConnectBorder(bool 
bInP) const
     {   return Get( RES_PARATR_CONNECT_BORDER, bInP ); }
+inline const SvxAutoFrameDirectionItem &SwAttrSet::GetAutoFrameDirection(bool 
bInP) const
+    {   return Get( RES_PARATR_AUTOFRAMEDIR, bInP ); }
 
 // Implementation of paragraph-attributes methods of SwFormat
 inline const SvxLineSpacingItem &SwFormat::GetLineSpacing(bool bInP) const
diff --git a/sw/inc/swatrset.hxx b/sw/inc/swatrset.hxx
index 8e3df5fcb145..67709a849665 100644
--- a/sw/inc/swatrset.hxx
+++ b/sw/inc/swatrset.hxx
@@ -130,6 +130,7 @@ class SvxHangingPunctuationItem;
 class SvxForbiddenRuleItem;
 class SvxParaVertAlignItem;
 class SvxParaGridItem;
+class SvxAutoFrameDirectionItem;
 class SwParaConnectBorderItem;
 
 // TableBox attributes
@@ -322,6 +323,7 @@ public:
     inline const SvxParaVertAlignItem &GetParaVertAlign(bool = true) const;
     inline const SvxParaGridItem        &GetParaGrid(bool = true) const;
     inline const SwParaConnectBorderItem &GetParaConnectBorder(bool = true ) 
const;
+    inline const SvxAutoFrameDirectionItem &GetAutoFrameDirection(bool = true) 
const;
 
     // Tablebox attributes  - implementation in cellatr.hxx
     inline  const SwTableBoxNumFormat       &GetTableBoxNumFormat( bool = true 
) const;
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 341777e80b23..57ed686f8442 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -736,6 +736,7 @@ inline constexpr OUString UNO_NAME_CELL_NAME = 
u"CellName"_ustr;
 inline constexpr OUString UNO_NAME_PARA_USER_DEFINED_ATTRIBUTES = 
u"ParaUserDefinedAttributes"_ustr;
 inline constexpr OUString UNO_NAME_MERGE_LAST_PARA = u"MergeLastPara"_ustr;
 inline constexpr OUString UNO_NAME_WRITING_MODE = u"WritingMode"_ustr;
+inline constexpr OUString UNO_NAME_PARA_WRITING_MODE_AUTOMATIC = 
u"WritingModeAutomatic"_ustr;
 inline constexpr OUString UNO_NAME_GRID_COLOR = u"GridColor"_ustr;
 inline constexpr OUString UNO_NAME_GRID_LINES = u"GridLines"_ustr;
 inline constexpr OUString UNO_NAME_GRID_BASE_HEIGHT = u"GridBaseHeight"_ustr;
diff --git 
a/sw/qa/extras/odfexport/data/tdf162120-style-writing-mode-automatic.fodt 
b/sw/qa/extras/odfexport/data/tdf162120-style-writing-mode-automatic.fodt
new file mode 100644
index 000000000000..bf3cc0283cf9
--- /dev/null
+++ b/sw/qa/extras/odfexport/data/tdf162120-style-writing-mode-automatic.fodt
@@ -0,0 +1,147 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; xmlns:c
 alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"
 xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:officeooo="http://openoffice.org/2009/office"; 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:
 meta:1.0" 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text">
+ 
<office:meta><meta:creation-date>2025-10-30T08:33:30.003457423</meta:creation-date><dc:date>2025-10-31T10:32:54.029847023</dc:date><meta:editing-duration>PT2M18S</meta:editing-duration><meta:editing-cycles>2</meta:editing-cycles><meta:generator>LibreOfficeDev/26.2.0.0.alpha0$Linux_X86_64
 
LibreOffice_project/08b6c9f129d48adf1e4850742651c78f750af488</meta:generator><meta:document-statistic
 meta:table-count="0" meta:image-count="0" meta:object-count="0" 
meta:page-count="1" meta:paragraph-count="4" meta:word-count="21" 
meta:character-count="114" 
meta:non-whitespace-character-count="97"/></office:meta>
+ <office:font-face-decls>
+  <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation 
Serif'" style:font-family-generic="roman" style:font-pitch="variable"/>
+  <style:font-face style:name="Noto Sans1" svg:font-family="'Noto Sans'" 
style:font-family-generic="system" style:font-pitch="variable"/>
+  <style:font-face style:name="Noto Serif CJK SC" svg:font-family="'Noto Serif 
CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+  <style:default-style style:family="graphic">
+   <style:graphic-properties svg:stroke-color="#3465a4" 
draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" 
draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" 
draw:start-line-spacing-vertical="0.283cm" 
draw:end-line-spacing-horizontal="0.283cm" 
draw:end-line-spacing-vertical="0.283cm" style:writing-mode="lr-tb" 
style:flow-with-text="false"/>
+   <style:paragraph-properties style:text-autospace="ideograph-alpha" 
style:line-break="strict" loext:tab-stop-distance="0cm" 
style:font-independent-line-spacing="false">
+    <style:tab-stops/>
+   </style:paragraph-properties>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" 
fo:language="en" fo:country="CA" style:letter-kerning="true" 
style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" 
style:language-asian="zh" style:country-asian="CN" 
style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" 
style:language-complex="hi" style:country-complex="IN"/>
+  </style:default-style>
+  <style:default-style style:family="paragraph">
+   <style:paragraph-properties fo:orphans="2" fo:widows="2" 
fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" 
loext:hyphenation-keep-type="column" loext:hyphenation-keep-line="false" 
style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" 
style:line-break="strict" style:tab-stop-distance="1.251cm" 
style:writing-mode="page"/>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" 
fo:language="en" fo:country="CA" style:letter-kerning="true" 
style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" 
style:language-asian="zh" style:country-asian="CN" 
style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" 
style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" 
fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" 
loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" 
loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/>
+  </style:default-style>
+  <style:default-style style:family="table">
+   <style:table-properties table:border-model="collapsing"/>
+  </style:default-style>
+  <style:default-style style:family="table-row">
+   <style:table-row-properties fo:keep-together="auto"/>
+  </style:default-style>
+  <style:style style:name="Standard" style:family="paragraph" 
style:class="text"/>
+  <style:style style:name="AutoStyle" style:family="paragraph" 
style:parent-style-name="Standard">
+   <style:paragraph-properties style:writing-mode-automatic="true"/>
+  </style:style>
+  <text:outline-style style:name="Outline">
+   <text:outline-level-style text:level="1" loext:num-list-format="%1%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="2" loext:num-list-format="%2%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="3" loext:num-list-format="%3%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="4" loext:num-list-format="%4%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="5" loext:num-list-format="%5%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="6" loext:num-list-format="%6%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="7" loext:num-list-format="%7%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="8" loext:num-list-format="%8%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="9" loext:num-list-format="%9%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="10" loext:num-list-format="%10%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+  </text:outline-style>
+  <text:notes-configuration text:note-class="footnote" style:num-format="1" 
text:start-value="0" text:footnotes-position="page" 
text:start-numbering-at="document"/>
+  <text:notes-configuration text:note-class="endnote" style:num-format="i" 
text:start-value="0"/>
+  <text:linenumbering-configuration text:number-lines="false" 
text:offset="0.499cm" style:num-format="1" text:number-position="left" 
text:increment="5"/>
+  </office:styles>
+ <office:automatic-styles>
+  <style:style style:name="P1" style:family="paragraph" 
style:parent-style-name="Standard">
+   <style:text-properties/>
+  </style:style>
+  <style:style style:name="P2" style:family="paragraph" 
style:parent-style-name="Standard">
+   <style:paragraph-properties style:writing-mode-automatic="true"/>
+   <style:text-properties/>
+  </style:style>
+  <style:style style:name="P3" style:family="paragraph">
+   <style:paragraph-properties style:writing-mode-automatic="true"/>
+  </style:style>
+  <style:style style:name="P4" style:family="paragraph">
+   <loext:graphic-properties draw:fill="none" draw:fill-color="#ffffff"/>
+  </style:style>
+  <style:style style:name="gr1" style:family="graphic">
+   <style:graphic-properties draw:stroke="none" svg:stroke-color="#000000" 
draw:fill="none" draw:fill-color="#ffffff" fo:min-height="11.933cm" 
loext:decorative="false" style:run-through="foreground" 
style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" 
style:vertical-pos="from-top" style:vertical-rel="paragraph" 
style:horizontal-pos="from-left" style:horizontal-rel="paragraph" 
draw:wrap-influence-on-position="once-concurrent" loext:allow-overlap="true" 
style:flow-with-text="false"/>
+   <style:paragraph-properties style:writing-mode="lr-tb"/>
+  </style:style>
+  <style:page-layout style:name="pm1">
+   <style:page-layout-properties fo:page-width="21.59cm" 
fo:page-height="27.94cm" style:num-format="1" 
style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" 
fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" 
style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" 
style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" 
style:layout-grid-mode="none" style:layout-grid-ruby-below="false" 
style:layout-grid-print="false" style:layout-grid-display="false" 
style:footnote-max-height="0cm" loext:margin-gutter="0cm">
+    <style:footnote-sep style:width="0.018cm" 
style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" 
style:line-style="solid" style:adjustment="left" style:rel-width="25%" 
style:color="#000000"/>
+   </style:page-layout-properties>
+   <style:header-style/>
+   <style:footer-style/>
+  </style:page-layout>
+  <style:style style:name="dp1" style:family="drawing-page">
+   <style:drawing-page-properties draw:background-size="full"/>
+  </style:style>
+ </office:automatic-styles>
+ <office:master-styles>
+  <style:master-page style:name="Standard" style:page-layout-name="pm1" 
draw:style-name="dp1"/>
+ </office:master-styles>
+ <office:body>
+  <office:text>
+   <text:sequence-decls>
+    <text:sequence-decl text:display-outline-level="0" 
text:name="Illustration"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Table"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Text"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
+   </text:sequence-decls>
+   <text:p text:style-name="P1">This paragraph is normal</text:p>
+   <text:p text:style-name="P1"/>
+   <text:p text:style-name="P2">This paragraph is auto</text:p>
+   <text:p text:style-name="P1"/>
+   <text:p text:style-name="P1">This paragraph is also normal</text:p>
+   <text:p text:style-name="P1"/>
+   <text:p text:style-name="AutoStyle">This paragraph is auto by a named 
style</text:p>
+   <text:p text:style-name="P1"/>
+   <text:p text:style-name="P1"><draw:frame text:anchor-type="paragraph" 
draw:z-index="0" draw:name="Text Frame 1" draw:style-name="gr1" 
draw:text-style-name="P4" svg:width="15.452cm" svg:height="11.933cm" 
svg:x="0.804cm" svg:y="1.589cm">
+     <draw:text-box>
+      <text:p>This paragraph is normal too</text:p>
+      <text:p/>
+      <text:p text:style-name="P3">But this one is auto</text:p>
+      <text:p/>
+      <text:p>And finally, this one is normal</text:p>
+     </draw:text-box>
+    </draw:frame></text:p>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/odfexport/odfexport4.cxx 
b/sw/qa/extras/odfexport/odfexport4.cxx
index 087e19731391..e7391f1ed17a 100644
--- a/sw/qa/extras/odfexport/odfexport4.cxx
+++ b/sw/qa/extras/odfexport/odfexport4.cxx
@@ -1696,6 +1696,19 @@ CPPUNIT_TEST_FIXTURE(Test, 
testTdf118350StartEndPreserved)
                 "text-align", u"end");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf162120StyleWritingModeAutomaticSerialization)
+{
+    loadAndReload("tdf162120-style-writing-mode-automatic.fodt");
+
+    auto pStylesDoc = parseExport(u"styles.xml"_ustr);
+    assertXPath(pStylesDoc, 
"//style:paragraph-properties[@style:writing-mode-automatic]", 1);
+    assertXPath(pStylesDoc, 
"//style:style[@style:name='AutoStyle']/style:paragraph-properties",
+                "writing-mode-automatic", u"true");
+
+    auto pContentDoc = parseExport(u"content.xml"_ustr);
+    assertXPath(pContentDoc, 
"//style:paragraph-properties[@style:writing-mode-automatic]", 2);
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/qa/extras/uiwriter/data/tdf162120-auto-rtl.fodt 
b/sw/qa/extras/uiwriter/data/tdf162120-auto-rtl.fodt
new file mode 100644
index 000000000000..e5d61c5b3058
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf162120-auto-rtl.fodt
@@ -0,0 +1,122 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/"; 
xmlns:grddl="http://www.w3.org/2003/g/data-view#"; 
xmlns:xhtml="http://www.w3.org/1999/xhtml"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:xsd="http://www.w3.org/2001/XMLSchema"; 
xmlns:xforms="http://www.w3.org/2002/xforms"; 
xmlns:dom="http://www.w3.org/2001/xml-events"; 
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 
xmlns:math="http://www.w3.org/1998/Math/MathML"; 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:ooo="http://openoffice.org/2004/office"; 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 
xmlns:ooow="http://openoffice.org/2004/writer"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
xmlns:drawooo="http://openoffice.org/2010/draw"; 
xmlns:oooc="http://openoffice.org/2004/calc"; 
xmlns:dc="http://purl.org/dc/elements/1.1/"; xmlns:c
 alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 
xmlns:tableooo="http://openoffice.org/2009/table"; 
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 
xmlns:rpt="http://openoffice.org/2005/report"; 
xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"
 xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 
xmlns:officeooo="http://openoffice.org/2009/office"; 
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 
xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:
 meta:1.0" 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0"
 office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text">
+ 
<office:meta><meta:creation-date>2025-11-06T11:23:30.187236969</meta:creation-date><dc:date>2025-11-06T11:30:37.198630783</dc:date><meta:editing-duration>PT4M9S</meta:editing-duration><meta:editing-cycles>2</meta:editing-cycles><meta:generator>LibreOfficeDev/26.2.0.0.alpha0$Linux_X86_64
 
LibreOffice_project/cb898851676f98ce58e79d4ffd1c0081b0003335</meta:generator><meta:document-statistic
 meta:table-count="0" meta:image-count="0" meta:object-count="0" 
meta:page-count="1" meta:paragraph-count="1" meta:word-count="1" 
meta:character-count="2" meta:non-whitespace-character-count="2"/></office:meta>
+ <office:font-face-decls>
+  <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation 
Serif'" style:font-family-generic="roman" style:font-pitch="variable"/>
+  <style:font-face style:name="Noto Sans Arabic" svg:font-family="'Noto Sans 
Arabic'" style:font-adornments="Regular" style:font-family-generic="swiss" 
style:font-pitch="variable"/>
+  <style:font-face style:name="Noto Sans1" svg:font-family="'Noto Sans'" 
style:font-family-generic="system" style:font-pitch="variable"/>
+  <style:font-face style:name="Noto Serif CJK SC" svg:font-family="'Noto Serif 
CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+  <style:default-style style:family="graphic">
+   <style:graphic-properties svg:stroke-color="#3465a4" 
draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" 
draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" 
draw:start-line-spacing-vertical="0.283cm" 
draw:end-line-spacing-horizontal="0.283cm" 
draw:end-line-spacing-vertical="0.283cm" style:writing-mode="lr-tb" 
style:flow-with-text="false"/>
+   <style:paragraph-properties style:text-autospace="ideograph-alpha" 
style:line-break="strict" loext:tab-stop-distance="0cm" 
style:font-independent-line-spacing="false">
+    <style:tab-stops/>
+   </style:paragraph-properties>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" 
fo:language="en" fo:country="CA" style:letter-kerning="true" 
style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" 
style:language-asian="zh" style:country-asian="CN" 
style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" 
style:language-complex="hi" style:country-complex="IN"/>
+  </style:default-style>
+  <style:default-style style:family="paragraph">
+   <style:paragraph-properties fo:orphans="2" fo:widows="2" 
fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" 
loext:hyphenation-keep-type="column" loext:hyphenation-keep-line="false" 
style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" 
style:line-break="strict" style:tab-stop-distance="1.251cm" 
style:writing-mode="page"/>
+   <style:text-properties style:use-window-font-color="true" 
loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" 
fo:language="en" fo:country="CA" style:letter-kerning="true" 
style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" 
style:language-asian="zh" style:country-asian="CN" 
style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" 
style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" 
fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" 
loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" 
loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/>
+  </style:default-style>
+  <style:default-style style:family="table">
+   <style:table-properties table:border-model="collapsing"/>
+  </style:default-style>
+  <style:default-style style:family="table-row">
+   <style:table-row-properties fo:keep-together="auto"/>
+  </style:default-style>
+  <style:style style:name="Standard" style:family="paragraph" 
style:class="text">
+   <style:paragraph-properties fo:text-align="start" 
style:justify-single-word="false" style:writing-mode-automatic="true"/>
+   <style:text-properties style:font-name-complex="Noto Sans Arabic" 
style:font-family-complex="'Noto Sans Arabic'" 
style:font-style-name-complex="Regular" 
style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" 
style:language-complex="ar" style:country-complex="EG"/>
+  </style:style>
+  <text:outline-style style:name="Outline">
+   <text:outline-level-style text:level="1" loext:num-list-format="%1%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="2" loext:num-list-format="%2%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="3" loext:num-list-format="%3%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="4" loext:num-list-format="%4%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="5" loext:num-list-format="%5%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="6" loext:num-list-format="%6%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="7" loext:num-list-format="%7%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="8" loext:num-list-format="%8%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="9" loext:num-list-format="%9%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+   <text:outline-level-style text:level="10" loext:num-list-format="%10%" 
style:num-format="">
+    <style:list-level-properties 
text:list-level-position-and-space-mode="label-alignment">
+     <style:list-level-label-alignment text:label-followed-by="listtab"/>
+    </style:list-level-properties>
+   </text:outline-level-style>
+  </text:outline-style>
+  <text:notes-configuration text:note-class="footnote" style:num-format="1" 
text:start-value="0" text:footnotes-position="page" 
text:start-numbering-at="document"/>
+  <text:notes-configuration text:note-class="endnote" style:num-format="i" 
text:start-value="0"/>
+  <text:linenumbering-configuration text:number-lines="false" 
text:offset="0.499cm" style:num-format="1" text:number-position="left" 
text:increment="5"/>
+  </office:styles>
+ <office:automatic-styles>
+  <style:style style:name="P1" style:family="paragraph" 
style:parent-style-name="Standard">
+   <style:paragraph-properties style:writing-mode="rl-tb"/>
+   <style:text-properties style:language-complex="ar" 
style:country-complex="EG"/>
+  </style:style>
+  <style:style style:name="T1" style:family="text">
+   <style:text-properties fo:language="en" fo:country="US"/>
+  </style:style>
+  <style:page-layout style:name="pm1">
+   <style:page-layout-properties fo:page-width="21.59cm" 
fo:page-height="27.94cm" style:num-format="1" 
style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" 
fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" 
style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" 
style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" 
style:layout-grid-mode="none" style:layout-grid-ruby-below="false" 
style:layout-grid-print="false" style:layout-grid-display="false" 
style:footnote-max-height="0cm" loext:margin-gutter="0cm">
+    <style:footnote-sep style:width="0.018cm" 
style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" 
style:line-style="solid" style:adjustment="left" style:rel-width="25%" 
style:color="#000000"/>
+   </style:page-layout-properties>
+   <style:header-style/>
+   <style:footer-style/>
+  </style:page-layout>
+  <style:style style:name="dp1" style:family="drawing-page">
+   <style:drawing-page-properties draw:background-size="full"/>
+  </style:style>
+ </office:automatic-styles>
+ <office:master-styles>
+  <style:master-page style:name="Standard" style:page-layout-name="pm1" 
draw:style-name="dp1"/>
+ </office:master-styles>
+ <office:body>
+  <office:text>
+   <text:sequence-decls>
+    <text:sequence-decl text:display-outline-level="0" 
text:name="Illustration"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Table"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Text"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
+    <text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
+   </text:sequence-decls>
+   <text:p text:style-name="P1">ا<text:span 
text:style-name="T1">a</text:span></text:p>
+  </office:text>
+ </office:body>
+</office:document>
\ No newline at end of file
diff --git a/sw/qa/extras/uiwriter/uiwriter11.cxx 
b/sw/qa/extras/uiwriter/uiwriter11.cxx
index 5e4d2b10e5b9..cc642e56d600 100644
--- a/sw/qa/extras/uiwriter/uiwriter11.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter11.cxx
@@ -374,6 +374,29 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testTdf108791)
     }
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testTdf162120AutoRTL)
+{
+    createSwDoc("tdf162120-auto-rtl.fodt");
+    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+
+    // The initial direction should be RTL
+    CPPUNIT_ASSERT_EQUAL(short(1),
+                         getProperty<short>(getRun(getParagraph(1), 1), 
u"WritingMode"_ustr));
+
+    // Insert a strong LTR character at the start of the paragraph.
+    // The writing mode should automatically switch to LTR.
+    pWrtShell->Insert(u"a"_ustr);
+    CPPUNIT_ASSERT_EQUAL(short(0),
+                         getProperty<short>(getRun(getParagraph(1), 1), 
u"WritingMode"_ustr));
+
+    // Delete the leading LTR character.
+    // The writing mode should switch back to RTL.
+    pWrtShell->DelLeft();
+    CPPUNIT_ASSERT_EQUAL(short(1),
+                         getProperty<short>(getRun(getParagraph(1), 1), 
u"WritingMode"_ustr));
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/qa/uitest/styleInspector/styleInspector.py 
b/sw/qa/uitest/styleInspector/styleInspector.py
index a9ab1fc940ee..1f044dfc4dec 100644
--- a/sw/qa/uitest/styleInspector/styleInspector.py
+++ b/sw/qa/uitest/styleInspector/styleInspector.py
@@ -26,7 +26,7 @@ class styleNavigator(UITestCase):
             # The cursor is on text without formatting and default style
             self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
-            self.assertEqual(155, 
len(xListBox.getChild('0').getChild('0').getChildren()))
+            self.assertEqual(156, 
len(xListBox.getChild('0').getChild('0').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
@@ -36,7 +36,7 @@ class styleNavigator(UITestCase):
             # The cursor is on text with direct formatting
             self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
-            self.assertEqual(155, 
len(xListBox.getChild('0').getChild('0').getChildren()))
+            self.assertEqual(156, 
len(xListBox.getChild('0').getChild('0').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
 
@@ -54,7 +54,7 @@ class styleNavigator(UITestCase):
             # The cursor is on text with paragraph direct formatting
             self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
-            self.assertEqual(155, 
len(xListBox.getChild('0').getChild('0').getChildren()))
+            self.assertEqual(156, 
len(xListBox.getChild('0').getChild('0').getChildren()))
 
             xParDirFormatting = xListBox.getChild('1')
             self.assertEqual(7, len(xParDirFormatting.getChildren()))
@@ -75,7 +75,7 @@ class styleNavigator(UITestCase):
             xParStyle = xListBox.getChild('0')
             self.assertEqual(3, len(xParStyle.getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xParStyle.getChild('0'))['Text'])
-            self.assertEqual(155, len(xParStyle.getChild('0').getChildren()))
+            self.assertEqual(156, len(xParStyle.getChild('0').getChildren()))
             self.assertEqual("Heading  ", 
get_state_as_dict(xParStyle.getChild('1'))['Text'])
             self.assertEqual(28, len(xParStyle.getChild('1').getChildren()))
 
@@ -116,7 +116,7 @@ class styleNavigator(UITestCase):
             xParStyle = xListBox.getChild('0')
             self.assertEqual(3, len(xParStyle.getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xParStyle.getChild('0'))['Text'])
-            self.assertEqual(155, len(xParStyle.getChild('0').getChildren()))
+            self.assertEqual(156, len(xParStyle.getChild('0').getChildren()))
             self.assertEqual("Body Text        ", 
get_state_as_dict(xParStyle.getChild('1'))['Text'])
             self.assertEqual(6, len(xParStyle.getChild('1').getChildren()))
 
@@ -151,7 +151,7 @@ class styleNavigator(UITestCase):
             # The cursor is on text without metadata
             self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
-            self.assertEqual(155, 
len(xListBox.getChild('0').getChild('0').getChildren()))
+            self.assertEqual(156, 
len(xListBox.getChild('0').getChild('0').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
@@ -161,7 +161,7 @@ class styleNavigator(UITestCase):
             # The cursor is on text with paragraph metadata showed under 
direct paragraph formatting
             self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
-            self.assertEqual(155, 
len(xListBox.getChild('0').getChild('0').getChildren()))
+            self.assertEqual(156, 
len(xListBox.getChild('0').getChild('0').getChildren()))
 
             xParDirFormatting = xListBox.getChild('1')
             self.assertEqual(1, len(xParDirFormatting.getChildren()))
@@ -214,7 +214,7 @@ class styleNavigator(UITestCase):
             # The cursor is on text without metadata
             self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
-            self.assertEqual(155, 
len(xListBox.getChild('0').getChild('0').getChildren()))
+            self.assertEqual(156, 
len(xListBox.getChild('0').getChild('0').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
@@ -224,7 +224,7 @@ class styleNavigator(UITestCase):
             # The cursor is on text with paragraph metadata showed under 
direct paragraph formatting
             self.assertEqual(1, len(xListBox.getChild('1').getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xListBox.getChild('1').getChild('0'))['Text'])
-            self.assertEqual(155, 
len(xListBox.getChild('1').getChild('0').getChildren()))
+            self.assertEqual(156, 
len(xListBox.getChild('1').getChild('0').getChildren()))
 
             # Outer bookmark
             xBookmarkFormatting = xListBox.getChild('0')
@@ -271,7 +271,7 @@ class styleNavigator(UITestCase):
             # The cursor is on text without metadata
             self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
-            self.assertEqual(155, 
len(xListBox.getChild('0').getChild('0').getChildren()))
+            self.assertEqual(156, 
len(xListBox.getChild('0').getChild('0').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
             self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
 
diff --git a/sw/qa/uitest/styleInspector/tdf137513.py 
b/sw/qa/uitest/styleInspector/tdf137513.py
index b615f8af8d2b..b5271f487593 100644
--- a/sw/qa/uitest/styleInspector/tdf137513.py
+++ b/sw/qa/uitest/styleInspector/tdf137513.py
@@ -35,7 +35,7 @@ class tdf137513(UITestCase):
             self.assertEqual(2, len(xListBox.getChild('0').getChildren()))
             self.assertEqual("Default Paragraph Style  ", 
get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
             self.assertEqual("Table Contents   ", 
get_state_as_dict(xListBox.getChild('0').getChild('1'))['Text'])
-            self.assertEqual(155, 
len(xListBox.getChild('0').getChild('0').getChildren()))
+            self.assertEqual(156, 
len(xListBox.getChild('0').getChild('0').getChildren()))
 
             xTableContent = xListBox.getChild('0').getChild('1')
             self.assertEqual(5, len(xTableContent.getChildren()))
diff --git a/sw/source/core/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx
index 21a5cc10c32f..bfc29059a774 100644
--- a/sw/source/core/bastyp/init.cxx
+++ b/sw/source/core/bastyp/init.cxx
@@ -26,6 +26,7 @@
 #include <comphelper/processfactory.hxx>
 #include <doc.hxx>
 #include <editeng/acorrcfg.hxx>
+#include <editeng/autodiritem.hxx>
 #include <editeng/autokernitem.hxx>
 #include <editeng/blinkitem.hxx>
 #include <editeng/boxitem.hxx>
@@ -376,6 +377,7 @@ std::unique_ptr<ItemInfoPackage> 
createItemInfoPackageSwAttributes()
             { RES_PARATR_SNAPTOGRID, new SvxParaGridItem( true, 
RES_PARATR_SNAPTOGRID ), SID_ATTR_PARA_SNAPTOGRID, SFX_ITEMINFOFLAG_NONE },
             { RES_PARATR_CONNECT_BORDER, new SwParaConnectBorderItem, 
SID_ATTR_BORDER_CONNECT, SFX_ITEMINFOFLAG_NONE },
             { RES_PARATR_OUTLINELEVEL, new SfxUInt16Item( 
RES_PARATR_OUTLINELEVEL, 0 ), SID_ATTR_PARA_OUTLINE_LEVEL, 
SFX_ITEMINFOFLAG_NONE },
+            { RES_PARATR_AUTOFRAMEDIR, new SvxAutoFrameDirectionItem( false, 
RES_PARATR_AUTOFRAMEDIR ), SID_ATTR_PARA_AUTOFRAMEDIRECTION, 
SFX_ITEMINFOFLAG_NONE },
             { RES_PARATR_RSID, new SvxRsidItem( 0, RES_PARATR_RSID ), 0, 
SFX_ITEMINFOFLAG_NONE },
             { RES_PARATR_GRABBAG, new SfxGrabBagItem( RES_PARATR_GRABBAG ), 
SID_ATTR_PARA_GRABBAG, SFX_ITEMINFOFLAG_NONE },
 
diff --git a/sw/source/core/doc/dbgoutsw.cxx b/sw/source/core/doc/dbgoutsw.cxx
index cfb85bb2b291..3e54aa44a8f3 100644
--- a/sw/source/core/doc/dbgoutsw.cxx
+++ b/sw/source/core/doc/dbgoutsw.cxx
@@ -159,6 +159,7 @@ static std::map<sal_uInt16,OUString> & GetItemWhichMap()
         { RES_PARATR_VERTALIGN , "PARATR_VERTALIGN" },
         { RES_PARATR_SNAPTOGRID , "PARATR_SNAPTOGRID" },
         { RES_PARATR_CONNECT_BORDER , "PARATR_CONNECT_BORDER" },
+        { RES_PARATR_AUTOFRAMEDIR, "PARATR_AUTOFRAMEDIR" },
         { RES_FILL_ORDER , "FILL_ORDER" },
         { RES_FRM_SIZE , "FRM_SIZE" },
         { RES_PAPER_BIN , "PAPER_BIN" },
diff --git a/sw/source/core/edit/eddel.cxx b/sw/source/core/edit/eddel.cxx
index 654b9b0fb547..bcf151df3b37 100644
--- a/sw/source/core/edit/eddel.cxx
+++ b/sw/source/core/edit/eddel.cxx
@@ -164,6 +164,9 @@ bool SwEditShell::Delete(bool const isArtificialSelection, 
bool goLeft)
             DeleteSel(rPaM, isArtificialSelection, goLeft, &bUndo);
         }
 
+        // tdf#162120: Automatically adjust paragraph directions after delete
+        UpdateSelectionAutoParaDirection();
+
         // If undo container then close here
         if( bUndo )
         {
diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx
index 9a69d60e1565..742f4c7e22cf 100644
--- a/sw/source/core/edit/editsh.cxx
+++ b/sw/source/core/edit/editsh.cxx
@@ -24,6 +24,9 @@
 #include <comphelper/processfactory.hxx>
 #include <comphelper/string.hxx>
 #include <unotools/transliterationwrapper.hxx>
+#include <i18nutil/guessparadirection.hxx>
+#include <editeng/autodiritem.hxx>
+#include <editeng/frmdiritem.hxx>
 #include <fmtsrnd.hxx>
 #include <fmtinfmt.hxx>
 #include <txtinet.hxx>
@@ -59,6 +62,58 @@
 
 using namespace com::sun::star;
 
+void SwEditShell::UpdateSelectionAutoParaDirection()
+{
+    for (SwPaM& rPaM : getShellCursor(true)->GetRingContainer())
+    {
+        auto* pNode = rPaM.GetPointNode().GetTextNode();
+        if (!pNode)
+        {
+            continue;
+        }
+
+        const SvxAutoFrameDirectionItem* pAutoItem
+            = pNode->GetSwAttrSet().GetItemIfSet(RES_PARATR_AUTOFRAMEDIR);
+        if (!pAutoItem || !pAutoItem->GetValue())
+        {
+            continue;
+        }
+
+        Point aPt;
+        std::pair<Point, bool> const tmp(aPt, false);
+        const SwTextFrame* pFrame
+            = static_cast<SwTextFrame*>(pNode->getLayoutFrame(GetLayout(), 
rPaM.GetPoint(), &tmp));
+
+        bool bIsAlreadyRtl = pFrame->IsRightToLeft();
+
+        bool bShouldBeRtl = bIsAlreadyRtl;
+        switch (i18nutil::GuessParagraphDirection(pNode->GetText()))
+        {
+            case i18nutil::ParagraphDirection::Ambiguous:
+                bShouldBeRtl = bIsAlreadyRtl;
+                break;
+
+            case i18nutil::ParagraphDirection::LeftToRight:
+                bShouldBeRtl = false;
+                break;
+
+            case i18nutil::ParagraphDirection::RightToLeft:
+                bShouldBeRtl = true;
+                break;
+        }
+
+        if (bShouldBeRtl == bIsAlreadyRtl)
+        {
+            continue;
+        }
+
+        SvxFrameDirection eNeeded = bShouldBeRtl ? 
SvxFrameDirection::Horizontal_RL_TB
+                                                 : 
SvxFrameDirection::Horizontal_LR_TB;
+        rPaM.GetDoc().getIDocumentContentOperations().InsertPoolItem(
+            rPaM, SvxFrameDirectionItem{ eNeeded, RES_FRAMEDIR });
+    }
+}
+
 void SwEditShell::Insert( sal_Unicode c, bool bOnlyCurrCursor )
 {
     StartAllAction();
@@ -73,6 +128,9 @@ void SwEditShell::Insert( sal_Unicode c, bool 
bOnlyCurrCursor )
 
     }
 
+    // tdf#162120: Automatically adjust paragraph direction after insert
+    UpdateSelectionAutoParaDirection();
+
     EndAllAction();
 }
 
@@ -162,6 +220,9 @@ void SwEditShell::Insert2(const OUString &rStr, const bool 
bForceExpandHints )
 
     SetInFrontOfLabel( false ); // #i27615#
 
+    // tdf#162120: Automatically adjust paragraph direction after insert
+    UpdateSelectionAutoParaDirection();
+
     EndAllAction();
 }
 
@@ -978,6 +1039,9 @@ OUString SwEditShell::DeleteExtTextInput( bool bInsText )
         if ( ! bInsText && IsOverwriteCursor() )
             *GetCursor()->GetPoint() = aPos;
 
+        // tdf#162120: Automatically adjust paragraph direction after insert
+        UpdateSelectionAutoParaDirection();
+
         EndAllAction();
     }
     return sRet;
diff --git a/sw/source/core/unocore/unomapproperties.hxx 
b/sw/source/core/unocore/unomapproperties.hxx
index 0e6ee62e52af..e2dfba35bf15 100644
--- a/sw/source/core/unocore/unomapproperties.hxx
+++ b/sw/source/core/unocore/unomapproperties.hxx
@@ -255,6 +255,7 @@
         { UNO_NAME_CHAR_SHADING_VALUE,                  RES_CHRATR_BACKGROUND, 
        cppu::UnoType<sal_Int32>::get(),         PROPERTY_NONE,                
MID_SHADING_VALUE                      }, \
         { UNO_NAME_PARA_INTEROP_GRAB_BAG,               RES_PARATR_GRABBAG,    
        cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> 
>::get(), PROPERTY_NONE,                0                                      
}, \
         { UNO_NAME_CHAR_SCRIPT_HINT,                    
RES_CHRATR_SCRIPT_HINT,        cppu::UnoType<sal_Int16>::get(),        
PropertyAttribute::MAYBEVOID, MID_SCRIPTHINT }, \
+        { UNO_NAME_PARA_WRITING_MODE_AUTOMATIC,         
RES_PARATR_AUTOFRAMEDIR,       cppu::UnoType<bool>::get(),       
PropertyAttribute::MAYBEVOID, 0 }, \
 
 #define COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN \
         COMMON_CRSR_PARA_PROPERTIES_WITHOUT_FN_01 \
@@ -547,7 +548,8 @@
                     { UNO_NAME_OUTLINE_LEVEL, 
RES_PARATR_OUTLINELEVEL,cppu::UnoType<sal_Int16>::get(), 
PropertyAttribute::MAYBEVOID, 0}, \
                     { UNO_NAME_HIDDEN, FN_UNO_HIDDEN,     
cppu::UnoType<bool>::get(), PROPERTY_NONE, 0}, \
                     { UNO_NAME_STYLE_INTEROP_GRAB_BAG, 
FN_UNO_STYLE_INTEROP_GRAB_BAG, cppu::UnoType< 
cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0}, \
-                    { UNO_NAME_PARA_INTEROP_GRAB_BAG, RES_PARATR_GRABBAG, 
cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), 
PROPERTY_NONE, 0},
+                    { UNO_NAME_PARA_INTEROP_GRAB_BAG, RES_PARATR_GRABBAG, 
cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), 
PROPERTY_NONE, 0}, \
+                    { UNO_NAME_PARA_WRITING_MODE_AUTOMATIC, 
RES_PARATR_AUTOFRAMEDIR, cppu::UnoType<bool>::get(), 
PropertyAttribute::MAYBEVOID, 0},
 
 #define COMMON_ACCESSIBILITY_TEXT_ATTRIBUTE \
                     { UNO_NAME_CHAR_BACK_COLOR, RES_CHRATR_BACKGROUND,    
cppu::UnoType<sal_Int32>::get(),           PROPERTY_NONE ,MID_BACK_COLOR }, \
diff --git a/sw/source/filter/html/css1atr.cxx 
b/sw/source/filter/html/css1atr.cxx
index 85d5368a3dfb..fa4f4fec235e 100644
--- a/sw/source/filter/html/css1atr.cxx
+++ b/sw/source/filter/html/css1atr.cxx
@@ -3484,6 +3484,7 @@ SwAttrFnTab const aCSS1AttrFnTab = {
 /* RES_PARATR_SNAPTOGRID*/          nullptr, // new
 /* RES_PARATR_CONNECT_TO_BORDER */  nullptr, // new
 /* RES_PARATR_OUTLINELEVEL */       nullptr, // new since cws outlinelevel
+/* RES_PARATR_AUTOFRAMEDIR */       nullptr,
 /* RES_PARATR_RSID */               nullptr, // new
 /* RES_PARATR_GRABBAG */            nullptr,
 
diff --git a/sw/source/filter/html/htmlatr.cxx 
b/sw/source/filter/html/htmlatr.cxx
index 026d6c1060f7..1a5b991efd12 100644
--- a/sw/source/filter/html/htmlatr.cxx
+++ b/sw/source/filter/html/htmlatr.cxx
@@ -3361,6 +3361,7 @@ const SwAttrFnTab aHTMLAttrFnTab = {
 /* RES_PARATR_SNAPTOGRID*/          nullptr, // new
 /* RES_PARATR_CONNECT_TO_BORDER */  nullptr, // new
 /* RES_PARATR_OUTLINELEVEL */       nullptr,
+/* RES_PARATR_AUTOFRAMEDIR */       nullptr,
 /* RES_PARATR_RSID */               nullptr,
 /* RES_PARATR_GRABBAG */            nullptr,
 
diff --git a/sw/source/uibase/shells/txtattr.cxx 
b/sw/source/uibase/shells/txtattr.cxx
index eee4503fb501..8197b5682323 100644
--- a/sw/source/uibase/shells/txtattr.cxx
+++ b/sw/source/uibase/shells/txtattr.cxx
@@ -26,6 +26,7 @@
 #include <sfx2/bindings.hxx>
 #include <sfx2/request.hxx>
 #include <sfx2/viewfrm.hxx>
+#include <editeng/autodiritem.hxx>
 #include <editeng/fhgtitem.hxx>
 #include <editeng/adjustitem.hxx>
 #include <editeng/lspcitem.hxx>
@@ -327,6 +328,7 @@ void SwTextShell::ExecParaAttr(SfxRequest &rReq)
     // Get both attributes immediately isn't more expensive!!
     SfxItemSet aSet(SfxItemSet::makeFixedSfxItemSet<RES_PARATR_LINESPACING, 
RES_PARATR_ADJUST,
                                                     RES_PARATR_HYPHENZONE, 
RES_PARATR_HYPHENZONE,
+                                                    RES_PARATR_AUTOFRAMEDIR, 
RES_PARATR_AUTOFRAMEDIR,
                                                     RES_FRAMEDIR, 
RES_FRAMEDIR>(GetPool()));
     sal_uInt16 nSlot = rReq.GetSlot();
     switch (nSlot)
@@ -406,6 +408,10 @@ SET_LINESPACE:
                         SvxFrameDirection::Horizontal_LR_TB : 
SvxFrameDirection::Horizontal_RL_TB;
             aSet.Put( SvxFrameDirectionItem( eFrameDirection, RES_FRAMEDIR ) );
 
+            // tdf#162120: The paragraph direction has been manually set by 
the user.
+            // Don't automatically adjust the paragraph direction anymore.
+            aSet.Put(SvxAutoFrameDirectionItem(false, 
RES_PARATR_AUTOFRAMEDIR));
+
             if (bChgAdjust)
             {
                 SvxAdjust eAdjust = (SID_ATTR_PARA_LEFT_TO_RIGHT == nSlot) ?
diff --git a/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx 
b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
index 33a27b191cac..e8eb46377abd 100644
--- a/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
+++ b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
@@ -339,6 +339,7 @@ static OUString PropertyNametoRID(const OUString& rName)
         { "UnvisitedCharStyleName", RID_UNVISITED_CHAR_STYLE_NAME },
         { "VisitedCharStyleName", RID_VISITED_CHAR_STYLE_NAME },
         { "WritingMode", RID_WRITING_MODE },
+        { "WritingModeAutomatic", RID_WRITING_MODE_AUTOMATIC },
         { "BorderColor", RID_BORDER_COLOR },
         { "BorderInnerLineWidth", RID_BORDER_INNER_LINE_WIDTH },
         { "BorderLineDistance", RID_BORDER_LINE_DISTANCE },
diff --git a/xmloff/inc/xmlprop.hxx b/xmloff/inc/xmlprop.hxx
index 657ddf1eeae8..689220a4819e 100644
--- a/xmloff/inc/xmlprop.hxx
+++ b/xmloff/inc/xmlprop.hxx
@@ -691,6 +691,7 @@ inline constexpr OUString PROP_WidthType = 
u"WidthType"_ustr;
 inline constexpr OUString PROP_WrapInfluenceOnPosition = 
u"WrapInfluenceOnPosition"_ustr;
 inline constexpr OUString PROP_WrapTextAtFlyStart = u"WrapTextAtFlyStart"_ustr;
 inline constexpr OUString PROP_WritingMode = u"WritingMode"_ustr;
+inline constexpr OUString PROP_WritingModeAutomatic = 
u"WritingModeAutomatic"_ustr;
 inline constexpr OUString PROP_XName = u"XName"_ustr;
 inline constexpr OUString PROP_YName = u"YName"_ustr;
 
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 4b8c63d5936c..f8cfdddf335a 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -2227,6 +2227,7 @@ namespace xmloff::token {
         TOKEN( "wrap-contour-mode",               XML_WRAP_CONTOUR_MODE ),
         TOKEN( "wrap-option",                     XML_WRAP_OPTION ),
         TOKEN( "writing-mode",                    XML_WRITING_MODE ),
+        TOKEN( "writing-mode-automatic",          XML_WRITING_MODE_AUTOMATIC ),
         TOKEN( "www",                             XML_WWW ),
         TOKEN( "x",                               XML_X ),
         TOKEN( "x1",                              XML_X1 ),
diff --git a/xmloff/source/text/txtprmap.cxx b/xmloff/source/text/txtprmap.cxx
index 593006cf0ec3..f239a75b32a1 100644
--- a/xmloff/source/text/txtprmap.cxx
+++ b/xmloff/source/text/txtprmap.cxx
@@ -465,6 +465,9 @@ XMLPropertyMapEntry constexpr aXMLParaPropMap[] =
 
     MP_ED( PROP_WritingMode, XML_NAMESPACE_STYLE, XML_WRITING_MODE, 
XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT, CTF_TEXTWRITINGMODE ),
 
+    // RES_PARATR_AUTOFRAMEDIR
+    MP_E( PROP_WritingModeAutomatic, XML_NAMESPACE_STYLE, 
XML_WRITING_MODE_AUTOMATIC, XML_TYPE_BOOL, 0 ),
+
     MP_E( PROP_ParaIsConnectBorder, XML_NAMESPACE_STYLE, XML_JOIN_BORDER, 
XML_TYPE_BOOL, 0 ),
 
     MP_E( PROP_DefaultOutlineLevel, XML_NAMESPACE_STYLE, 
XML_DEFAULT_OUTLINE_LEVEL, 
XML_TYPE_TEXT_NUMBER8_ONE_BASED|MID_FLAG_SPECIAL_ITEM_EXPORT|MID_FLAG_NO_PROPERTY_IMPORT,
 CTF_DEFAULT_OUTLINE_LEVEL ),
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index 9576187b7522..28317a175325 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -2127,6 +2127,7 @@ wrap-contour
 wrap-contour-mode
 wrap-option
 writing-mode
+writing-mode-automatic
 www
 x
 x1

Reply via email to