tdf#134734 xmloff: ODF import compatibility for BackgroundFullSize

This is annoyingly complex because LO 6.3 changed the way backgrounds
are painted in an inconsistent way.

Use the generator version to guess what the document should look like,
which of course will give the wrong result if it was created before LO
6.3 and then round-tripped with LO 6.3.

Since LO 7.0 at least a hard-coded draw:background-size was written.

Change-Id: If9c5d2b32bfa50cbe4fb166132f7223763af850f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112770
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
diff --git a/include/xmloff/xmlimp.hxx b/include/xmloff/xmlimp.hxx
index 12a81a3..191f6aa 100644
--- a/include/xmloff/xmlimp.hxx
+++ b/include/xmloff/xmlimp.hxx
@@ -556,6 +556,7 @@ public:
    /// @ATTENTION: when adding a new value more specific than "6x", grep for
    /// all current uses and adapt them!!!
    static const sal_uInt16 LO_6x = 60 | LO_flag;
    static const sal_uInt16 LO_63x = 63 | LO_flag;
    static const sal_uInt16 LO_7x = 70 | LO_flag;
    static const sal_uInt16 ProductVersionUnknown = SAL_MAX_UINT16;

diff --git a/sw/qa/extras/odfexport/data/pagestyle_background_lo64.odt b/sw/qa/extras/odfexport/data/pagestyle_background_lo64.odt
new file mode 100644
index 0000000..c8b3c3f
--- /dev/null
+++ b/sw/qa/extras/odfexport/data/pagestyle_background_lo64.odt
Binary files differ
diff --git a/sw/qa/extras/odfexport/data/pagestyle_background_ooo33.odt b/sw/qa/extras/odfexport/data/pagestyle_background_ooo33.odt
new file mode 100644
index 0000000..92098d0
--- /dev/null
+++ b/sw/qa/extras/odfexport/data/pagestyle_background_ooo33.odt
Binary files differ
diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx
index e307ea6..841019b 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -1887,6 +1887,169 @@ DECLARE_ODFEXPORT_TEST(testMasterPageWithDrawingPage, "sw_hatch.odt")
    CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty<sal_Int16>(xStyle, "FillTransparence"));
}

DECLARE_ODFEXPORT_EXPORTONLY_TEST(testPageStyleBackgroundFullSizeOOo, "pagestyle_background_ooo33.odt")
{
    xmlDocUniquePtr pXmlDoc = parseExport("styles.xml");
    // Standard
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Standard']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "background-size", "border");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Standard']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill", "solid");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Standard']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill-color", "#99ccff");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Standard']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "opacity", "100%");
    // Endnote
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Endnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "background-size", "border");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Endnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill", "bitmap");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Endnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "repeat", "repeat");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Endnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill-image-ref-point", "top-left");
    // Footnote
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Footnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "background-size", "border");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Footnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill", "bitmap");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Footnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "repeat", "stretch");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Footnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill-image-ref-point", "top-left");
}

DECLARE_ODFEXPORT_EXPORTONLY_TEST(testPageStyleBackgroundFullSizeLO64, "pagestyle_background_lo64.odt")
{
    xmlDocUniquePtr pXmlDoc = parseExport("styles.xml");
    // Standard
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Standard']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "background-size", "full");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Standard']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill", "solid");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Standard']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill-color", "#99ccff");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Standard']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "opacity", "100%");
    // Endnote
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Endnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "background-size", "full");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Endnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill", "bitmap");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Endnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "repeat", "repeat");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Endnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill-image-ref-point", "top-left");
    // Footnote
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Footnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "background-size", "border");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Footnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill", "bitmap");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Footnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "repeat", "stretch");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Footnote']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill-image-ref-point", "top-left");
    // Landscape
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Landscape']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "background-size", "border");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Landscape']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill", "bitmap");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Landscape']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "repeat", "no-repeat");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Landscape']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill-image-ref-point", "top-left");
    // Index
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Index']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "background-size", "full");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Index']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill", "gradient");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Index']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "gradient-step-count", "0");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='Index']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "opacity", "100%");
    // First Page
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='First_20_Page']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "background-size", "full");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='First_20_Page']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill", "hatch");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='First_20_Page']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "fill-hatch-solid", "false");
    assertXPath(pXmlDoc,
        "/office:document-styles/office:automatic-styles/style:style[@style:family='drawing-page' and @style:name = "
        "/office:document-styles/office:master-styles/style:master-page[@style:name='First_20_Page']/attribute::draw:style-name"
        "]/style:drawing-page-properties", "opacity", "100%");
}

