tdf#121525 OOXML import: fix formula alignment

Formula alignment was not handled at all.
Now "oMathPara", "oMathParaPr" elements
and m:jc attribute are handled using paragraph
alignment, as a workaround.

Co-author: Tibor Nagy

Change-Id: I71546755492e0f9187c77f5324bada6f3c68f0dc
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91435
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/qa/extras/ooxmlexport/data/tdf130907.docx b/sw/qa/extras/ooxmlexport/data/tdf130907.docx
new file mode 100644
index 0000000..c0c25fc
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf130907.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
index c85afe6..6e60584 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
@@ -44,6 +44,33 @@ protected:
    }
};

DECLARE_OOXMLIMPORT_TEST(Tdf130907,"tdf130907.docx")
{
    uno::Reference<text::XTextRange> xPara1 = getParagraph(2);
    CPPUNIT_ASSERT(xPara1.is());
    uno::Reference<beans::XPropertySet> xFormula1Props = getParagraphAnchoredObject(0, xPara1);
    CPPUNIT_ASSERT(xFormula1Props.is());
    sal_Int16 nHOri1;
    xFormula1Props->getPropertyValue("HoriOrient") >>= nHOri1;
    CPPUNIT_ASSERT_EQUAL_MESSAGE("The alignment of the equation is not left!",sal_Int16(3),nHOri1);

    uno::Reference<text::XTextRange> xPara2 = getParagraph(3);
    CPPUNIT_ASSERT(xPara2.is());
    uno::Reference<beans::XPropertySet> xFormula2Props = getParagraphAnchoredObject(0, xPara2);
    CPPUNIT_ASSERT(xFormula2Props.is());
    sal_Int16 nHOri2;
    xFormula2Props->getPropertyValue("HoriOrient") >>= nHOri2;
    CPPUNIT_ASSERT_EQUAL_MESSAGE("The alignment of the equation is not center!", sal_Int16(2), nHOri2);

    uno::Reference<text::XTextRange> xPara3 = getParagraph(5);
    CPPUNIT_ASSERT(xPara3.is());
    uno::Reference<beans::XPropertySet> xFormula3Props = getParagraphAnchoredObject(0, xPara3);
    CPPUNIT_ASSERT(xFormula3Props.is());
    sal_Int16 nHOri3;
    xFormula3Props->getPropertyValue("HoriOrient") >>= nHOri3;
    CPPUNIT_ASSERT_EQUAL_MESSAGE("The alignment of the equation is not right!", sal_Int16(1), nHOri3);
}

DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf78749, "tdf78749.docx")
{
    //Shape lost the background image before, now check if it still has...
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index 4b9c1d1..07bd913 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -732,8 +732,18 @@ void DomainMapper::lcl_attribute(Id nName, Value & val)
            m_pImpl->ImportGraphic( val.getProperties(), IMPORT_AS_DETECTED_INLINE );
        }
        break;
        case NS_ooxml::LN_Value_math_ST_Jc_centerGroup:
        case NS_ooxml::LN_Value_math_ST_Jc_center:
            m_pImpl->appendStarMath(val, eMathParaJc::CENTER);
            break;
        case NS_ooxml::LN_Value_math_ST_Jc_left:
            m_pImpl->appendStarMath(val, eMathParaJc::LEFT);
            break;
        case NS_ooxml::LN_Value_math_ST_Jc_right:
            m_pImpl->appendStarMath(val, eMathParaJc::RIGHT);
            break;
        case NS_ooxml::LN_starmath:
            m_pImpl->appendStarMath( val );
            m_pImpl->appendStarMath( val, eMathParaJc::INLINE );
            break;
        case NS_ooxml::LN_CT_FramePr_dropCap:
        case NS_ooxml::LN_CT_FramePr_lines:
diff --git a/writerfilter/source/dmapper/DomainMapper.hxx b/writerfilter/source/dmapper/DomainMapper.hxx
index 6fdb44e..dfabf1e 100644
--- a/writerfilter/source/dmapper/DomainMapper.hxx
+++ b/writerfilter/source/dmapper/DomainMapper.hxx
@@ -129,6 +129,14 @@ public:

    void HandleRedline( Sprm& rSprm );

    enum eMathParaJc
    {
        INLINE,
        CENTER,
        LEFT,
        RIGHT
    };

