tdf#118521 writerfilter: ContextMargin grouped with Top/Bottom

fixes tdf#104348, but tagging with the bug# of the initial fixes.

Internally, EditEng holds Top/Bottom/Context settings in one
object, so if only one piece is set, the cloned object
starts with docDefaults, so the un-initialized parts also need to
be specified with the values they inherit from their style.

So this patch makes two corrections. The first is grouping
ContextMargin with top/bottom. The second correction
is to check the entire style-chain instead of only
the direct style for the inherited property.

Change-Id: Ie1d4c9538aefece4ff8b7287242c7f4d33319b3b
Reviewed-on: https://gerrit.libreoffice.org/57914
Tested-by: Jenkins
Reviewed-by: Justin Luth <justin_luth@sil.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/qa/extras/ooxmlexport/data/tdf104348_contextMargin.docx b/sw/qa/extras/ooxmlexport/data/tdf104348_contextMargin.docx
new file mode 100644
index 0000000..ef3d065
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf104348_contextMargin.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index bb5d915..121c2d7 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -524,6 +524,18 @@ DECLARE_OOXMLEXPORT_TEST(testMarginsFromStyle, "margins_from_style.docx")
    CPPUNIT_ASSERT_EQUAL(sal_Int32(600), getProperty<sal_Int32>(getParagraph(3), "ParaBottomMargin"));
}

DECLARE_OOXMLEXPORT_TEST(testTdf104348_contextMargin, "tdf104348_contextMargin.docx")
{
    // tdf#104348 shows that ContextMargin belongs with Top/Bottom handling

    uno::Reference<beans::XPropertySet> xMyStyle(getStyles("ParagraphStyles")->getByName("MyStyle"), uno::UNO_QUERY);
    // from paragraph style - this is what direct formatting should equal
    sal_Int32 nMargin = getProperty<sal_Int32>(xMyStyle, "ParaBottomMargin");
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nMargin);
    // from direct formatting
    CPPUNIT_ASSERT_EQUAL(nMargin, getProperty<sal_Int32>(getParagraph(2), "ParaBottomMargin"));
}

DECLARE_OOXMLEXPORT_TEST(testTdf118521_marginsLR, "tdf118521_marginsLR.docx")
{
    // tdf#118521 paragraphs with direct formatting of only some of left, right, or first margins have
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 3a71b39..c6a6807 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -1472,46 +1472,60 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap )

                // tdf#118521 set paragraph top or bottom margin based on the paragraph style
                // if we already set the other margin with direct formatting
                if (pStyleSheetProperties && pParaContext && m_xPreviousParagraph.is() &&
                        pParaContext->isSet(PROP_PARA_TOP_MARGIN) != pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN))
                if ( pParaContext && m_xPreviousParagraph.is() )
                {
                    boost::optional<PropertyMap::Property> oProperty;
                    if (pParaContext->isSet(PROP_PARA_TOP_MARGIN))
                    const bool bTopSet = pParaContext->isSet(PROP_PARA_TOP_MARGIN);
                    const bool bBottomSet = pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN);
                    const bool bContextSet = pParaContext->isSet(PROP_PARA_CONTEXT_MARGIN);
                    if ( !(bTopSet == bBottomSet && bBottomSet == bContextSet) )
                    {
                        if ( (oProperty = pStyleSheetProperties->getProperty(PROP_PARA_BOTTOM_MARGIN)) )
                            m_xPreviousParagraph->setPropertyValue("ParaBottomMargin", oProperty->second);
                    }
                    else
                    {
                        if ( (oProperty = pStyleSheetProperties->getProperty(PROP_PARA_TOP_MARGIN)) )
                            m_xPreviousParagraph->setPropertyValue("ParaTopMargin", oProperty->second);
                        if ( !bTopSet )
                        {
                            uno::Any aMargin = GetPropertyFromStyleSheet(PROP_PARA_TOP_MARGIN);
                            if ( aMargin != uno::Any() )
                                m_xPreviousParagraph->setPropertyValue("ParaTopMargin", aMargin);
                        }
                        if ( !bBottomSet )
                        {
                            uno::Any aMargin = GetPropertyFromStyleSheet(PROP_PARA_BOTTOM_MARGIN);
                            if ( aMargin != uno::Any() )
                                m_xPreviousParagraph->setPropertyValue("ParaBottomMargin", aMargin);
                        }
                        if ( !bContextSet )
                        {
                            uno::Any aMargin = GetPropertyFromStyleSheet(PROP_PARA_CONTEXT_MARGIN);
                            if ( aMargin != uno::Any() )
                                m_xPreviousParagraph->setPropertyValue("ParaContextMargin", aMargin);
                        }
                    }
                }

                // Left, Right, and Hanging settings are also grouped. Ensure that all or none are set.
                // m_xPreviousParagraph was set earlier, so really it still is the current paragraph...
                if ( pStyleSheetProperties && pParaContext && m_xPreviousParagraph.is() )
                if ( pParaContext && m_xPreviousParagraph.is() )
                {
                    const bool bLeftSet  = pParaContext->isSet(PROP_PARA_LEFT_MARGIN);
                    const bool bRightSet = pParaContext->isSet(PROP_PARA_RIGHT_MARGIN);
                    const bool bFirstSet = pParaContext->isSet(PROP_PARA_FIRST_LINE_INDENT);
                    if ( !(bLeftSet == bRightSet && bRightSet == bFirstSet) )
                    {
                        boost::optional<PropertyMap::Property> oProperty;
                        if ( !bLeftSet )
                        {
                            if ( (oProperty = pStyleSheetProperties->getProperty(PROP_PARA_LEFT_MARGIN)) )
                                m_xPreviousParagraph->setPropertyValue("ParaLeftMargin", oProperty->second);
                            uno::Any aMargin = GetPropertyFromStyleSheet(PROP_PARA_LEFT_MARGIN);
                            if ( aMargin != uno::Any() )
                                m_xPreviousParagraph->setPropertyValue("ParaLeftMargin", aMargin);
                        }
                        if ( !bRightSet )
                        {
                            if ( (oProperty = pStyleSheetProperties->getProperty(PROP_PARA_RIGHT_MARGIN)) )
                                m_xPreviousParagraph->setPropertyValue("ParaRightMargin", oProperty->second);
                            uno::Any aMargin = GetPropertyFromStyleSheet(PROP_PARA_RIGHT_MARGIN);
                            if ( aMargin != uno::Any() )
                                m_xPreviousParagraph->setPropertyValue("ParaRightMargin", aMargin);
                        }
                        if ( !bFirstSet )
                        {
                            if ( (oProperty = pStyleSheetProperties->getProperty(PROP_PARA_FIRST_LINE_INDENT)) )
                                m_xPreviousParagraph->setPropertyValue("ParaFirstLineIndent", oProperty->second);
                            uno::Any aMargin = GetPropertyFromStyleSheet(PROP_PARA_FIRST_LINE_INDENT);
                            if ( aMargin != uno::Any() )
                                m_xPreviousParagraph->setPropertyValue("ParaFirstLineIndent", aMargin);
                        }
                    }
                }