sw/qa/extras/ooxmlexport/ooxmlexport22.cxx         |   11 ---
 sw/source/filter/ww8/docxattributeoutput.cxx       |   69 +++++++++++++++++++++
 sw/source/writerfilter/dmapper/StyleSheetTable.cxx |   10 +++
 3 files changed, 82 insertions(+), 8 deletions(-)

New commits:
commit e6a5de6f14cb2414e2f76b5a9d5a68dd28fff3ff
Author:     Justin Luth <jl...@mail.com>
AuthorDate: Sat Aug 9 10:40:42 2025 -0400
Commit:     Justin Luth <jl...@mail.com>
CommitDate: Wed Aug 13 03:07:41 2025 +0200

    tdf#167721 writerfilter styles: adjust leftChars by hangingChars
    
    Fifth Problem - styles import needs to adjust the left margin
    just like the paragraph import does.
    
    The way MS implements "hanging"
    is that w:hanging defines where the first line starts
    and w:left defines how much further the remaining lines start.
    
    This is opposed to "firstLine"
    where w:firstLine defines the additional indent for the first line
    and w:left defines where the entire paragraph's indent.
    
    LO's implementation is much nicer, where the left margin
    always defines the entire paragraph's indent.
    
    make CppunitTest_sw_ooxmlexport22 \
        CPPUNIT_TEST_NAME=testTdf167721_chUnits
    
    Change-Id: I6ac4b49350d33d31d0948530910b4d4712bdc403
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189269
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <jl...@mail.com>

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx
index 5384f0bd9145..3ceeb86c3d98 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx
@@ -274,7 +274,7 @@ CPPUNIT_TEST_FIXTURE(Test, 
testTdf166553_paraStyleAfterBreak)
     CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xPara, 
u"CharWeight"_ustr));
 }
 
-CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits)
+DECLARE_OOXMLEXPORT_TEST(testTdf167721_chUnits, "tdf167721_chUnits.docx")
 {
     // given a document that specifies some margins using Ch-based Left/Right 
indentation
     // where w:rightChars is inherited from the parent styles - so it 
overrides w:right
@@ -286,8 +286,6 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits)
     // inherited formatting from the style chain in styles.xml
     //     <w:ind w:rightChars="200" (2 ic) w:hangingChars=400 (4 ic)
     //            w:leftChars="300" (3 ic) w:left="2834"/> (5 cm)
-    createSwDoc("tdf167721_chUnits.docx");
-    // saveAndReload(mpFilter);
 
     // Test the style 
#############################################################################
     uno::Reference<beans::XPropertySet> xStyle(
@@ -300,7 +298,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits)
 
     auto aLeftCh
         = getProperty<css::beans::Pair<double, sal_Int16>>(xStyle, 
u"ParaLeftMarginUnit"_ustr);
-    CPPUNIT_ASSERT_EQUAL(double(3), aLeftCh.First);
+    CPPUNIT_ASSERT_EQUAL(double(7), aLeftCh.First);
 
     auto aRightCh
         = getProperty<css::beans::Pair<double, sal_Int16>>(xStyle, 
u"ParaRightMarginUnit"_ustr);
diff --git a/sw/source/writerfilter/dmapper/StyleSheetTable.cxx 
b/sw/source/writerfilter/dmapper/StyleSheetTable.cxx
index ee3c28e7f907..7e46ae555a1b 100644
--- a/sw/source/writerfilter/dmapper/StyleSheetTable.cxx
+++ b/sw/source/writerfilter/dmapper/StyleSheetTable.cxx
@@ -1381,6 +1381,16 @@ void StyleSheetTable::ApplyStyleSheetsImpl(const 
FontTablePtr& rFontTable, std::
                                             == 
getPropertyName(PROP_PARA_FIRST_LINE_INDENT_UNIT);
                                     });
                                 }
+
+                                // hanging margins need to alter the left 
margin
+                                if (bLeftChSet && stFirstCh.First < 0.0)
+                                {
+                                    stLeftCh.First -= stFirstCh.First;
+                                    beans::PropertyValue aPV(
+                                        
getPropertyName(PROP_PARA_LEFT_MARGIN_UNIT), 0,
+                                        uno::Any(stLeftCh), 
beans::PropertyState_DIRECT_VALUE);
+                                    aPropValues.push_back(aPV);
+                                }
                             }
 
                             if (bFirstSet && bFirstChSet)
