sw: tdf#50613 fix async chart load handling
Especially if synchronous loading is requested, an async worker is on the way
and we would need to 'wait' for the data.
Change-Id: I20f9938738c1b46bda6b9a7f5a761e82153aed3b
diff --git a/sw/inc/ndole.hxx b/sw/inc/ndole.hxx
index b8e434c..372b053 100644
--- a/sw/inc/ndole.hxx
+++ b/sw/inc/ndole.hxx
@@ -45,7 +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;
class DeflateData* m_pDeflateData;
SwOLEObj( const SwOLEObj& rObj ) = delete;
diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx
index 1ea83bf..816ceb8 100644
--- a/sw/source/core/ole/ndole.cxx
+++ b/sw/source/core/ole/ndole.cxx
@@ -649,18 +649,27 @@ class DeflateData
{
private:
friend class DeflateThread;
friend class SwOLEObj;
const uno::Reference< frame::XModel > maXModel;
uno::Reference< frame::XModel > maXModel;
drawinglayer::primitive2d::Primitive2DContainer maPrimitive2DSequence;
basegfx::B2DRange maRange;
// set from the WorkerThread when done
std::atomic< bool> mbFinished;
// evtl.set from the SwOLEObj destructor when a WorkerThread is still active
// since it is not possible to kill it - let it terminate and delete the
// data working on itself
std::atomic< bool> mbKilled;
public:
DeflateData(const uno::Reference< frame::XModel >& rXModel)
: maXModel(rXModel),
maPrimitive2DSequence(),
maRange(),
mbFinished(false)
mbFinished(false),
mbKilled(false)
{
}
@@ -681,11 +690,14 @@ public:
void waitFinished()
{
const TimeValue aTimeValue(0, 100000); // 1/10th second
while(!mbFinished)
while(!mbFinished && !mbKilled)
{
osl_waitThread(&aTimeValue);
// need to wait until the load in progress is finished.
// to do so, Application::Yield() is needed since the execution
// here means that the SolarMutex is locked, but the
// WorkerThreads need it to be able to continue and finish
// the running import
Application::Yield();
}
}
};
@@ -694,6 +706,7 @@ public:
class DeflateThread : public comphelper::ThreadTask
{
// the data to work on
DeflateData& mrDeflateData;
public:
@@ -707,14 +720,24 @@ private:
{
try
{
// load the chart data and get the primitives
mrDeflateData.maPrimitive2DSequence = ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
mrDeflateData.maXModel,
mrDeflateData.maRange);
// model no longer needed and done
mrDeflateData.maXModel.clear();
mrDeflateData.mbFinished = true;
}
catch (const uno::Exception&)
{
}
if(mrDeflateData.mbKilled)
{
// need to cleanup myself - data will not be used
delete &mrDeflateData;
}
}
};
@@ -726,7 +749,7 @@ SwOLEObj::SwOLEObj( const svt::EmbeddedObjectRef& xObj ) :
xOLERef( xObj ),
m_aPrimitive2DSequence(),
m_aRange(),
m_aDeflateData(nullptr)
m_pDeflateData(nullptr)
{
xOLERef.Lock();
if ( xObj.is() )
@@ -743,7 +766,7 @@ SwOLEObj::SwOLEObj( const OUString &rString, sal_Int64 nAspect ) :
aName( rString ),
m_aPrimitive2DSequence(),
m_aRange(),
m_aDeflateData(nullptr)
m_pDeflateData(nullptr)
{
xOLERef.Lock();
xOLERef.SetViewAspect( nAspect );
@@ -751,10 +774,12 @@ SwOLEObj::SwOLEObj( const OUString &rString, sal_Int64 nAspect ) :
SwOLEObj::~SwOLEObj()
{
if(m_aDeflateData)
if(m_pDeflateData)
{
m_aDeflateData->waitFinished();
delete m_aDeflateData;
// set flag so that the worker thread will delete m_pDeflateData
// when finished and forget about it
m_pDeflateData->mbKilled = true;
m_pDeflateData = nullptr;
}
if( pListener )
@@ -998,19 +1023,22 @@ drawinglayer::primitive2d::Primitive2DContainer SwOLEObj::tryToGetChartContentAs
basegfx::B2DRange& rRange,
bool bSynchron)
{
if(m_aDeflateData)
if(m_pDeflateData)
{
if(bSynchron)
{
m_aDeflateData->waitFinished();
// data in high quality is requested, wait until the data is available
// since a WorkerThread was already started to load it
m_pDeflateData->waitFinished();
}
if(m_aDeflateData->isFinished())
if(m_pDeflateData->isFinished())
{
m_aPrimitive2DSequence = m_aDeflateData->getSequence();
m_aRange = m_aDeflateData->getRange();
delete m_aDeflateData;
m_aDeflateData = nullptr;
// copy the result data and cleanup
m_aPrimitive2DSequence = m_pDeflateData->getSequence();
m_aRange = m_pDeflateData->getRange();
delete m_pDeflateData;
m_pDeflateData = nullptr;
}
}
@@ -1022,18 +1050,24 @@ drawinglayer::primitive2d::Primitive2DContainer SwOLEObj::tryToGetChartContentAs
{
static bool bAnynchronousLoadingAllowed = true;
if(bSynchron || !bAnynchronousLoadingAllowed)
if(bSynchron ||
!bAnynchronousLoadingAllowed ||
0 == comphelper::ThreadPool::getSharedOptimalPool().getWorkerCount())
{
// load chart synchron in this Thread
m_aPrimitive2DSequence = ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
aXModel,
m_aRange);
}
else
{
if(!m_aDeflateData)
// if not yet setup, initiate and start a WorkerThread to load the chart
// and it's primitives asynchron. If it already works, returning nothing
// is okay (preview will be reused)
if(!m_pDeflateData)
{
m_aDeflateData = new DeflateData(aXModel);
DeflateThread* pNew = new DeflateThread(*m_aDeflateData);
m_pDeflateData = new DeflateData(aXModel);
DeflateThread* pNew = new DeflateThread(*m_pDeflateData);
comphelper::ThreadPool::getSharedOptimalPool().pushTask(pNew);
}
}
@@ -1042,6 +1076,7 @@ drawinglayer::primitive2d::Primitive2DContainer SwOLEObj::tryToGetChartContentAs
if(!m_aPrimitive2DSequence.empty() && !m_aRange.isEmpty())
{
// when we have data, also copy the buffered Range data as output
rRange = m_aRange;
}
@@ -1053,11 +1088,12 @@ void SwOLEObj::resetBufferedData()
m_aPrimitive2DSequence = drawinglayer::primitive2d::Primitive2DContainer();
m_aRange.reset();
if(m_aDeflateData)
if(m_pDeflateData)
{
m_aDeflateData->waitFinished();
delete m_aDeflateData;
m_aDeflateData = nullptr;
// load is in progress, wait until finished and cleanup without using it
m_pDeflateData->waitFinished();
delete m_pDeflateData;
m_pDeflateData = nullptr;
}
}