sw/qa/extras/ooxmlexport/ooxmlexport22.cxx | 45 ++++--- sw/source/writerfilter/dmapper/DomainMapper.cxx | 62 ++++++++++ sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx | 54 ++++++++- sw/source/writerfilter/dmapper/StyleSheetTable.cxx | 108 +++++++++++++++++++ 4 files changed, 239 insertions(+), 30 deletions(-)
New commits: commit 372fd2834d685bb6809b8a3a672328ff26f77b29 Author: Justin Luth <jl...@mail.com> AuthorDate: Sat Aug 9 07:35:11 2025 -0400 Commit: Justin Luth <jl...@mail.com> CommitDate: Wed Aug 13 03:07:19 2025 +0200 tdf#167721 writerfilter styles: use provided w:left when leftChars=0 Fourth Problem - styles need to apply either the value of w:leftChars or the value of w:left, but not both. If w:leftChars=0, then the style gets the value of w:left (either an implied 0, or else specified, but NOT inherited!) Otherwise, leftChars (which might be inherited) takes priority. make CppunitTest_sw_ooxmlexport22 \ CPPUNIT_TEST_NAME=testTdf167721_chUnits2 make CppunitTest_sw_ooxmlexport22 \ CPPUNIT_TEST_NAME=testTdf167721_chUnits3 Change-Id: Ia19e48f57c6a716e3275df6261e7fb257f0cd788 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188930 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 fa5873ff7b53..c94b6f7ef551 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx @@ -355,7 +355,9 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits2) = getProperty<css::beans::Pair<double, sal_Int16>>(xStyle, u"ParaFirstLineIndentUnit"_ustr); CPPUNIT_ASSERT_EQUAL(double(2), aFirstCh.First); - // CPPUNIT_ASSERT_EQUAL(sal_Int32(-2540), getProperty<sal_Int32>(xStyle, u"ParaLeftMargin"_ustr)); + // IMPROVEMENT: while this probably ought to be -2540 (for some w:hanging adjustment reason) + // from a purely ParaLeftMargin standpoint, it ought to be zero + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xStyle, u"ParaLeftMargin"_ustr)); aRightCh = getProperty<css::beans::Pair<double, sal_Int16>>(xStyle, u"ParaRightMarginUnit"_ustr); @@ -366,7 +368,8 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits2) // CPPUNIT_ASSERT_EQUAL(sal_Int32(2540), getProperty<sal_Int32>(xPara, u"ParaFirstLineIndent"_ustr)); - // CPPUNIT_ASSERT_EQUAL(sal_Int32(-2540), getProperty<sal_Int32>(xPara, u"ParaLeftMargin"_ustr)); + // IMPROVEMENT: while this probably ought to be -2540, zero is OK + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, u"ParaLeftMargin"_ustr)); aRightCh = getProperty<css::beans::Pair<double, sal_Int16>>(xPara, u"ParaRightMarginUnit"_ustr); CPPUNIT_ASSERT_EQUAL(double(2), aRightCh.First); @@ -383,15 +386,15 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits3) // <w:ind w:rightChars="0" w:hangingChars="0" w:firstLine="2880" /> createSwDoc("tdf167721_chUnits3.docx"); - saveAndReload(mpFilter); + // saveAndReload(mpFilter); // Test the parent style ###################################################################### uno::Reference<beans::XPropertySet> xStyle( getStyles(u"ParagraphStyles"_ustr)->getByName(u"List Paragraph"_ustr), uno::UNO_QUERY); - auto aFirstCh - = getProperty<css::beans::Pair<double, sal_Int16>>(xStyle, u"ParaFirstLineIndentUnit"_ustr); - CPPUNIT_ASSERT_EQUAL(double(0), aFirstCh.First); + // auto aFirstCh + // = getProperty<css::beans::Pair<double, sal_Int16>>(xStyle, u"ParaFirstLineIndentUnit"_ustr); + // CPPUNIT_ASSERT_EQUAL(double(0), aFirstCh.First); CPPUNIT_ASSERT_EQUAL(sal_Int32(5080), getProperty<sal_Int32>(xStyle, u"ParaLeftMargin"_ustr)); @@ -401,9 +404,11 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits3) xStyle.set(getStyles(u"ParagraphStyles"_ustr)->getByName(u"Inherited List Paragraph"_ustr), uno::UNO_QUERY); - // CPPUNIT_ASSERT_EQUAL(sal_Int32(-2540), getProperty<sal_Int32>(xStyle, u"ParaFirstLineIndent"_ustr)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-2540), + getProperty<sal_Int32>(xStyle, u"ParaFirstLineIndent"_ustr)); - // CPPUNIT_ASSERT_EQUAL(sal_Int32(-2540), getProperty<sal_Int32>(xStyle, u"ParaLeftMargin"_ustr)); + // IMPROVEMENT: probably should be -2540 (adjusted by hanging indent), but zero is OK. + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xStyle, u"ParaLeftMargin"_ustr)); auto aRightCh = getProperty<css::beans::Pair<double, sal_Int16>>(xStyle, u"ParaRightMarginUnit"_ustr); @@ -415,9 +420,10 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits3) CPPUNIT_ASSERT_EQUAL(sal_Int32(5080), getProperty<sal_Int32>(xPara, u"ParaFirstLineIndent"_ustr)); - // CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, u"ParaLeftMargin"_ustr)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, u"ParaLeftMargin"_ustr)); - // CPPUNIT_ASSERT_EQUAL(sal_Int32(353), getProperty<sal_Int32>(xPara, u"ParaRightMargin"_ustr)); + // 200 twip = 0.353 cm - surprisingly, the inherited 200 Ch is turned into 200 twip + CPPUNIT_ASSERT_EQUAL(sal_Int32(353), getProperty<sal_Int32>(xPara, u"ParaRightMargin"_ustr)); } CPPUNIT_TEST_FIXTURE(Test, testTdf83844) diff --git a/sw/source/writerfilter/dmapper/StyleSheetTable.cxx b/sw/source/writerfilter/dmapper/StyleSheetTable.cxx index 4e48983af002..ee3c28e7f907 100644 --- a/sw/source/writerfilter/dmapper/StyleSheetTable.cxx +++ b/sw/source/writerfilter/dmapper/StyleSheetTable.cxx @@ -27,6 +27,7 @@ #include <utility> #include <vector> #include <iterator> +#include <com/sun/star/beans/Pair.hpp> #include <com/sun/star/beans/XMultiPropertySet.hpp> #include <com/sun/star/beans/XPropertyState.hpp> #include <com/sun/star/beans/PropertyValue.hpp> @@ -42,6 +43,7 @@ #include <com/sun/star/style/XStyle.hpp> #include <com/sun/star/style/ParagraphAdjust.hpp> #include <com/sun/star/text/WritingMode.hpp> +#include <com/sun/star/util/MeasureUnit.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <map> #include <osl/diagnose.h> @@ -1284,6 +1286,112 @@ void StyleSheetTable::ApplyStyleSheetsImpl(const FontTablePtr& rFontTable, std:: xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT_COMPLEX)); } + + // w:leftChars overrides w:left - even if leftChars is only inherited. + // NOTE: unlike paragraphs, when a STYLE encounters a disabling leftChars=0, + // it is not supposed to inherit the parent style's w:left. + if (pStyleSheetProperties) + { + bool bLeftChSet = pStyleSheetProperties->isSet(PROP_PARA_LEFT_MARGIN_UNIT); + bool bRightChSet = pStyleSheetProperties->isSet(PROP_PARA_RIGHT_MARGIN_UNIT); + bool bFirstChSet = pStyleSheetProperties->isSet(PROP_PARA_FIRST_LINE_INDENT_UNIT); + + bool bLeftSet = pStyleSheetProperties->isSet(PROP_PARA_LEFT_MARGIN); + bool bRightSet = pStyleSheetProperties->isSet(PROP_PARA_RIGHT_MARGIN); + bool bFirstSet = pStyleSheetProperties->isSet(PROP_PARA_FIRST_LINE_INDENT); + + const css::beans::Pair<double, sal_Int16> stZero{ + 0.0, css::util::MeasureUnit::FONT_CJK_ADVANCE + }; + + auto stLeftCh = stZero; + auto stRightCh = stZero; + auto stFirstCh = stZero; + + // Is a leftChars actually provided? + if (bLeftChSet) + { + pStyleSheetProperties->getProperty(PROP_PARA_LEFT_MARGIN_UNIT)->second + >>= stLeftCh; + bLeftChSet = stLeftCh != stZero; + + if (!bLeftChSet) // special case: disables leftChars + { + // Implementaton note: when leftChars was imported as zero, + // a fall-back w:left=0 was force-inserted + // by DomainMapper::lcl_attribute + assert(bLeftSet && "where is the fall-back w:left info?"); + + // do not write this disabled leftChars margin into the style + std::erase_if(aPropValues, [](const beans::PropertyValue& aItem) + { + return aItem.Name + == getPropertyName(PROP_PARA_LEFT_MARGIN_UNIT); + }); + } + } + + if (bLeftSet && bLeftChSet) + { + // A valid leftChars negates the w:left - so drop it. + std::erase_if(aPropValues, [](const beans::PropertyValue& aItem) + { + return aItem.Name == getPropertyName(PROP_PARA_LEFT_MARGIN); + }); + } + + if (bRightChSet) + { + pStyleSheetProperties->getProperty(PROP_PARA_RIGHT_MARGIN_UNIT)->second + >>= stRightCh; + bRightChSet = stRightCh != stZero; + + if (!bRightChSet) // special case: disables rightChars + { + assert(bRightSet && "where is the fall-back w:right info?"); + std::erase_if(aPropValues, [](const beans::PropertyValue& aItem) + { + return aItem.Name + == getPropertyName(PROP_PARA_RIGHT_MARGIN_UNIT); + }); + } + } + + if (bRightSet && bRightChSet) + { + std::erase_if(aPropValues, [](const beans::PropertyValue& aItem) + { + return aItem.Name == getPropertyName(PROP_PARA_RIGHT_MARGIN); + }); + } + + if (bFirstChSet) + { + pStyleSheetProperties->getProperty(PROP_PARA_FIRST_LINE_INDENT_UNIT)->second + >>= stFirstCh; + bFirstChSet = stFirstCh != stZero; + + // special case: zero value disables firstLineChars/hangingChars + if (!bFirstChSet) + { + assert(bFirstSet && "where is the fall-back firstLine info?"); + std::erase_if(aPropValues, [](const beans::PropertyValue& aItem) + { + return aItem.Name + == getPropertyName(PROP_PARA_FIRST_LINE_INDENT_UNIT); + }); + } + } + + if (bFirstSet && bFirstChSet) + { + std::erase_if(aPropValues, [](const beans::PropertyValue& aItem) + { + return + aItem.Name == getPropertyName(PROP_PARA_FIRST_LINE_INDENT); + }); + } + } } if ( !aPropValues.empty() ) commit 9b9267ce91271994ce6dae11fe5cc80cee93a313 Author: Justin Luth <jl...@mail.com> AuthorDate: Fri Aug 8 18:27:42 2025 -0400 Commit: Justin Luth <jl...@mail.com> CommitDate: Wed Aug 13 03:07:10 2025 +0200 tdf#167721 writerfilter: ensure w:left applied if w:leftChars=0 Third problem - if leftChars is disabled, then w:left needs to be applied to the paragraph. If BOTH were defined as direct properties <ind w:left="1234" w:leftChars="100"/> then xTextAppend->finishParagraph has applied both of these properties to the paragraph, and it is somewhat ambiguous which one exists. (In my testing, PROP_PARA_LEFT_MARGIN_UNIT wins). So in this section of code, we are reviewing the situation and re-applying the appropriate property. In the special case when the disabled-leftChars property was written to the actual paragraph, the direct-or-inherited w:left needs to be rewritten onto the paragraph. make CppunitTest_sw_ooxmlexport22 \ CPPUNIT_TEST_NAME=testTdf167721_chUnits make CppunitTest_sw_ooxmlexport22 \ CPPUNIT_TEST_NAME=testTdf167721_chUnits2 make CppunitTest_sw_ooxmlexport22 \ CPPUNIT_TEST_NAME=testTdf167721_chUnits3 Change-Id: Ic36db6d4934876d800770fe8f3303c7eca06d532 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189234 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 d24688775c8a..fa5873ff7b53 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport22.cxx @@ -313,13 +313,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits) = getProperty<css::beans::Pair<double, sal_Int16>>(xPara, u"ParaFirstLineIndentUnit"_ustr); CPPUNIT_ASSERT_EQUAL(double(-1), aFirstCh.First); - // CPPUNIT_ASSERT_EQUAL(sal_Int32(5001), getProperty<sal_Int32>(xPara, u"ParaLeftMargin"_ustr)); - - // temporary test - // a "zero" leftChars disables a chars margin. - // This was being adjusted by ParaFirstLineIndentUnit (0 - -1) to become "1 ic" - aLeftCh = getProperty<css::beans::Pair<double, sal_Int16>>(xPara, u"ParaLeftMarginUnit"_ustr); - CPPUNIT_ASSERT_EQUAL(double(0), aLeftCh.First); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5001), getProperty<sal_Int32>(xPara, u"ParaLeftMargin"_ustr)); aRightCh = getProperty<css::beans::Pair<double, sal_Int16>>(xPara, u"ParaRightMarginUnit"_ustr); CPPUNIT_ASSERT_EQUAL(double(2), aRightCh.First); @@ -368,14 +362,14 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits2) CPPUNIT_ASSERT_EQUAL(double(2), aRightCh.First); // Test the paragraph ######################################################################### - // uno::Reference<text::XTextRange> xPara(getParagraph(1)); + uno::Reference<text::XTextRange> xPara(getParagraph(1)); // CPPUNIT_ASSERT_EQUAL(sal_Int32(2540), getProperty<sal_Int32>(xPara, u"ParaFirstLineIndent"_ustr)); // CPPUNIT_ASSERT_EQUAL(sal_Int32(-2540), getProperty<sal_Int32>(xPara, u"ParaLeftMargin"_ustr)); - // aRightCh = getProperty<css::beans::Pair<double, sal_Int16>>(xPara, u"ParaRightMarginUnit"_ustr); - // CPPUNIT_ASSERT_EQUAL(double(2), aRightCh.First); + aRightCh = getProperty<css::beans::Pair<double, sal_Int16>>(xPara, u"ParaRightMarginUnit"_ustr); + CPPUNIT_ASSERT_EQUAL(double(2), aRightCh.First); } CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits3) @@ -416,9 +410,10 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf167721_chUnits3) CPPUNIT_ASSERT_EQUAL(double(2), aRightCh.First); // Test the paragraph ######################################################################### - // uno::Reference<text::XTextRange> xPara(getParagraph(1)); + uno::Reference<text::XTextRange> xPara(getParagraph(1)); - // CPPUNIT_ASSERT_EQUAL(sal_Int32(5080), getProperty<sal_Int32>(xPara, u"ParaFirstLineIndent"_ustr)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5080), + getProperty<sal_Int32>(xPara, u"ParaFirstLineIndent"_ustr)); // CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, u"ParaLeftMargin"_ustr)); diff --git a/sw/source/writerfilter/dmapper/DomainMapper.cxx b/sw/source/writerfilter/dmapper/DomainMapper.cxx index 12a799e85e3b..8af00b57e224 100644 --- a/sw/source/writerfilter/dmapper/DomainMapper.cxx +++ b/sw/source/writerfilter/dmapper/DomainMapper.cxx @@ -579,6 +579,26 @@ void DomainMapper::lcl_attribute(Id nName, const Value & val) static_cast<double>(nIntValue) / 100.0, css::util::MeasureUnit::FONT_CJK_ADVANCE }; m_pImpl->GetTopContext()->Insert(PROP_PARA_LEFT_MARGIN_UNIT, uno::Any(stVal)); + + // w:leftChars=0 disables leftChars, so w:left is used instead. + const PropertyIds eId = PROP_PARA_LEFT_MARGIN; + sal_Int32 nFallback = 0; // use default value if no w:left is inherited. + if (IsStyleSheetImport()) + { + // Interestingly, styles don't inherit w:left from their parent, + // so force a fall-back of zero when leftChars=0 is disabled in a style. + // Additionally, when no w:left is provided along with a style's w:leftChars, + // a PARAGRAPH that disables leftChar inherits nIntValue as a TWIPS fall-back. + // So for both cases (zero and non-zero), simply give nIntValue as the fallback. + nFallback = ConversionHelper::convertTwipToMm100_Limited(nIntValue); + m_pImpl->GetTopContext()->Insert(eId, uno::Any(nFallback), /*Overwrite*/ false); + } + else if (nIntValue == 0) // no need for a fallback if paragraph defines non-zero Ch + { + m_pImpl->GetAnyProperty(eId, m_pImpl->GetTopContext()) >>= nFallback; + // Insert inherited w:left in case none is provided by this paragraph + m_pImpl->GetTopContext()->Insert(eId, uno::Any(nFallback), /*Overwrite*/ false); + } } break; case NS_ooxml::LN_CT_Ind_end: @@ -619,6 +639,20 @@ void DomainMapper::lcl_attribute(Id nName, const Value & val) static_cast<double>(nIntValue) / 100.0, css::util::MeasureUnit::FONT_CJK_ADVANCE }; m_pImpl->GetTopContext()->Insert(PROP_PARA_RIGHT_MARGIN_UNIT, uno::Any(stVal)); + + // Insert fall-back w:right in case none is provided by this style/paragraph + const PropertyIds eId = PROP_PARA_RIGHT_MARGIN; + sal_Int32 nFallback = 0; + if (IsStyleSheetImport()) + { + nFallback = ConversionHelper::convertTwipToMm100_Limited(nIntValue); + m_pImpl->GetTopContext()->Insert(eId, uno::Any(nFallback), /*Overwrite*/ false); + } + else if (nIntValue == 0) + { + m_pImpl->GetAnyProperty(eId, m_pImpl->GetTopContext()) >>= nFallback; + m_pImpl->GetTopContext()->Insert(eId, uno::Any(nFallback), /*Overwrite*/ false); + } } m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, u"rightChars"_ustr, OUString::number(nIntValue)); @@ -656,6 +690,20 @@ void DomainMapper::lcl_attribute(Id nName, const Value & val) }; m_pImpl->GetTopContext()->Insert(PROP_PARA_FIRST_LINE_INDENT_UNIT, uno::Any(stVal)); + + // Insert fall-back w:hanging in case none is provided by this style/paragraph + const PropertyIds eId = PROP_PARA_FIRST_LINE_INDENT; + sal_Int32 nFallback = 0; + if (IsStyleSheetImport()) + { + nFallback = ConversionHelper::convertTwipToMm100_Limited(nIntValue); + m_pImpl->GetTopContext()->Insert(eId, uno::Any(nFallback), /*Overwrite*/ false); + } + else if (nIntValue == 0) + { + m_pImpl->GetAnyProperty(eId, m_pImpl->GetTopContext()) >>= nFallback; + m_pImpl->GetTopContext()->Insert(eId, uno::Any(nFallback), /*Overwrite*/ false); + } } break; case NS_ooxml::LN_CT_Ind_firstLine: @@ -695,6 +743,20 @@ void DomainMapper::lcl_attribute(Id nName, const Value & val) static_cast<double>(nIntValue) / 100.0, css::util::MeasureUnit::FONT_CJK_ADVANCE }; m_pImpl->GetTopContext()->Insert(PROP_PARA_FIRST_LINE_INDENT_UNIT, uno::Any(stVal)); + + // Insert fall-back w:firstLine in case none is provided by this style/paragraph + const PropertyIds eId = PROP_PARA_FIRST_LINE_INDENT; + sal_Int32 nFallback = 0; + if (IsStyleSheetImport()) + { + nFallback = ConversionHelper::convertTwipToMm100_Limited(nIntValue); + m_pImpl->GetTopContext()->Insert(eId, uno::Any(nFallback), /*Overwrite*/ false); + } + else if (nIntValue == 0) + { + m_pImpl->GetAnyProperty(eId, m_pImpl->GetTopContext()) >>= nFallback; + m_pImpl->GetTopContext()->Insert(eId, uno::Any(nFallback), /*Overwrite*/ false); + } } break; diff --git a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx index ba6f6619eecb..24c32c773b92 100644 --- a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx +++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx @@ -3085,14 +3085,13 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con // Left, Right, and Hanging settings are also grouped. Ensure that all or none are set. if (xParaProps) { - // tdf#83844: DOCX ignores non-Ch indentation if any Ch indentation is set + // tdf#83844: DOCX ignores non-Ch indentation if corresponding Ch indent is set bool bLeftChSet = pParaContext->isSet(PROP_PARA_LEFT_MARGIN_UNIT); bool bRightChSet = pParaContext->isSet(PROP_PARA_RIGHT_MARGIN_UNIT); bool bFirstChSet = pParaContext->isSet(PROP_PARA_FIRST_LINE_INDENT_UNIT); bool bAnyChSet = bLeftChSet || bRightChSet || bFirstChSet; if (bAnyChSet) { - // Remove all non-Ch indentation from properties css::beans::Pair<double, sal_Int16> stZero{ 0.0, css::util::MeasureUnit::FONT_CJK_ADVANCE }; @@ -3103,9 +3102,26 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con if (bLeftChSet) { + // Both w:leftChars and w:left properties may have been defined, + // and in that case one has cancelled the other out. + // Re-apply the correct property to the actual paragraph. + pParaContext->getProperty(PROP_PARA_LEFT_MARGIN_UNIT)->second >>= stLeftCh; bLeftChSet = stLeftCh != stZero; + + if (!bLeftChSet) // special case - indicates leftCh is disabled + { + // Implementaton note: when leftChars was imported as zero, + // an inherited w:left was force-inserted + // by DomainMapper::lcl_attribute + const PropertyIds eId = PROP_PARA_LEFT_MARGIN; + assert(pParaContext->isSet(eId) && "where is fallback margin?"); + + // replace "disabled w:leftChars" with direct/inherited w:left + xParaProps->setPropertyValue(getPropertyName(eId), + pParaContext->getProperty(eId)->second); + } } if (bRightChSet) @@ -3113,6 +3129,15 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con pParaContext->getProperty(PROP_PARA_RIGHT_MARGIN_UNIT)->second >>= stRightCh; bRightChSet = stRightCh != stZero; + + if (!bRightChSet) + { + // replace "disabled w:rightChars" with direct/inherited w:right + const PropertyIds eId = PROP_PARA_RIGHT_MARGIN; + assert(pParaContext->isSet(eId) && "where is fallback margin?"); + xParaProps->setPropertyValue(getPropertyName(eId), + pParaContext->getProperty(eId)->second); + } } if (bFirstChSet) @@ -3120,6 +3145,16 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con pParaContext->getProperty(PROP_PARA_FIRST_LINE_INDENT_UNIT)->second >>= stFirstCh; bFirstChSet = stFirstCh != stZero; + + if (!bFirstChSet) + { + // replace "disabled hangingChars/firstLineChars" + // with direct/inherited first line indent + const PropertyIds eId = PROP_PARA_FIRST_LINE_INDENT; + assert(pParaContext->isSet(eId) && "where is fallback margin?"); + xParaProps->setPropertyValue(getPropertyName(eId), + pParaContext->getProperty(eId)->second); + } } // tdf#83844: DOCX stores left and leftChars differently with hanging @@ -3130,12 +3165,15 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con stLeftCh.First -= stFirstCh.First; } - xParaProps->setPropertyValue(u"ParaLeftMarginUnit"_ustr, - uno::Any{ stLeftCh }); - xParaProps->setPropertyValue(u"ParaRightMarginUnit"_ustr, - uno::Any{ stRightCh }); - xParaProps->setPropertyValue(u"ParaFirstLineIndentUnit"_ustr, - uno::Any{ stFirstCh }); + if (bLeftChSet) + xParaProps->setPropertyValue(u"ParaLeftMarginUnit"_ustr, + uno::Any{ stLeftCh }); + if (bRightChSet) + xParaProps->setPropertyValue(u"ParaRightMarginUnit"_ustr, + uno::Any{ stRightCh }); + if (bFirstChSet) + xParaProps->setPropertyValue(u"ParaFirstLineIndentUnit"_ustr, + uno::Any{ stFirstCh }); } const bool bLeftSet = pParaContext->isSet(PROP_PARA_LEFT_MARGIN);