1111#include " qgsmaplayer.h"
1212#include " qgsmaplayerregistry.h"
1313#include " qgsmaplayerrenderer.h"
14+ #include " qgsmaprenderercache.h"
1415#include " qgspallabeling.h"
1516
1617
1718QgsMapRendererJob::QgsMapRendererJob ( const QgsMapSettings& settings )
1819 : mSettings(settings)
20+ , mCache( 0 )
1921{
2022}
2123
@@ -24,6 +26,11 @@ QgsMapRendererJob::Errors QgsMapRendererJob::errors() const
2426 return mErrors ;
2527}
2628
29+ void QgsMapRendererJob::setCache ( QgsMapRendererCache* cache )
30+ {
31+ mCache = cache;
32+ }
33+
2734
2835QgsMapRendererQImageJob::QgsMapRendererQImageJob ( const QgsMapSettings& settings )
2936 : QgsMapRendererJob( settings )
@@ -74,6 +81,7 @@ void QgsMapRendererSequentialJob::start()
7481 mPainter = new QPainter (&mImage );
7582
7683 mInternalJob = new QgsMapRendererCustomPainterJob (mSettings , mPainter );
84+ mInternalJob ->setCache ( mCache );
7785
7886 connect (mInternalJob , SIGNAL (finished ()), SLOT (internalFinished ()));
7987
@@ -115,7 +123,11 @@ QgsLabelingResults* QgsMapRendererSequentialJob::takeLabelingResults()
115123
116124QImage QgsMapRendererSequentialJob::renderedImage ()
117125{
118- return mImage ;
126+ if ( isActive () && mCache )
127+ // this will allow immediate display of cached layers and at the same time updates of the layer being rendered
128+ return composeImage ( mSettings , mInternalJob ->jobs () );
129+ else
130+ return mImage ;
119131}
120132
121133
@@ -309,7 +321,8 @@ void QgsMapRendererCustomPainterJob::doRender()
309321 mPainter ->setCompositionMode ( job.blendMode );
310322 }
311323
312- job.renderer ->render ();
324+ if ( !job.cached )
325+ job.renderer ->render ();
313326
314327 if ( job.img )
315328 {
@@ -496,6 +509,12 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabelin
496509 QListIterator<QString> li ( mSettings .layers () );
497510 li.toBack ();
498511
512+ if ( mCache )
513+ {
514+ bool cacheValid = mCache ->init ( mSettings .visibleExtent (), mSettings .scale () );
515+ qDebug (" CACHE VALID: %d" , cacheValid);
516+ }
517+
499518 while ( li.hasPrevious () )
500519 {
501520 QString layerId = li.previous ();
@@ -542,38 +561,56 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabelin
542561 }
543562 }
544563
545- // Flattened image for drawing when a blending mode is set
546- QImage * mypFlattenedImage = 0 ;
547-
548- // If we are drawing with an alternative blending mode then we need to render to a separate image
549- // before compositing this on the map. This effectively flattens the layer and prevents
550- // blending occuring between objects on the layer
551- if ( !painter || needTemporaryImage ( ml ) )
564+ // Force render of layers that are being edited
565+ // or if there's a labeling engine that needs the layer to register features
566+ if ( mCache && ml->type () == QgsMapLayer::VectorLayer )
552567 {
553- mypFlattenedImage = new QImage ( mSettings .outputSize ().width (),
554- mSettings .outputSize ().height (), QImage::Format_ARGB32 );
555- if ( mypFlattenedImage->isNull () )
556- {
557- mErrors .append ( Error ( layerId, " Insufficient memory for image " + QString::number ( mSettings .outputSize ().width () ) + " x" + QString::number ( mSettings .outputSize ().height () ) ) );
558- delete mypFlattenedImage;
559- continue ;
560- }
561- mypFlattenedImage->fill ( 0 );
568+ QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
569+ if ( vl->isEditable () || ( labelingEngine && labelingEngine->willUseLayer ( vl ) ) )
570+ mCache ->setCacheImage ( ml->id (), QImage () );
562571 }
563572
564573 layerJobs.append ( LayerRenderJob () );
565574 LayerRenderJob& job = layerJobs.last ();
575+ job.cached = false ;
566576 job.img = 0 ;
567577 job.blendMode = ml->blendMode ();
578+ job.layerId = ml->id ();
568579
569580 job.context = QgsRenderContext::fromMapSettings ( mSettings );
570581 job.context .setPainter ( painter );
571582 job.context .setLabelingEngine ( labelingEngine );
572583 job.context .setCoordinateTransform ( ct );
573584 job.context .setExtent ( r1 );
574585
575- if ( mypFlattenedImage )
586+ // if we can use the cache, let's do it and avoid rendering!
587+ if ( mCache && !mCache ->cacheImage ( ml->id () ).isNull () )
576588 {
589+ job.cached = true ;
590+ job.img = new QImage ( mCache ->cacheImage ( ml->id () ) );
591+ job.renderer = 0 ;
592+ job.context .setPainter ( 0 );
593+ continue ;
594+ }
595+
596+ // If we are drawing with an alternative blending mode then we need to render to a separate image
597+ // before compositing this on the map. This effectively flattens the layer and prevents
598+ // blending occuring between objects on the layer
599+ if ( mCache || !painter || needTemporaryImage ( ml ) )
600+ {
601+ // Flattened image for drawing when a blending mode is set
602+ QImage * mypFlattenedImage = 0 ;
603+ mypFlattenedImage = new QImage ( mSettings .outputSize ().width (),
604+ mSettings .outputSize ().height (), QImage::Format_ARGB32_Premultiplied );
605+ if ( mypFlattenedImage->isNull () )
606+ {
607+ mErrors .append ( Error ( layerId, " Insufficient memory for image " + QString::number ( mSettings .outputSize ().width () ) + " x" + QString::number ( mSettings .outputSize ().height () ) ) );
608+ delete mypFlattenedImage;
609+ layerJobs.removeLast ();
610+ continue ;
611+ }
612+ mypFlattenedImage->fill ( 0 );
613+
577614 job.img = mypFlattenedImage;
578615 QPainter* mypPainter = new QPainter ( job.img );
579616 mypPainter->setRenderHint ( QPainter::Antialiasing, mSettings .testFlag ( QgsMapSettings::Antialiasing ) );
@@ -603,18 +640,28 @@ void QgsMapRendererJob::cleanupJobs( LayerRenderJobs& jobs )
603640 {
604641 LayerRenderJob& job = *it;
605642 if ( job.img )
606- {
643+ {
607644 delete job.context .painter ();
608645 job.context .setPainter ( 0 );
646+
647+ if ( mCache && !job.cached && !job.context .renderingStopped () )
648+ {
649+ qDebug (" caching image for %s" , job.layerId .toAscii ().data ());
650+ mCache ->setCacheImage ( job.layerId , *job.img );
651+ }
652+
609653 delete job.img ;
610654 job.img = 0 ;
611655 }
612656
613- foreach ( QString message, job.renderer ->errors () )
614- mErrors .append ( Error ( job.renderer ->layerID (), message ) );
657+ if ( job.renderer )
658+ {
659+ foreach ( QString message, job.renderer ->errors () )
660+ mErrors .append ( Error ( job.renderer ->layerID (), message ) );
615661
616- delete job.renderer ;
617- job.renderer = 0 ;
662+ delete job.renderer ;
663+ job.renderer = 0 ;
664+ }
618665 }
619666
620667 jobs.clear ();
@@ -752,7 +799,7 @@ QgsLabelingResults* QgsMapRendererParallelJob::takeLabelingResults()
752799QImage QgsMapRendererParallelJob::renderedImage ()
753800{
754801 if ( mStatus == RenderingLayers )
755- return composeImage ();
802+ return composeImage ( mSettings , mLayerJobs );
756803 else
757804 return mFinalImage ; // when rendering labels or idle
758805}
@@ -762,7 +809,7 @@ void QgsMapRendererParallelJob::renderLayersFinished()
762809 Q_ASSERT ( mStatus == RenderingLayers );
763810
764811 // compose final image
765- mFinalImage = composeImage ();
812+ mFinalImage = composeImage ( mSettings , mLayerJobs );
766813
767814 cleanupJobs ( mLayerJobs );
768815
@@ -798,6 +845,9 @@ void QgsMapRendererParallelJob::renderLayerStatic(LayerRenderJob& job)
798845 if ( job.context .renderingStopped () )
799846 return ;
800847
848+ if ( job.cached )
849+ return ;
850+
801851 QTime t;
802852 t.start ();
803853 QgsDebugMsg ( QString (" job %1 start" ).arg ( (ulong) &job, 0 , 16 ) );
@@ -817,14 +867,14 @@ void QgsMapRendererParallelJob::renderLabelsStatic(QgsMapRendererParallelJob* se
817867}
818868
819869
820- QImage QgsMapRendererParallelJob ::composeImage ()
870+ QImage QgsMapRendererJob ::composeImage ( const QgsMapSettings& settings, const LayerRenderJobs& jobs )
821871{
822- QImage image ( mSettings .outputSize (), QImage::Format_ARGB32_Premultiplied );
823- image.fill ( mSettings .backgroundColor ().rgb () );
872+ QImage image ( settings .outputSize (), QImage::Format_ARGB32_Premultiplied );
873+ image.fill ( settings .backgroundColor ().rgb () );
824874
825875 QPainter painter (&image);
826876
827- for (LayerRenderJobs::const_iterator it = mLayerJobs . begin (); it != mLayerJobs . end (); ++it)
877+ for (LayerRenderJobs::const_iterator it = jobs. constBegin (); it != jobs. constEnd (); ++it)
828878 {
829879 const LayerRenderJob& job = *it;
830880
0 commit comments