commit 30791dd5105d2ab088dbd296256357cd04a1feff
Author:     Justin Luth <jl...@mail.com>
AuthorDate: Sat Aug 9 08:35:22 2025 -0400
Commit:     Justin Luth <jl...@mail.com>
CommitDate: Wed Aug 13 03:07:34 2025 +0200

    tdf#167721 docx export: add w:left=0 when w:leftChars=0
    
    Setting w:leftChars to zero means that it is disabled.
    It will use w:left instead.
    
    Since w:left could otherwise be inherited from the paragraph style,
    make sure that it is specified as zero.
    
    Change-Id: I9b14d96aae4b5128e3dc490a57022832eee9b2f0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189268
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <jl...@mail.com>

diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index f3f91c09d114..034522181382 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -9413,6 +9413,10 @@ void 
DocxAttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rF
         {
             AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, XML_firstLineChars),
                           OString::number(stValue.m_dValue * 100.0));
+
+            // handle special value "zero" which disables firstLineChars
+            if (stValue.m_dValue == 0.0)
+                AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, XML_firstLine), 
OString::number(0));
         }
         else
         {
@@ -9501,6 +9505,11 @@ void 
DocxAttributeOutput::FormatTextLeftMargin(SvxTextLeftMarginItem const& rTex
 
         AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, (bEcma1st ? 
XML_leftChars : XML_startChars)),
                       OString::number(stValue.m_dValue * 100.0));
+
+        // handle special value "zero" which disables leftChars
+        if (stValue.m_dValue == 0.0)
+            AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, (bEcma1st ? XML_left 
: XML_start)),
+                  OString::number(0));
         return;
     }
 
@@ -9536,6 +9545,11 @@ void 
DocxAttributeOutput::FormatRightMargin(SvxRightMarginItem const& rRightMarg
     {
         AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, (bEcma1st ? 
XML_rightChars : XML_endChars)),
                       OString::number(stValue.m_dValue * 100.0));
+
+        // handle special value "zero" which disables rightChars
+        if (stValue.m_dValue == 0.0)
+            AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, (bEcma1st ? 
XML_right : XML_end)),
+                  OString::number(0));
         return;
     }
 
commit 9be90060e67ca0f2eeb0c5acb2d33dd3a9730d85
Author:     Justin Luth <jl...@mail.com>
AuthorDate: Sat Aug 9 11:23:23 2025 -0400
Commit:     Justin Luth <jl...@mail.com>
CommitDate: Wed Aug 13 03:07:26 2025 +0200

    tdf#167721 docx export: disable inherited leftChars when writing w:left
    
    There are two w:ind items that can affect the left margin,
    and leftChars has the priority.
    
    So if the parent style's left margin was written as a leftChars,
    then a non-leftChars w:left needs to also disable w:leftChars.
    
    make CppunitTest_sw_ooxmlexport22 \
        CPPUNIT_TEST_NAME=testTdf167721_chUnits3
    
    Change-Id: Ie0126ea5e5409907d4edc999ec13ac5f667aa682
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189267
    Reviewed-by: Justin Luth <jl...@mail.com>
    Tested-by: Jenkins

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx
index c94b6f7ef551..5384f0bd9145 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx
@@ -375,7 +375,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits2)
     CPPUNIT_ASSERT_EQUAL(double(2), aRightCh.First);
 }
 
-CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits3)
+DECLARE_OOXMLEXPORT_TEST(testTdf167721_chUnits3, "tdf167721_chUnits3.docx")
 {
     // given a nasty edge-case document
     // Style "List Paragraph": left = 2 inch, right = 2 cm, first line = none
@@ -385,9 +385,6 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits3)
     // Paragraph: left = 0, right = 0.14 inch, first line = +2 inch
     //     <w:ind w:rightChars="0" w:hangingChars="0" w:firstLine="2880" />
 
-    createSwDoc("tdf167721_chUnits3.docx");
-    // saveAndReload(mpFilter);
-
     // Test the parent style 
######################################################################
     uno::Reference<beans::XPropertySet> xStyle(
         getStyles(u"ParagraphStyles"_ustr)->getByName(u"List Paragraph"_ustr), 
uno::UNO_QUERY);
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index c4e1c4a7db81..f3f91c09d114 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -9424,6 +9424,26 @@ void 
DocxAttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rF
     }
 
     sal_Int32 const 
nFirstLineAdjustment(rFirstLine.ResolveTextFirstLineOffset({}));
+
+    // if the parent style wrote a FONT_CJK_ADVANCE margin (which has 
inheritance priority)
+    // then hangingChars/firstLineChars (either one) needs to be disabled
+    const SvxFirstLineIndentItem* pInherited = nullptr;
+    if (auto pNd = dynamic_cast<const 
SwContentNode*>(m_rExport.m_pOutFormatNode)) //paragraph
+        pInherited = 
&static_cast<SwTextFormatColl&>(pNd->GetAnyFormatColl()).GetAttrSet().GetFirstLineIndent();
+    else if (m_rExport.m_bStyDef && m_rExport.m_pCurrentStyle && 
m_rExport.m_pCurrentStyle->DerivedFrom()) //style
+        pInherited = 
&m_rExport.m_pCurrentStyle->DerivedFrom()->GetFirstLineIndent();
+    if (pInherited)
+    {
+        stValue = pInherited->GetTextFirstLineOffset();
+        if (stValue.m_nUnit == css::util::MeasureUnit::FONT_CJK_ADVANCE)
+        {
+            AddToAttrList(m_pLRSpaceAttrList,
+                          FSNS(XML_w,
+                               nFirstLineAdjustment > 0 ? XML_firstLineChars : 
XML_hangingChars),
+                          OString::number(0));
+        }
+    }
+
     if (nFirstLineAdjustment > 0)
     {
         AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, XML_firstLine),
@@ -9484,6 +9504,24 @@ void 
DocxAttributeOutput::FormatTextLeftMargin(SvxTextLeftMarginItem const& rTex
         return;
     }
 
+    // if the parent style wrote a FONT_CJK_ADVANCE margin (which has 
inheritance priority)
+    // then leftChars needs to be disabled
+    const SvxTextLeftMarginItem* pInherited = nullptr;
+    if (auto pNd = dynamic_cast<const 
SwContentNode*>(m_rExport.m_pOutFormatNode)) //paragraph
+        pInherited = 
&static_cast<SwTextFormatColl&>(pNd->GetAnyFormatColl()).GetAttrSet().GetTextLeftMargin();
+    else if (m_rExport.m_bStyDef && m_rExport.m_pCurrentStyle && 
m_rExport.m_pCurrentStyle->DerivedFrom()) //style
+        pInherited = 
&m_rExport.m_pCurrentStyle->DerivedFrom()->GetTextLeftMargin();
+    if (pInherited)
+    {
+        stValue = pInherited->GetTextLeft();
+        if (stValue.m_nUnit == css::util::MeasureUnit::FONT_CJK_ADVANCE)
+        {
+            AddToAttrList(m_pLRSpaceAttrList,
+                          FSNS(XML_w, bEcma1st ? XML_leftChars : 
XML_startChars),
+                          OString::number(0));
+        }
+    }
+
     AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, (bEcma1st ? XML_left : 
XML_start)),
                   OString::number(pTextLeftMargin->ResolveTextLeft({})));
 }
@@ -9501,6 +9539,23 @@ void 
DocxAttributeOutput::FormatRightMargin(SvxRightMarginItem const& rRightMarg
         return;
     }
 
+    // if the parent style wrote a FONT_CJK_ADVANCE margin (which has 
inheritance priority)
+    // then rightChars needs to be disabled
+    const SvxRightMarginItem* pInherited = nullptr;
+    if (auto pNd = dynamic_cast<const 
SwContentNode*>(m_rExport.m_pOutFormatNode)) //paragraph
+        pInherited = 
&static_cast<SwTextFormatColl&>(pNd->GetAnyFormatColl()).GetAttrSet().GetRightMargin();
+    else if (m_rExport.m_bStyDef && m_rExport.m_pCurrentStyle && 
m_rExport.m_pCurrentStyle->DerivedFrom()) //style
+        pInherited = 
&m_rExport.m_pCurrentStyle->DerivedFrom()->GetRightMargin();
+    if (pInherited)
+    {
+        stValue = pInherited->GetRight();
+        if (stValue.m_nUnit == css::util::MeasureUnit::FONT_CJK_ADVANCE)
+        {
+            AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, bEcma1st ? 
XML_rightChars : XML_endChars),
+                          OString::number(0));
+        }
+    }
+
     AddToAttrList(m_pLRSpaceAttrList, FSNS(XML_w, (bEcma1st ? XML_right : 
XML_end)),
                   OString::number(rRightMargin.ResolveRight({})));
 }

Reply via email to