tdf#117217 ww8: export/import all cell backgrounds

... using TDefTableShd2nd and TDefTableShd3rd

P.S. There might be some other subtleties going on here.
> sprmTDefTableShdRaw:
> If a cell is set to ShdAuto in rgShd, the cell is
> not shaded. If a cell is set to ShdNil in rgShd, the cell is shaded
> according to the table style. By default, cells are shaded according
> to the table style.
(sprmTDefTableShdRaw not imported in LO, and ShdNil unknown)

> sprmTDefTableShd:
> If nFib is greater than 0x00D9 and the application understands
> table styles, then this Sprm MUST be ignored.
(aka NewShd from MSO 2000ish - never ignored by LO, and almost certainly
LO doesn't understand these table styles despite ?nFib == 0x0101? )

These seem to be very "late" modifications to the .doc format,
so likely very few things support the advanced features.
In any case, I haven't done anything novel here - just copying
what was done for template1 into template2 and template3,
so these subtleties are irrelevant for this patch.

Change-Id: Ic330179cf771a6f2531ed75dfb441fba10a04c7c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/98856
Tested-by: Justin Luth <justin_luth@sil.org>
Reviewed-by: Justin Luth <justin_luth@sil.org>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
diff --git a/sw/qa/extras/ww8export/data/tdf117217_largeTableBackgrounds.odt b/sw/qa/extras/ww8export/data/tdf117217_largeTableBackgrounds.odt
new file mode 100644
index 0000000..bbb1eaa
--- /dev/null
+++ b/sw/qa/extras/ww8export/data/tdf117217_largeTableBackgrounds.odt
Binary files differ
diff --git a/sw/qa/extras/ww8export/ww8export3.cxx b/sw/qa/extras/ww8export/ww8export3.cxx
index 13da2fe..460937c 100644
--- a/sw/qa/extras/ww8export/ww8export3.cxx
+++ b/sw/qa/extras/ww8export/ww8export3.cxx
@@ -417,6 +417,18 @@ DECLARE_WW8EXPORT_TEST(testTdf128608_tableParaBackColor, "tdf128608_tableParaBac
    CPPUNIT_ASSERT_EQUAL_MESSAGE("No fillstyle", drawing::FillStyle_NONE, getProperty<drawing::FillStyle>(xPara, "FillStyle"));
}

DECLARE_WW8EXPORT_TEST(testTdf117217_largeTableBackgrounds, "tdf117217_largeTableBackgrounds.odt")
{
    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTextTablesSupplier->getTextTables(), uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
    // Cell 22: light-red == 16711680
    uno::Reference<text::XTextRange> xCell(xTable->getCellByName("V1"), uno::UNO_QUERY_THROW);
    CPPUNIT_ASSERT_EQUAL_MESSAGE("light red", sal_Int32(0xE0C2CD), getProperty<sal_Int32>(xCell, "BackColor"));
    xCell.set(xTable->getCellByName("Z1"), uno::UNO_QUERY_THROW);
    CPPUNIT_ASSERT_EQUAL_MESSAGE("light red", sal_Int32(0xE0C2CD), getProperty<sal_Int32>(xCell, "BackColor"));
}

DECLARE_WW8EXPORT_TEST(testTdf94009_zeroPgMargin, "tdf94009_zeroPgMargin.odt")
{
    CPPUNIT_ASSERT_EQUAL(1, getPages());
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index c22eae5..294ce056 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -2683,18 +2683,49 @@ void WW8AttributeOutput::TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t
        m_rWW8Export.InsUInt16( aShd.GetValue() );
    }

/*sprmTDefTableShdRaw:
 * A DefTableShdOperand value that specifies the ... shading for cells 1 up to 22 in the row,
 * ... Cells 23 to 44 are shaded by sprmTDefTableShdRaw2nd,
 * and cells 45 to 63 are shaded by sprmTDefTableShdRaw3rd.
 */
    sal_uInt32 const aSprmIds[] { NS_sprm::TDefTableShd::val,
                                  NS_sprm::TDefTableShdRaw::val };
    sal_uInt8 nBoxes0 = rTabBoxes.size();
    if (nBoxes0 > 21)
        nBoxes0 = 21;

                                  NS_sprm::TDefTableShdRaw::val,
                                  NS_sprm::TDefTableShdRaw::val,
                                  NS_sprm::TDefTableShd2nd::val,
                                  NS_sprm::TDefTableShdRaw2nd::val,
                                  NS_sprm::TDefTableShd3rd::val,
                                  NS_sprm::TDefTableShdRaw3rd::val };
    for (sal_uInt32 m : aSprmIds)
    {
        m_rWW8Export.InsUInt16( m );
        m_rWW8Export.pO->push_back( static_cast<sal_uInt8>(nBoxes0 * 10) );
        sal_uInt8 nStart = 0;
        sal_uInt8 nStop = rTabBoxes.size();
        switch ( m )
        {
            case NS_sprm::TDefTableShd::val:
            case NS_sprm::TDefTableShdRaw::val:
                if ( nStop > 21 )
                    nStop = 22;
                break;
            case NS_sprm::TDefTableShd2nd::val:
            case NS_sprm::TDefTableShdRaw2nd::val:
                nStart = 22;
                if ( nStop > 43 )
                    nStop = 44;
                break;
            case NS_sprm::TDefTableShd3rd::val:
            case NS_sprm::TDefTableShdRaw3rd::val:
                nStart = 44;
                if ( nStop > 62 )
                    nStop = 63;
                break;
        }
        if ( nStart >= nStop )
            break;

        for ( sal_uInt8 n = 0; n < nBoxes0; n++ )
        m_rWW8Export.InsUInt16( m );
        m_rWW8Export.pO->push_back( static_cast<sal_uInt8>((nStop-nStart) * 10) );

        for ( sal_uInt8 n = nStart; n < nStop; n++ )
        {
            const SwTableBox * pBox1 = rTabBoxes[n];
            const SwFrameFormat * pFrameFormat = pBox1->GetFrameFormat();
diff --git a/sw/source/filter/ww8/ww8par.hxx b/sw/source/filter/ww8/ww8par.hxx
index 810b692..2ff459b 100644
--- a/sw/source/filter/ww8/ww8par.hxx
+++ b/sw/source/filter/ww8/ww8par.hxx
@@ -1058,7 +1058,7 @@ struct WW8TabBandDesc
    void ProcessSpacing(const sal_uInt8* pParamsTInsert);
    void ProcessSpecificSpacing(const sal_uInt8* pParamsTInsert);
    void ReadShd(const sal_uInt8* pS );
    void ReadNewShd(const sal_uInt8* pS, bool bVer67);
    void ReadNewShd(const sal_uInt8* pS, bool bVer67, sal_uInt8 nStart);

    enum wwDIR {wwTOP = 0, wwLEFT = 1, wwBOTTOM = 2, wwRIGHT = 3};

diff --git a/sw/source/filter/ww8/ww8par2.cxx b/sw/source/filter/ww8/ww8par2.cxx
index 4addec4..bda2cb2 100644
--- a/sw/source/filter/ww8/ww8par2.cxx
+++ b/sw/source/filter/ww8/ww8par2.cxx
@@ -1593,20 +1593,20 @@ void WW8TabBandDesc::ReadShd(const sal_uInt8* pS )
        pSHDs[i].SetWWValue( *pShd );
}

void WW8TabBandDesc::ReadNewShd(const sal_uInt8* pS, bool bVer67)
void WW8TabBandDesc::ReadNewShd(const sal_uInt8* pS, bool bVer67, sal_uInt8 nStart)
{
    sal_uInt8 nLen = pS ? *(pS - 1) : 0;
    if (!nLen)
    if (!nLen || nStart >= nWwCols)
        return;

    if (!pNewSHDs)
        pNewSHDs = new Color[nWwCols];

    short nCount = nLen / 10; //10 bytes each
    short nCount = nLen / 10 + nStart; //10 bytes each
    if (nCount > nWwCols)
        nCount = nWwCols;

    int i=0;
    int i=nStart;
    while (i < nCount)
        pNewSHDs[i++] = SwWW8ImplReader::ExtractColour(pS, bVer67);

@@ -1637,7 +1637,8 @@ enum wwTableSprm
    sprmTDefTable, sprmTDyaRowHeight, sprmTDefTableShd, sprmTDxaLeft,
    sprmTSetBrc, sprmTSetBrc90, sprmTDxaCol, sprmTInsert, sprmTDelete,
    sprmTTableHeader, sprmTDxaGapHalf, sprmTTableBorders, sprmTTableBorders90,
    sprmTDefTableNewShd, sprmTCellPadding, sprmTCellPaddingDefault
    sprmTDefTableNewShd, sprmTDefTableNewShd2nd, sprmTDefTableNewShd3rd,
    sprmTCellPadding, sprmTCellPaddingDefault
};

}
@@ -1681,6 +1682,10 @@ static wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
                    return sprmTDefTableShd;
                case NS_sprm::TDefTableShd::val:
                    return sprmTDefTableNewShd;
                case NS_sprm::TDefTableShd2nd::val:
                    return sprmTDefTableNewShd2nd;
                case NS_sprm::TDefTableShd3rd::val:
                    return sprmTDefTableNewShd3rd;
                case NS_sprm::TTableBorders::val:
                    return sprmTTableBorders90;
                case NS_sprm::TSetBrc80::val:
@@ -1810,7 +1815,7 @@ WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
        short nTabeDxaNew      = SHRT_MAX;
        bool bTabRowJustRead   = false;
        const sal_uInt8* pShadeSprm = nullptr;
        const sal_uInt8* pNewShadeSprm = nullptr;
        const sal_uInt8* pNewShadeSprm[3] = {nullptr, nullptr, nullptr};
        const sal_uInt8* pTableBorders = nullptr;
        sal_uInt16 nTableBordersLen = 0;
        const sal_uInt8* pTableBorders90 = nullptr;
@@ -1905,7 +1910,13 @@ WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
                        pShadeSprm = pParams;
                        break;
                    case sprmTDefTableNewShd:
                        pNewShadeSprm = pParams;
                        pNewShadeSprm[0] = pParams;
                        break;
                    case sprmTDefTableNewShd2nd:
                        pNewShadeSprm[1] = pParams;
                        break;
                    case sprmTDefTableNewShd3rd:
                        pNewShadeSprm[2] = pParams;
                        break;
                    case sprmTDxaLeft:
                        // our Writer cannot shift single table lines
@@ -1963,8 +1974,12 @@ WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
            // so they were saved up until here
            if (pShadeSprm)
                pNewBand->ReadShd(pShadeSprm);
            if (pNewShadeSprm)
                pNewBand->ReadNewShd(pNewShadeSprm, bOldVer);
            if (pNewShadeSprm[0])
                pNewBand->ReadNewShd(pNewShadeSprm[0], bOldVer, /*nStart=*/0);
            if (pNewShadeSprm[1])
                pNewBand->ReadNewShd(pNewShadeSprm[1], bOldVer, /*nStart=*/22);
            if (pNewShadeSprm[2])
                pNewBand->ReadNewShd(pNewShadeSprm[2], bOldVer, /*nStart=*/44);
            if (pTableBorders90)
                pNewBand->ProcessSprmTTableBorders(9, pTableBorders90, nTableBorders90Len);
            else if (pTableBorders)