tdf#131496 vcl image lazy load: speed up vector images with custom pref size

This speeds up the loading of the bugdoc:

- old cost: 6378 ms
- new cost: 1891 ms (30% of baseline)

Images were initially loaded at import time, but commit
acb803b730f2c6bd82e39beab58949ec14f85eb0 (tdf#125591 DOC import:
lazy-load metafiles with explicit size, 2019-06-11) changed this, so
that they are lazy-loaded. That improved performance, but sometimes gave
incorrect results.

Then commit d8371cdfd092c6426c01aae130ea4eaa6d627a6f (tdf#127446 vcl
image lazy-load: fix custom size handling of metafiles, 2019-09-30)
fixed the correctness problem, but the loading was no longer lazy in the
tdf#131496 case.

This is an attempt to bring back lazy-loading for vector-based images,
while maintaining the correct preferred size.

The problem was that the PPT import triggered a vector -> bitmap
conversion during load:

	#0  0x00007ffff03c7e36 in ImpGraphic::loadPrepared() (this=this@entry=0x1f88a90) at vcl/source/gdi/impgraph.cxx:1424
	#1  0x00007ffff03c72c7 in ImpGraphic::ImplSwapIn() (this=0x1f88a90) at vcl/source/gdi/impgraph.cxx:1444
	#2  0x00007ffff03c7535 in ImpGraphic::ensureAvailable() const (this=this@entry=0x1f88a90) at vcl/source/gdi/impgraph.cxx:1402
	#3  0x00007ffff03c9481 in ImpGraphic::ImplExportNative(SvStream&) const (this=0x1f88a90, rOStm=...) at vcl/source/gdi/impgraph.cxx:1590
	#4  0x00007ffff03bf9a8 in Graphic::ExportNative(SvStream&) const (this=this@entry=0x20534e0, rOStream=...) at vcl/source/gdi/graph.cxx:544
	#5  0x00007ffff1c79a28 in svt::EmbeddedObjectRef::SetGraphicToContainer(Graphic const&, comphelper::EmbeddedObjectContainer&, rtl::OUString const&, rtl::OUString const&)
	    (rGraphic=..., aContainer=..., aName="Object 1", aMediaType="") at svtools/source/misc/embedhlp.cxx:773
	#6  0x00007ffff1c79b6f in svt::EmbeddedObjectRef::AssignToContainer(comphelper::EmbeddedObjectContainer*, rtl::OUString const&)
	    (this=0x207ae90, pContainer=pContainer@entry=0x1f8de40, rPersistName=...) at svtools/source/misc/embedhlp.cxx:369
	#7  0x00007ffff239f736 in SdrOle2Obj::Connect_Impl() (this=this@entry=0x20734f0) at svx/source/svdraw/svdoole2.cxx:984
	#8  0x00007ffff23a6310 in SdrOle2Obj::Init() (this=this@entry=0x20734f0) at svx/source/svdraw/svdoole2.cxx:695

Try to defer that conversion by not doing a
maVectorGraphicData->getReplacement() in ImpGraphic::ImplSetPrefSize(),
rather just store the preferred size and apply it later when
getReplacement() is called.

This helps, because the above OLE-from-PPT case loads the graphic, but
only to export it as SVM, so it doesn't need a vector -> bitmap
conversion otherwise.

Change-Id: I24790c0a3e298d5fbb3faff35d529e79cc72845a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/92144
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
diff --git a/vcl/inc/impgraph.hxx b/vcl/inc/impgraph.hxx
index eaf691c1..8fa1df9 100644
--- a/vcl/inc/impgraph.hxx
+++ b/vcl/inc/impgraph.hxx
@@ -56,6 +56,8 @@ private:

    GDIMetaFile                  maMetaFile;
    BitmapEx                     maEx;
    /// If maEx is empty, this preferred size will be set on it when it gets initialized.
    Size                         maExPrefSize;
    ImpSwapInfo                  maSwapInfo;
    std::unique_ptr<Animation>   mpAnimation;
    std::shared_ptr<GraphicReader> mpContext;
@@ -195,6 +197,9 @@ private:

    const std::shared_ptr<VectorGraphicData>& getVectorGraphicData() const;

    /// Gets the bitmap replacement for a vector graphic.
    BitmapEx getVectorGraphicReplacement() const;

    bool ensureAvailable () const;

    bool loadPrepared();
diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx
index 292c0bc..6ea0685 100644
--- a/vcl/source/gdi/impgraph.cxx
+++ b/vcl/source/gdi/impgraph.cxx
@@ -490,6 +490,18 @@ bool ImpGraphic::makeAvailable()
    return ensureAvailable();
}

BitmapEx ImpGraphic::getVectorGraphicReplacement() const
{
    BitmapEx aRet = maVectorGraphicData->getReplacement();

    if (maExPrefSize.getWidth() && maExPrefSize.getHeight())
    {
        aRet.SetPrefSize(maExPrefSize);
    }

    return aRet;
}

