tdf#61908:XLSX formula cell range is not exported for MMULT.

Problem Description:
- Matrix multiplication cell formula range is not exported after roundtrip.

XML Difference:
Original : <f t="array" ref="G5:G6">MMULT(A1:C2,E1:E3)</f>

Roundtrip : <f aca="false">MMULT(A1:C2,E1:E3)</f>

Solution : Added formula cell range support for matrix multiplication.

Change-Id: Ic871f064a98a324bc16a4253b633c97417c3f900
Reviewed-on: https://gerrit.libreoffice.org/16033
Reviewed-by: David Tardon <dtardon@redhat.com>
Tested-by: David Tardon <dtardon@redhat.com>
diff --git a/sc/qa/unit/data/xlsx/matrix-multiplication.xlsx b/sc/qa/unit/data/xlsx/matrix-multiplication.xlsx
new file mode 100644
index 0000000..f79d6b6
--- /dev/null
+++ b/sc/qa/unit/data/xlsx/matrix-multiplication.xlsx
Binary files differ
diff --git a/sc/qa/unit/subsequent_export-test.cxx b/sc/qa/unit/subsequent_export-test.cxx
index c194e31..ef9053d 100644
--- a/sc/qa/unit/subsequent_export-test.cxx
+++ b/sc/qa/unit/subsequent_export-test.cxx
@@ -147,6 +147,8 @@ public:
    void testHiddenShape();
    void testHyperlinkXLSX();
    void testMoveCellAnchoredShapes();
    void testMatrixMultiplication();


    CPPUNIT_TEST_SUITE(ScExportTest);
    CPPUNIT_TEST(test);
@@ -203,6 +205,8 @@ public:
    CPPUNIT_TEST(testHiddenShape);
    CPPUNIT_TEST(testHyperlinkXLSX);
    CPPUNIT_TEST(testMoveCellAnchoredShapes);
    CPPUNIT_TEST(testMatrixMultiplication);


    CPPUNIT_TEST_SUITE_END();

@@ -2647,7 +2651,6 @@ void ScExportTest::testHiddenShape()
    CPPUNIT_ASSERT(pDoc);
    assertXPath(pDoc, "/xdr:wsDr/xdr:twoCellAnchor/xdr:sp[1]/xdr:nvSpPr/xdr:cNvPr", "hidden", "1");
}

void ScExportTest::testHyperlinkXLSX()
{
    ScDocShellRef xDocSh = loadDoc("hyperlink.", XLSX);
@@ -2821,6 +2824,32 @@ void ScExportTest::testMoveCellAnchoredShapes()
    xDocSh2->DoClose();
}

void ScExportTest::testMatrixMultiplication()
{
    ScDocShellRef xShell = loadDoc("matrix-multiplication.", XLSX);
    CPPUNIT_ASSERT(xShell.Is());

    ScDocShellRef xDocSh = saveAndReload(&(*xShell), XLSX);
    CPPUNIT_ASSERT(xDocSh.Is());

    xmlDocPtr pDoc = XPathHelper::parseExport(&(*xDocSh), m_xSFactory, "xl/worksheets/sheet1.xml", XLSX);
    CPPUNIT_ASSERT(pDoc);

    OUString CellFormulaRange = getXPath(pDoc,
        "/x:worksheet/x:sheetData/x:row[4]/x:c/x:f","ref");

    // make sure that the CellFormulaRange is G5:G6.
    CPPUNIT_ASSERT_EQUAL(OUString("G5:G6"), CellFormulaRange);

    OUString CellFormulaType = getXPath(pDoc,
        "/x:worksheet/x:sheetData/x:row[4]/x:c/x:f","t");

    // make sure that the CellFormulaType is array.
    CPPUNIT_ASSERT_EQUAL(OUString("array"), CellFormulaType);

    xDocSh->DoClose();
}

CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest);

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/filter/excel/xetable.cxx b/sc/source/filter/excel/xetable.cxx
index 2ce7195..38bb673 100644
--- a/sc/source/filter/excel/xetable.cxx
+++ b/sc/source/filter/excel/xetable.cxx
@@ -932,23 +932,59 @@ void XclExpFormulaCell::SaveXml( XclExpXmlStream& rStrm )
            // OOXTODO: XML_cm, XML_vm, XML_ph
            FSEND );

    rWorksheet->startElement( XML_f,
            // OOXTODO: XML_t,      ST_CellFormulaType
            XML_aca,    XclXmlUtils::ToPsz( (mxTokArr && mxTokArr->IsVolatile()) || (mxAddRec && mxAddRec->IsVolatile()) ),
            // OOXTODO: XML_ref,    ST_Ref
            // OOXTODO: XML_dt2D,   bool
            // OOXTODO: XML_dtr,    bool
            // OOXTODO: XML_del1,   bool
            // OOXTODO: XML_del2,   bool
            // OOXTODO: XML_r1,     ST_CellRef
            // OOXTODO: XML_r2,     ST_CellRef
            // OOXTODO: XML_ca,     bool
            // OOXTODO: XML_si,     uint
            // OOXTODO: XML_bx      bool
            FSEND );
    ScAddress aScPos( static_cast< SCCOL >( GetXclPos().mnCol ), static_cast< SCROW >( GetXclPos().mnRow ), rStrm.GetRoot().GetCurrScTab() );

    if ( mrScFmlaCell.GetMatrixFlag() == MM_FORMULA)
    {
        // origin of the matrix - find the used matrix range
        SCCOL nMatWidth;
        SCROW nMatHeight;
        mrScFmlaCell.GetMatColsRows( nMatWidth, nMatHeight );
        OSL_ENSURE( nMatWidth && nMatHeight, "XclExpFormulaCell::XclExpFormulaCell - empty matrix" );
        ScRange aMatScRange( aScPos );
        ScAddress& rMatEnd = aMatScRange.aEnd;
        rMatEnd.IncCol( static_cast< SCsCOL >( nMatWidth - 1 ) );
        rMatEnd.IncRow( static_cast< SCsROW >( nMatHeight - 1 ) );
        // reduce to valid range (range keeps valid, because start position IS valid
        rStrm.GetRoot().GetAddressConverter().ValidateRange( aMatScRange, true );

        OStringBuffer sFmlaCellRange;
        if (ValidRange(aMatScRange))
        {
            // calculate the cell range.
            sFmlaCellRange.append(XclXmlUtils::ToOString( rStrm.GetRoot().GetStringBuf(), aMatScRange.aStart ).getStr());
            sFmlaCellRange.append(":");
            sFmlaCellRange.append(XclXmlUtils::ToOString( rStrm.GetRoot().GetStringBuf(), aMatScRange.aEnd ).getStr());
        }

        if (aMatScRange.aStart.Col() == GetXclPos().mnCol && aMatScRange.aEnd.Row() > static_cast< SCROW >(GetXclPos().mnRow))
        {
            rWorksheet->startElement( XML_f,
                        XML_aca,    XclXmlUtils::ToPsz( (mxTokArr && mxTokArr->IsVolatile()) || (mxAddRec && mxAddRec->IsVolatile()) ),
                        XML_t, mxAddRec ? "array" : NULL,
                        XML_ref, !sFmlaCellRange.isEmpty()? sFmlaCellRange.getStr() : NULL,
                        // OOXTODO: XML_dt2D,   bool
                        // OOXTODO: XML_dtr,    bool
                        // OOXTODO: XML_del1,   bool
                        // OOXTODO: XML_del2,   bool
                        // OOXTODO: XML_r1,     ST_CellRef
                        // OOXTODO: XML_r2,     ST_CellRef
                        // OOXTODO: XML_ca,     bool
                        // OOXTODO: XML_si,     uint
                        // OOXTODO: XML_bx      bool
                        FSEND );
        }
    }
    else
    {
        rWorksheet->startElement( XML_f,
                                  XML_aca,    XclXmlUtils::ToPsz( (mxTokArr && mxTokArr->IsVolatile()) || (mxAddRec && mxAddRec->IsVolatile()) ),
                                  FSEND );
    }
    rWorksheet->writeEscaped( XclXmlUtils::ToOUString(
        rStrm.GetRoot().GetCompileFormulaContext(), mrScFmlaCell.aPos, mrScFmlaCell.GetCode()));
    rWorksheet->endElement( XML_f );

    if( strcmp( sType, "inlineStr" ) == 0 )
    {
        rWorksheet->startElement( XML_is, FSEND );