tdf#50613 add support to load charts asynchronously

Generating primitives for chart visualisation can be moved to a
paralell executed task that loads the chart, thus speeding up
initial visualization. This is not possible for e.g. PDF or print
targets, only for edit visualization. On fallback, the replacement
images of the charts are used which are metafiles and have less
quality as primitives, but load quicker.

Change-Id: I68caa9e1bec50832bce535b5f54633d53cdef037
diff --git a/drawinglayer/source/primitive2d/textlayoutdevice.cxx b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
index e249ddd..a7eb749 100644
--- a/drawinglayer/source/primitive2d/textlayoutdevice.cxx
+++ b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
@@ -85,7 +85,6 @@ namespace
    ImpTimedRefDev::~ImpTimedRefDev()
    {
        OSL_ENSURE(0L == mnUseCount, "destruction of a still used ImpTimedRefDev (!)");
        const SolarMutexGuard aGuard;
        mpVirDev.disposeAndClear();
    }

@@ -152,7 +151,8 @@ namespace drawinglayer
        }

        TextLayouterDevice::TextLayouterDevice()
        :   mrDevice(acquireGlobalVirtualDevice())
        :   maSolarGuard(),
            mrDevice(acquireGlobalVirtualDevice())
        {
        }

diff --git a/include/drawinglayer/primitive2d/textlayoutdevice.hxx b/include/drawinglayer/primitive2d/textlayoutdevice.hxx
index e606f09..5761d3a 100644
--- a/include/drawinglayer/primitive2d/textlayoutdevice.hxx
+++ b/include/drawinglayer/primitive2d/textlayoutdevice.hxx
@@ -26,6 +26,7 @@
#include <vector>
#include <com/sun/star/lang/Locale.hpp>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <vcl/svapp.hxx>