Bitmap ImpGraphic::ImplGetBitmap(const GraphicConversionParameters& rParameters) const
{
    Bitmap aRetBmp;
@@ -501,7 +513,7 @@ Bitmap ImpGraphic::ImplGetBitmap(const GraphicConversionParameters& rParameters)
        if(maVectorGraphicData.get() && maEx.IsEmpty())
        {
            // use maEx as local buffer for rendered svg
            const_cast< ImpGraphic* >(this)->maEx = maVectorGraphicData->getReplacement();
            const_cast< ImpGraphic* >(this)->maEx = getVectorGraphicReplacement();
        }

        const BitmapEx& rRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx );
@@ -610,7 +622,7 @@ BitmapEx ImpGraphic::ImplGetBitmapEx(const GraphicConversionParameters& rParamet
        if(maVectorGraphicData.get() && maEx.IsEmpty())
        {
            // use maEx as local buffer for rendered svg
            const_cast< ImpGraphic* >(this)->maEx = maVectorGraphicData->getReplacement();
            const_cast< ImpGraphic* >(this)->maEx = getVectorGraphicReplacement();
        }

        aRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx );
@@ -697,7 +709,7 @@ const GDIMetaFile& ImpGraphic::ImplGetGDIMetaFile() const
        if(maVectorGraphicData.get() && !maEx)
        {
            // use maEx as local buffer for rendered svg
            pThat->maEx = maVectorGraphicData->getReplacement();
            pThat->maEx = getVectorGraphicReplacement();
        }

        // #123983# directly create a metafile with the same PrefSize and PrefMapMode
@@ -752,10 +764,17 @@ Size ImpGraphic::ImplGetPrefSize() const
            {
                if(maVectorGraphicData.get() && maEx.IsEmpty())
                {
                    // svg not yet buffered in maEx, return size derived from range
                    const basegfx::B2DRange& rRange = maVectorGraphicData->getRange();
                    if (!maExPrefSize.getWidth() || !maExPrefSize.getHeight())
                    {
                        // svg not yet buffered in maEx, return size derived from range
                        const basegfx::B2DRange& rRange = maVectorGraphicData->getRange();

                    aSize = Size(basegfx::fround(rRange.getWidth()), basegfx::fround(rRange.getHeight()));
                        aSize = Size(basegfx::fround(rRange.getWidth()), basegfx::fround(rRange.getHeight()));
                    }
                    else
                    {
                        aSize = maExPrefSize;
                    }
                }
                else
                {
@@ -797,8 +816,7 @@ void ImpGraphic::ImplSetPrefSize( const Size& rPrefSize )
            // to allow setting the PrefSize at the BitmapEx to hold it
            if(maVectorGraphicData.get() && maEx.IsEmpty())
            {
                // use maEx as local buffer for rendered svg
                maEx = maVectorGraphicData->getReplacement();
                maExPrefSize = rPrefSize;
            }

            // #108077# Push through pref size to animation object,
@@ -808,7 +826,10 @@ void ImpGraphic::ImplSetPrefSize( const Size& rPrefSize )
                const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefSize( rPrefSize );
            }

            maEx.SetPrefSize( rPrefSize );
            if (!maExPrefSize.getWidth() || !maExPrefSize.getHeight())
            {
                maEx.SetPrefSize( rPrefSize );
            }
        }
        break;

@@ -881,7 +902,7 @@ void ImpGraphic::ImplSetPrefMapMode( const MapMode& rPrefMapMode )
            if(maVectorGraphicData.get())
            {
                // ignore for Vector Graphic Data. If this is really used (except the grfcache)
                // it can be extended by using maEx as buffer for maVectorGraphicData->getReplacement()
                // it can be extended by using maEx as buffer for getVectorGraphicReplacement()
            }
            else
            {
@@ -953,7 +974,7 @@ void ImpGraphic::ImplDraw( OutputDevice* pOutDev, const Point& rDestPt ) const
                if(maVectorGraphicData.get() && !maEx)
                {
                    // use maEx as local buffer for rendered svg
                    const_cast< ImpGraphic* >(this)->maEx = maVectorGraphicData->getReplacement();
                    const_cast< ImpGraphic* >(this)->maEx = getVectorGraphicReplacement();
                }

                if ( mpAnimation )
@@ -990,7 +1011,7 @@ void ImpGraphic::ImplDraw( OutputDevice* pOutDev,
                if(maVectorGraphicData.get() && maEx.IsEmpty())
                {
                    // use maEx as local buffer for rendered svg
                    const_cast< ImpGraphic* >(this)->maEx = maVectorGraphicData->getReplacement();
                    const_cast< ImpGraphic* >(this)->maEx = getVectorGraphicReplacement();
                }

                if( mpAnimation )
@@ -1138,7 +1159,7 @@ bool ImpGraphic::ImplReadEmbedded( SvStream& rIStm )
            if(maVectorGraphicData.get() && maEx.IsEmpty())
            {
                // use maEx as local buffer for rendered svg
                maEx = maVectorGraphicData->getReplacement();
                maEx = getVectorGraphicReplacement();
            }

            maEx.SetSizePixel(aSize);