tdf#108037 Reduce time and memory consumed exporting to PDF

by avoiding making multiple copies of the Primitive2D container
that we pass to TransformPrimitive2D.
Instead, make TransformPrimitive2D store its children using a
GroupPrimitive2D, which means we can share the GroupPrimitive2D
among all the TransformPrimitive2D instances we create.

Change-Id: I8a4398f9db6a6ab013ee24ad53836975fba6f3df
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162951
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/drawinglayer/source/primitive2d/fillgraphicprimitive2d.cxx b/drawinglayer/source/primitive2d/fillgraphicprimitive2d.cxx
index 8c50993..bc91586 100644
--- a/drawinglayer/source/primitive2d/fillgraphicprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/fillgraphicprimitive2d.cxx
@@ -70,11 +70,12 @@ namespace drawinglayer::primitive2d
                    rGraphic,
                    basegfx::B2DHomMatrix());

                rtl::Reference<GroupPrimitive2D> xGroup = new GroupPrimitive2D(std::move(xSeq));
                for(const auto &a : aMatrices)
                {
                    rContainer.push_back(new TransformPrimitive2D(
                        getTransformation() * a,
                        Primitive2DContainer(xSeq)));
                        *xGroup));
                }
            }
            else
diff --git a/drawinglayer/source/primitive2d/transformprimitive2d.cxx b/drawinglayer/source/primitive2d/transformprimitive2d.cxx
index 0442cd6..8c36fa9 100644
--- a/drawinglayer/source/primitive2d/transformprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/transformprimitive2d.cxx
@@ -19,6 +19,7 @@

#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
#include <drawinglayer/primitive2d/Tools.hxx>
#include <utility>


@@ -30,18 +31,27 @@ namespace drawinglayer::primitive2d
        TransformPrimitive2D::TransformPrimitive2D(
            basegfx::B2DHomMatrix aTransformation,
            Primitive2DContainer&& aChildren)
        :   GroupPrimitive2D(std::move(aChildren)),
            maTransformation(std::move(aTransformation))
        :   maTransformation(std::move(aTransformation)),
            mxChildren(new GroupPrimitive2D(std::move(aChildren)))
        {
        }

        TransformPrimitive2D::TransformPrimitive2D(
            basegfx::B2DHomMatrix aTransformation,
            GroupPrimitive2D& rChildren)
        :   maTransformation(std::move(aTransformation)),
            mxChildren(&rChildren)
        {
        }

        bool TransformPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
        {
            if(GroupPrimitive2D::operator==(rPrimitive))
            if(BasePrimitive2D::operator==(rPrimitive))
            {
                const TransformPrimitive2D& rCompare = static_cast< const TransformPrimitive2D& >(rPrimitive);

                return (getTransformation() == rCompare.getTransformation());
                return maTransformation == rCompare.maTransformation
                    && arePrimitive2DReferencesEqual(mxChildren, rCompare.mxChildren);
            }

            return false;
diff --git a/include/drawinglayer/primitive2d/transformprimitive2d.hxx b/include/drawinglayer/primitive2d/transformprimitive2d.hxx
index 73e589b..8c3c22c 100644
--- a/include/drawinglayer/primitive2d/transformprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/transformprimitive2d.hxx
@@ -46,19 +46,24 @@ namespace drawinglayer::primitive2d
            different, transformed states without the need to create those
            thousand primitive contents.
         */
        class DRAWINGLAYER_DLLPUBLIC TransformPrimitive2D final : public GroupPrimitive2D
        class DRAWINGLAYER_DLLPUBLIC TransformPrimitive2D final : public BasePrimitive2D
        {
        private:
            // the transformation to apply to the child geometry
            basegfx::B2DHomMatrix                   maTransformation;
            rtl::Reference<GroupPrimitive2D>        mxChildren;

        public:
            /// constructor
            TransformPrimitive2D(
                basegfx::B2DHomMatrix aTransformation,
                Primitive2DContainer&& rChildren);
            TransformPrimitive2D(
                basegfx::B2DHomMatrix aTransformation,
                GroupPrimitive2D& rChildren);

            /// data read access
            const Primitive2DContainer& getChildren() const { return mxChildren->getChildren(); }
            const basegfx::B2DHomMatrix& getTransformation() const { return maTransformation; }

            /// compare operator
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx
index d99e56b..13dff82 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -8,6 +8,7 @@
 */

#include <sal/config.h>
#include <sal/log.hxx>

#include <test/bootstrapfixture.hxx>
#include <test/xmltesttools.hxx>
@@ -83,12 +84,27 @@ namespace
{
bool arePrimitive2DSequencesEqual(const Primitive2DSequence& rA, const Primitive2DSequence& rB)
{
    return std::equal(rA.begin(), rA.end(), rB.begin(), rB.end(),
    auto rv = std::mismatch(rA.begin(), rA.end(), rB.begin(), rB.end(),
        [](const css::uno::Reference<css::graphic::XPrimitive2D>& a,
           const css::uno::Reference<css::graphic::XPrimitive2D>& b)
        {
            return drawinglayer::primitive2d::arePrimitive2DReferencesEqual(a, b);
        });
    if (rv.first == rA.end() && rv.second == rB.end())
        return true;
    if (rv.first == rA.end() || rv.second == rB.end())
    {
        SAL_WARN("svgio",
                "first seq length == " << rA.size() <<
                "second seq length == " << rB.size());
        return false;
    }
    auto idx = std::distance(rA.begin(), rv.first);
    SAL_WARN("svgio",
            "first difference at index " << idx <<
            " expected element " << typeid(*rA[idx]).name() <<
            " but got element " << typeid(*rB[idx]).name());
    return false;
}
}