// predefines
class VirtualDevice;
@@ -57,6 +58,7 @@ namespace drawinglayer
        class DRAWINGLAYER_DLLPUBLIC TextLayouterDevice
        {
            /// internally used VirtualDevice
            SolarMutexGuard                 maSolarGuard;
            VirtualDevice&                  mrDevice;

        public:
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx
index 63bfcdd..8a6a741 100644
--- a/svx/source/svdraw/svdotextdecomposition.cxx
+++ b/svx/source/svdraw/svdotextdecomposition.cxx
@@ -686,6 +686,7 @@ void SdrTextObj::impDecomposeContourTextPrimitive(
    aPolyPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(fabs(aScale.getX()), fabs(aScale.getY())));

    // prepare outliner
    SolarMutexGuard aSolarGuard;
    SdrOutliner& rOutliner = ImpGetDrawOutliner();
    const Size aNullSize;
    rOutliner.SetPaperSize(aNullSize);
@@ -737,6 +738,7 @@ void SdrTextObj::impDecomposeAutoFitTextPrimitive(

    // prepare outliner
    const SfxItemSet& rTextItemSet = rSdrAutofitTextPrimitive.getSdrText()->GetItemSet();
    SolarMutexGuard aSolarGuard;
    SdrOutliner& rOutliner = ImpGetDrawOutliner();
    SdrTextVertAdjust eVAdj = GetTextVerticalAdjust(rTextItemSet);
    SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust(rTextItemSet);
@@ -871,6 +873,7 @@ void SdrTextObj::impDecomposeBlockTextPrimitive(

    // prepare outliner
    const bool bIsCell(rSdrBlockTextPrimitive.getCellText());
    SolarMutexGuard aSolarGuard;
    SdrOutliner& rOutliner = ImpGetDrawOutliner();
    SdrTextHorzAdjust eHAdj = rSdrBlockTextPrimitive.getSdrTextHorzAdjust();
    SdrTextVertAdjust eVAdj = rSdrBlockTextPrimitive.getSdrTextVertAdjust();
@@ -1122,6 +1125,7 @@ void SdrTextObj::impDecomposeStretchTextPrimitive(
    aAnchorTextRange.expand(aTranslate + aScale);

    // prepare outliner
    SolarMutexGuard aSolarGuard;
    SdrOutliner& rOutliner = ImpGetDrawOutliner();
    const EEControlBits nOriginalControlWord(rOutliner.GetControlWord());
    const Size aNullSize;
@@ -1481,6 +1485,7 @@ void SdrTextObj::impDecomposeChainedTextPrimitive(

    // prepare outliner
    const SfxItemSet& rTextItemSet = rSdrChainedTextPrimitive.getSdrText()->GetItemSet();
    SolarMutexGuard aSolarGuard;
    SdrOutliner& rOutliner = ImpGetDrawOutliner();

    SdrTextVertAdjust eVAdj = GetTextVerticalAdjust(rTextItemSet);
diff --git a/sw/inc/ndole.hxx b/sw/inc/ndole.hxx
index d9223c4..b8e434c 100644
--- a/sw/inc/ndole.hxx
+++ b/sw/inc/ndole.hxx
@@ -20,15 +20,16 @@
#define INCLUDED_SW_INC_NDOLE_HXX

#include <ndnotxt.hxx>

#include <svtools/embedhlp.hxx>
#include <drawinglayer/primitive2d/baseprimitive2d.hxx>

class SwGrfFormatColl;
class SwDoc;
class SwOLENode;

class SwOLEListener_Impl;
class SwEmbedObjectLink;
class DeflateData;

class SW_DLLPUBLIC SwOLEObj
{
    friend class SwOLENode;
@@ -44,6 +45,7 @@ class SW_DLLPUBLIC SwOLEObj
    // eventually buffered data if it is a chart OLE
    drawinglayer::primitive2d::Primitive2DContainer     m_aPrimitive2DSequence;
    basegfx::B2DRange                                   m_aRange;
    class DeflateData*                                  m_aDeflateData;

    SwOLEObj( const SwOLEObj& rObj ) = delete;

@@ -69,7 +71,9 @@ public:

    // try to get OLE visualization in form of a Primitive2DSequence
    // and the corresponding B2DRange. This data may be locally buffered
    drawinglayer::primitive2d::Primitive2DContainer tryToGetChartContentAsPrimitive2DSequence(basegfx::B2DRange& rRange);
    drawinglayer::primitive2d::Primitive2DContainer tryToGetChartContentAsPrimitive2DSequence(
        basegfx::B2DRange& rRange,
        bool bSynchron);
    void resetBufferedData();
};

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index e58f646..08517a1 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -1001,7 +1001,8 @@ void SwNoTextFrame::PaintPicture( vcl::RenderContext* pOut, const SwRect &rGrfAr
            basegfx::B2DRange aSourceRange;
            const drawinglayer::primitive2d::Primitive2DContainer aSequence(
                pOLENd->GetOLEObj().tryToGetChartContentAsPrimitive2DSequence(
                    aSourceRange));
                    aSourceRange,
                    bPrn));

            if(!aSequence.empty() && !aSourceRange.isEmpty())
            {
diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx
index e543975..a6d9598 100644
--- a/sw/source/core/ole/ndole.cxx
+++ b/sw/source/core/ole/ndole.cxx
@@ -57,7 +57,8 @@
#include <vcl/graphicfilter.hxx>
#include <comcore.hrc>
#include <svx/charthelper.hxx>

#include <comphelper/threadpool.hxx>
#include <atomic>
#include <deque>

using namespace utl;
@@ -642,12 +643,89 @@ bool SwOLENode::IsChart() const
    return bIsChart;
}

//////////////////////////////////////////////////////////////////////////////

class DeflateData
{
private:
    friend class DeflateThread;

    const uno::Reference< frame::XModel >               maXModel;
    drawinglayer::primitive2d::Primitive2DContainer     maPrimitive2DSequence;
    basegfx::B2DRange                                   maRange;
    std::atomic< bool>                                  mbFinished;

public:
    DeflateData(const uno::Reference< frame::XModel >& rXModel)
    :   maXModel(rXModel),
        maPrimitive2DSequence(),
        maRange(),
        mbFinished(false)
    {
    }

    const drawinglayer::primitive2d::Primitive2DContainer& getSequence() const
    {
        return maPrimitive2DSequence;
    }

    const basegfx::B2DRange& getRange() const
    {
        return maRange;
    }

    bool isFinished() const
    {
        return mbFinished;
    }

    void waitFinished()
    {
        if(!mbFinished)
        {
            const TimeValue aTimeValue(0, 100000); // 1/10th second
            osl_waitThread(&aTimeValue);
        }
    }
};

//////////////////////////////////////////////////////////////////////////////

class DeflateThread : public comphelper::ThreadTask
{
    DeflateData&            mrDeflateData;

public:
    DeflateThread(DeflateData& rDeflateData)
    :   mrDeflateData(rDeflateData)
    {
    }

private:
    virtual void doWork() override
    {
        try
        {
            mrDeflateData.maPrimitive2DSequence = ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
                mrDeflateData.maXModel,
                mrDeflateData.maRange);
            mrDeflateData.mbFinished = true;
        }
        catch (const uno::Exception&)
        {
        }
    }
};

//////////////////////////////////////////////////////////////////////////////

SwOLEObj::SwOLEObj( const svt::EmbeddedObjectRef& xObj ) :
    pOLENd( nullptr ),
    pListener( nullptr ),
    xOLERef( xObj ),
    m_aPrimitive2DSequence(),
    m_aRange()
    m_aRange(),
    m_aDeflateData(nullptr)
{
    xOLERef.Lock();
    if ( xObj.is() )
@@ -663,7 +741,8 @@ SwOLEObj::SwOLEObj( const OUString &rString, sal_Int64 nAspect ) :
    pListener( nullptr ),
    aName( rString ),
    m_aPrimitive2DSequence(),
    m_aRange()
    m_aRange(),
    m_aDeflateData(nullptr)
{
    xOLERef.Lock();
    xOLERef.SetViewAspect( nAspect );
@@ -671,6 +750,12 @@ SwOLEObj::SwOLEObj( const OUString &rString, sal_Int64 nAspect ) :

SwOLEObj::~SwOLEObj()
{
    if(m_aDeflateData)
    {
        m_aDeflateData->waitFinished();
        delete m_aDeflateData;
    }

    if( pListener )
    {
        if ( xOLERef.is() )
@@ -908,17 +993,49 @@ OUString SwOLEObj::GetDescription()
    return SW_RESSTR(STR_OLE);
}

drawinglayer::primitive2d::Primitive2DContainer SwOLEObj::tryToGetChartContentAsPrimitive2DSequence(basegfx::B2DRange& rRange)
drawinglayer::primitive2d::Primitive2DContainer SwOLEObj::tryToGetChartContentAsPrimitive2DSequence(
    basegfx::B2DRange& rRange,
    bool bSynchron)
{
    if(m_aDeflateData)
    {
        if(bSynchron)
        {
            m_aDeflateData->waitFinished();
        }

        if(m_aDeflateData->isFinished())
        {
            m_aPrimitive2DSequence = m_aDeflateData->getSequence();
            m_aRange = m_aDeflateData->getRange();
            delete m_aDeflateData;
            m_aDeflateData = nullptr;
        }
    }

    if(m_aPrimitive2DSequence.empty() && m_aRange.isEmpty() && xOLERef.is() && xOLERef.IsChart())
    {
        const uno::Reference< frame::XModel > aXModel(xOLERef->getComponent(), uno::UNO_QUERY);

        if(aXModel.is())
        {
            m_aPrimitive2DSequence = ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
                aXModel,
                m_aRange);
            static bool bAnynchronousLoadingAllowed = true;

            if(bSynchron || !bAnynchronousLoadingAllowed)
            {
                m_aPrimitive2DSequence = ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
                    aXModel,
                    m_aRange);
            }
            else
            {
                if(!m_aDeflateData)
                {
                    m_aDeflateData = new DeflateData(aXModel);
                    DeflateThread* pNew = new DeflateThread(*m_aDeflateData);
                    comphelper::ThreadPool::getSharedOptimalPool().pushTask(pNew);
                }
            }
        }
    }

@@ -934,6 +1051,13 @@ void SwOLEObj::resetBufferedData()
{
    m_aPrimitive2DSequence = drawinglayer::primitive2d::Primitive2DContainer();
    m_aRange.reset();

    if(m_aDeflateData)
    {
        m_aDeflateData->waitFinished();
        delete m_aDeflateData;
        m_aDeflateData = nullptr;
    }
}

SwOLELRUCache::SwOLELRUCache()