private:
    // Stream
    virtual void lcl_startSectionGroup() override;
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index c46fb12..4ef7b844 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -2176,7 +2176,7 @@ void DomainMapper_Impl::appendOLE( const OUString& rStreamName, const std::share

}

void DomainMapper_Impl::appendStarMath( const Value& val )
void DomainMapper_Impl::appendStarMath( const Value& val , sal_uInt8 nAlign)
{
    uno::Reference< embed::XEmbeddedObject > formula;
    val.getAny() >>= formula;
@@ -2219,9 +2219,42 @@ void DomainMapper_Impl::appendStarMath( const Value& val )
                uno::makeAny( sal_Int32(size.Height())));
            // mimic the treatment of graphics here... it seems anchoring as character
            // gives a better ( visually ) result
            xStarMathProperties->setPropertyValue(getPropertyName( PROP_ANCHOR_TYPE ),
                uno::makeAny( text::TextContentAnchorType_AS_CHARACTER ) );
            appendTextContent( xStarMath, uno::Sequence< beans::PropertyValue >() );
            appendTextContent(xStarMath, uno::Sequence<beans::PropertyValue>());
            if (nAlign != DomainMapper::eMathParaJc::INLINE)
            {
                xStarMathProperties->setPropertyValue(
                    getPropertyName(PROP_ANCHOR_TYPE),
                    uno::makeAny(text::TextContentAnchorType_AT_PARAGRAPH));
                switch (nAlign)
                {
                    case DomainMapper::eMathParaJc::CENTER:
                        xStarMathProperties->setPropertyValue(
                            getPropertyName(PROP_HORI_ORIENT),
                            uno::makeAny(text::HoriOrientation::CENTER));
                        break;
                    case DomainMapper::eMathParaJc::LEFT:
                        xStarMathProperties->setPropertyValue(
                            getPropertyName(PROP_HORI_ORIENT),
                            uno::makeAny(text::HoriOrientation::LEFT));
                        break;
                    case DomainMapper::eMathParaJc::RIGHT:
                        xStarMathProperties->setPropertyValue(
                            getPropertyName(PROP_HORI_ORIENT),
                            uno::makeAny(text::HoriOrientation::RIGHT));
                        break;
                    default:
                        break;
                }
                xStarMathProperties->setPropertyValue(
                    "Surround",
                    uno::makeAny(text::WrapTextMode_NONE));
            }
            else
            {
                xStarMathProperties->setPropertyValue(
                    getPropertyName(PROP_ANCHOR_TYPE),
                    uno::makeAny(text::TextContentAnchorType_AS_CHARACTER));
            }
        }
        catch( const uno::Exception& )
        {
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index c96a68b..33a4eb5 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -678,7 +678,7 @@ public:
    void appendTextPortion( const OUString& rString, const PropertyMapPtr& pPropertyMap );
    void appendTextContent(const css::uno::Reference<css::text::XTextContent>&, const css::uno::Sequence<css::beans::PropertyValue>&);
    void appendOLE( const OUString& rStreamName, const std::shared_ptr<OLEHandler>& pOleHandler );
    void appendStarMath( const Value& v );
    void appendStarMath( const Value& v , sal_uInt8);
    css::uno::Reference<css::beans::XPropertySet> appendTextSectionAfter(css::uno::Reference<css::text::XTextRange> const & xBefore);

    /// AutoText import: each entry is placed in the separate section
diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
index f05f305..4cb7198 100644
--- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
+++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
@@ -66,6 +66,8 @@ OOXMLFastContextHandler::OOXMLFastContextHandler
  mId(0),
  mnDefine(0),
  mnToken(oox::XML_TOKEN_COUNT),
  mnMathJcVal(0),
  mbIsMathPara(false),
  mpStream(nullptr),
  mnTableDepth(0),
  inPositionV(false),
@@ -87,6 +89,8 @@ OOXMLFastContextHandler::OOXMLFastContextHandler(OOXMLFastContextHandler * pCont
  mId(0),
  mnDefine(0),
  mnToken(oox::XML_TOKEN_COUNT),
  mnMathJcVal(pContext->mnMathJcVal),
  mbIsMathPara(pContext->mbIsMathPara),
  mpStream(pContext->mpStream),
  mpParserState(pContext->mpParserState),
  mnTableDepth(pContext->mnTableDepth),
@@ -162,6 +166,19 @@ void SAL_CALL OOXMLFastContextHandler::startFastElement
        mbPreserveSpace = Attribs->getValue(oox::NMSP_xml | oox::XML_space) == "preserve";
        mbPreserveSpaceSet = true;
    }
    if (Element == (NMSP_officeMath | XML_oMathPara))
    {
        mnMathJcVal = eMathParaJc::CENTER;
        mbIsMathPara = true;
    }
    if (Element == (NMSP_officeMath | XML_jc) && mpParent && mpParent->mpParent )
    {
        mbIsMathPara = true;
        auto aAttrLst = Attribs->getFastAttributes();
        if (aAttrLst[0].Value == "center") mpParent->mpParent->mnMathJcVal = eMathParaJc::CENTER;
        if (aAttrLst[0].Value == "left") mpParent->mpParent->mnMathJcVal = eMathParaJc::LEFT;
        if (aAttrLst[0].Value == "right") mpParent->mpParent->mnMathJcVal = eMathParaJc::RIGHT;
    }

    if (oox::getNamespace(Element) == NMSP_mce)
        m_bDiscardChildren = prepareMceContext(Element, Attribs);
@@ -2143,7 +2160,28 @@ void OOXMLFastContextHandlerMath::process()
    {
        OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
        OOXMLValue::Pointer_t pVal( new OOXMLStarMathValue( ref ));
        pProps->add(NS_ooxml::LN_starmath, pVal, OOXMLProperty::ATTRIBUTE);
        if (mbIsMathPara)
        {
            switch (mnMathJcVal)
            {
                case eMathParaJc::CENTER:
                    pProps->add(NS_ooxml::LN_Value_math_ST_Jc_centerGroup, pVal,
                                OOXMLProperty::ATTRIBUTE);
                    break;
                case eMathParaJc::LEFT:
                    pProps->add(NS_ooxml::LN_Value_math_ST_Jc_left, pVal,
                                OOXMLProperty::ATTRIBUTE);
                    break;
                case eMathParaJc::RIGHT:
                    pProps->add(NS_ooxml::LN_Value_math_ST_Jc_right, pVal,
                                OOXMLProperty::ATTRIBUTE);
                    break;
                default:
                    break;
            }
        }
        else
            pProps->add(NS_ooxml::LN_starmath, pVal, OOXMLProperty::ATTRIBUTE);
        mpStream->props( pProps.get() );
    }
}
diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
index 5bc4ea3..ca6e650 100644
--- a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
+++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
@@ -195,6 +195,16 @@ protected:
    Id mnDefine;
    Token_t mnToken;

    // the formula insertion mode: inline/newline(left, center, right)
    sal_Int8 mnMathJcVal;
    bool mbIsMathPara;
    enum eMathParaJc
    {
        INLINE, //The equation is anchored as inline to the text
        CENTER, //The equation is center aligned
        LEFT,   //The equation is left aligned
        RIGHT  //The equation is right aligned
    };
    // the stream to send the stream events to.
    Stream * mpStream;

diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml
index b389947..380fc3f 100644
--- a/writerfilter/source/ooxml/model.xml
+++ b/writerfilter/source/ooxml/model.xml
@@ -8127,6 +8127,11 @@
          <ref name="CT_OMath"/>
        </element>
      </define>
      <define name="oMathParaPr">
        <element name="oMathParaPr">
          <ref name="CT_OMathParaPr"/>
        </element>
      </define>
    </grammar>
    <resource name="ST_Integer255" resource="Integer"/>
    <resource name="CT_Integer255" resource="Value">
@@ -8232,7 +8237,7 @@
    <resource name="CT_Style" resource="Value">
      <attribute name="val" tokenid="ooxml:CT_Style_val" action="setValue"/>
    </resource>
    <resource name="ST_Jc" resource="List">
    <resource name="ST_Jc" resource="String">
      <value tokenid="ooxml:Value_math_ST_Jc_start">left</value>
      <value tokenid="ooxml:Value_math_ST_Jc_end">right</value>
      <value tokenid="ooxml:Value_math_ST_Jc_left">left</value>
@@ -19184,6 +19189,8 @@
    </resource>
    <resource name="CT_OMath" resource="Math"/>
    <resource name="CT_OMathPara" resource="Stream"/>
    <resource name="CT_OMathParaPr" resource="Properties"/>
    <resource name="CT_OMathJc" resource="Value"/>
  </namespace>
</model>
<!-- vim: shiftwidth=2 softtabstop=2 expandtab: