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({}))); }