DECLARE_ODFEXPORT_EXPORTONLY_TEST(testPageStyleBackgroundFullSizeLO70, "pagestyle_background_lo70.odt")
{
    xmlDocUniquePtr pXmlDoc = parseExport("styles.xml");
diff --git a/xmloff/qa/unit/uxmloff.cxx b/xmloff/qa/unit/uxmloff.cxx
index b5aff93..1efd05d 100644
--- a/xmloff/qa/unit/uxmloff.cxx
+++ b/xmloff/qa/unit/uxmloff.cxx
@@ -197,6 +197,9 @@ void Test::testMetaGenerator()
        { "Collabora_Office/5.3.10.27$Linux_X86_64 LibreOffice_project/7a5a5378661e338a44666c08773cc796b8d1c84a", ";531027", SvXMLImport::LO_5x },
        { "LibreOfficeDev/5.4.7.0.0$Linux_X86_64 LibreOffice_project/ba7461fc88c08e75e315f786020a2946e56166c9", ";54700", SvXMLImport::LO_5x },
        { "LibreOfficeDev/6.0.3.0.0$Linux_X86_64 LibreOffice_project/34442b85bfb0c451738b4db023345a7484463321", ";60300", SvXMLImport::LO_6x },
        { "LibreOffice_powered_by_CIBDev/6.3.9.0.0$Linux_X86_64 LibreOffice_project/c87f331d2900eab70ac3021cbe530926efa6499f", ";63900", SvXMLImport::LO_63x },
        { "LibreOffice_powered_by_CIBDev/6.4.0.0.0$Linux_X86_64 LibreOffice_project/e29e100174c133d27e953934311d68602c4515b7", ";64000", SvXMLImport::LO_63x },
        { "LibreOfficeDev/7.0.6.0.0$Linux_X86_64 LibreOffice_project/dfc40e2292c6e19e285c10ed8c8044d9454107d0", ";70600", SvXMLImport::LO_7x },
    };

    for (size_t i = 0; i < SAL_N_ELEMENTS(tests); ++i)
diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx
index 6d7b080..7e904af 100644
--- a/xmloff/source/core/xmlimp.cxx
+++ b/xmloff/source/core/xmlimp.cxx
@@ -195,7 +195,16 @@ public:
                    }
                    else if ('6' == loVersion[0])
                    {
                        mnGeneratorVersion = SvXMLImport::LO_6x;
                        if (loVersion.getLength() > 1
                            && (loVersion[1] == '0' || loVersion[1] == '1'
                                || loVersion[1] == '2'))
                        {
                            mnGeneratorVersion = SvXMLImport::LO_6x; // 6.0/6.1/6.2
                        }
                        else
                        {
                            mnGeneratorVersion = SvXMLImport::LO_63x; // 6.3/6.4
                        }
                    }
                    else if ('7' == loVersion[0])
                    {
diff --git a/xmloff/source/style/PageMasterImportContext.cxx b/xmloff/source/style/PageMasterImportContext.cxx
index 17d9bf7..685d82b 100644
--- a/xmloff/source/style/PageMasterImportContext.cxx
+++ b/xmloff/source/style/PageMasterImportContext.cxx
@@ -33,6 +33,8 @@
//
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/BitmapMode.hpp>
#include <xmloff/xmlerror.hxx>
#include <xmloff/XMLTextMasterPageContext.hxx>

@@ -158,7 +160,7 @@ void PageStyleContext::FillPropertySet(const uno::Reference<beans::XPropertySet 
}

void PageStyleContext::FillPropertySet_PageStyle(
        const uno::Reference<beans::XPropertySet> & rPropSet,
        const uno::Reference<beans::XPropertySet> & xPropSet,
        XMLPropStyleContext *const pDrawingPageStyle)
{
    // need to filter out old fill definitions when the new ones are used. The new
@@ -229,7 +231,7 @@ void PageStyleContext::FillPropertySet_PageStyle(
        };

        // Fill PropertySet, but let it handle special properties not itself
        xImpPrMap->FillPropertySet(GetProperties(), rPropSet, aContextIDs);
        xImpPrMap->FillPropertySet(GetProperties(), xPropSet, aContextIDs);

        // get property set mapper
        const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper();
@@ -273,12 +275,12 @@ void PageStyleContext::FillPropertySet_PageStyle(

                            if(!xInfo.is())
                            {
                                xInfo = rPropSet->getPropertySetInfo();
                                xInfo = xPropSet->getPropertySetInfo();
                            }

                            if(xInfo->hasPropertyByName(rPropertyName))
                            {
                                rPropSet->setPropertyValue(rPropertyName,Any(sStyleName));
                                xPropSet->setPropertyValue(rPropertyName,Any(sStyleName));
                            }
                        }
                        catch(css::lang::IllegalArgumentException& e)
@@ -302,7 +304,71 @@ void PageStyleContext::FillPropertySet_PageStyle(
    // pDrawingPageStyle overrides this
    if (pDrawingPageStyle)
    {
        pDrawingPageStyle->FillPropertySet(rPropSet);
        pDrawingPageStyle->FillPropertySet(xPropSet);
    }
    // horrible heuristic to guess BackgroundFullSize for Writer < 7.0
    else if (!IsDefaultStyle() // ignore pool default, only fix existing styles
            && (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x)
            // also for AOO 4.x, assume there won't ever be a 4.2
            || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x))
    {
        bool isFullSize(true); // default is current LO default
        drawing::FillStyle fillStyle{drawing::FillStyle_NONE};
        xPropSet->getPropertyValue("FillStyle") >>= fillStyle;
        if (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_63x)
            // also for AOO 4.x, assume there won't ever be a 4.2
            || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x)
        {
            // before LO 6.3, always inside the margins (but ignore it if NONE)
            if (fillStyle != drawing::FillStyle_NONE)
            {
                isFullSize = false;
            }
        }
        else
        {
            // LO 6.3/6.4: guess depending on fill style/bitmap mode
            // this should work even if the document doesn't contain fill style
            // but only old background attributes
            // (can't use the aContextIDs stuff above because that requires
            //  re-routing through handleSpecialItem())
            switch (fillStyle)
            {
                case drawing::FillStyle_NONE:
                    break;
                case drawing::FillStyle_SOLID:
                case drawing::FillStyle_GRADIENT:
                case drawing::FillStyle_HATCH:
                    isFullSize = true;
                    break;
                case drawing::FillStyle_BITMAP:
                    {
                        drawing::BitmapMode bitmapMode{};
                        xPropSet->getPropertyValue("FillBitmapMode") >>= bitmapMode;
                        switch (bitmapMode)
                        {
                            case drawing::BitmapMode_REPEAT:
                                isFullSize = true;
                                break;
                            case drawing::BitmapMode_STRETCH:
                            case drawing::BitmapMode_NO_REPEAT:
                                isFullSize = false;
                                break;
                            default:
                                assert(false);
                        }
                    }
                    break;
                default:
                    assert(false);
            }
        }
        // set it explicitly if it's not the default
        if (!isFullSize)
        {
            SAL_INFO("xmloff.style", "FillPropertySet_PageStyle: Heuristically resetting BackgroundFullSize");
            xPropSet->setPropertyValue("BackgroundFullSize", uno::makeAny(isFullSize));
        }
    }

    // old code, replaced by above stuff
@@ -313,7 +379,7 @@ void PageStyleContext::FillPropertySet_PageStyle(
        uno::Any aPageUsage;
        XMLPMPropHdl_PageStyleLayout aPageUsageHdl;
        if (aPageUsageHdl.importXML(sPageUsage, aPageUsage, GetImport().GetMM100UnitConverter()))
            rPropSet->setPropertyValue("PageStyleLayout", aPageUsage);
            xPropSet->setPropertyValue("PageStyleLayout", aPageUsage);
    }
}