@@ -115,9 +115,16 @@ QgsComposerMap::~QgsComposerMap()
115115{
116116 delete mOverviewStack ;
117117 delete mGridStack ;
118+
119+ if ( mPainterJob )
120+ {
121+ disconnect ( mPainterJob .get (), &QgsMapRendererCustomPainterJob::finished, this , &QgsComposerMap::painterJobFinished );
122+ mPainterJob ->cancel ();
123+ mPainter ->end ();
124+ }
118125}
119126
120- /* This function is called by paint() and cache() to render the map. It does not override any functions
127+ /* This function is called by paint() to render the map. It does not override any functions
121128from QGraphicsItem. */
122129void QgsComposerMap::draw ( QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi, double *forceWidthScale )
123130{
@@ -206,12 +213,28 @@ void QgsComposerMap::cache()
206213 return ;
207214 }
208215
209- if ( mDrawing )
216+ if ( mPainterJob )
210217 {
211- return ;
218+ disconnect ( mPainterJob .get (), &QgsMapRendererCustomPainterJob::finished, this , &QgsComposerMap::painterJobFinished );
219+ QgsMapRendererCustomPainterJob *oldJob = mPainterJob .release ();
220+ QPainter *oldPainter = mPainter .release ();
221+ QImage *oldImage = mCacheRenderingImage .release ();
222+ connect ( oldJob, &QgsMapRendererCustomPainterJob::finished, this , [oldPainter, oldJob, oldImage]
223+ {
224+ oldJob->deleteLater ();
225+ delete oldPainter;
226+ delete oldImage;
227+ } );
228+ oldJob->cancelWithoutBlocking ();
229+ }
230+ else
231+ {
232+ mCacheRenderingImage .reset ( nullptr );
212233 }
213234
214- mDrawing = true ;
235+ Q_ASSERT ( !mPainterJob );
236+ Q_ASSERT ( !mPainter );
237+ Q_ASSERT ( !mCacheRenderingImage );
215238
216239 double horizontalVScaleFactor = horizontalViewScaleFactor ();
217240 if ( horizontalVScaleFactor < 0 )
@@ -242,38 +265,51 @@ void QgsComposerMap::cache()
242265 }
243266 }
244267
245- mCacheImage = QImage ( w, h, QImage::Format_ARGB32 );
268+ if ( w <= 0 || h <= 0 )
269+ return ;
270+
271+ mCacheRenderingImage .reset ( new QImage ( w, h, QImage::Format_ARGB32 ) );
246272
247273 // set DPI of the image
248- mCacheImage . setDotsPerMeterX ( 1000 * w / widthMM );
249- mCacheImage . setDotsPerMeterY ( 1000 * h / heightMM );
274+ mCacheRenderingImage -> setDotsPerMeterX ( 1000 * w / widthMM );
275+ mCacheRenderingImage -> setDotsPerMeterY ( 1000 * h / heightMM );
250276
251277 if ( hasBackground () )
252278 {
253279 // Initially fill image with specified background color. This ensures that layers with blend modes will
254280 // preview correctly
255- mCacheImage . fill ( backgroundColor ().rgba () );
281+ mCacheRenderingImage -> fill ( backgroundColor ().rgba () );
256282 }
257283 else
258284 {
259285 // no background, but start with empty fill to avoid artifacts
260- mCacheImage . fill ( QColor ( 255 , 255 , 255 , 0 ).rgba () );
286+ mCacheRenderingImage -> fill ( QColor ( 255 , 255 , 255 , 0 ).rgba () );
261287 }
262288
263- QPainter p ( &mCacheImage );
289+ mPainter .reset ( new QPainter ( mCacheRenderingImage .get () ) );
290+ QgsMapSettings settings ( mapSettings ( ext, QSizeF ( w, h ), mCacheRenderingImage ->logicalDpiX () ) );
291+ mPainterJob .reset ( new QgsMapRendererCustomPainterJob ( settings, mPainter .get () ) );
292+ connect ( mPainterJob .get (), &QgsMapRendererCustomPainterJob::finished, this , &QgsComposerMap::painterJobFinished );
293+ mPainterJob ->start ();
294+ }
264295
265- draw ( &p, ext, QSizeF ( w, h ), mCacheImage .logicalDpiX () );
266- p.end ();
296+ void QgsComposerMap::painterJobFinished ()
297+ {
298+ mPainter ->end ();
299+ mPainterJob .reset ( nullptr );
300+ mPainter .reset ( nullptr );
267301 mCacheUpdated = true ;
268-
269- mDrawing = false ;
302+ mCacheFinalImage = std::move ( mCacheRenderingImage );
303+ mLastRenderedImageOffsetX = 0 ;
304+ mLastRenderedImageOffsetY = 0 ;
305+ updateItem ();
270306}
271307
272308void QgsComposerMap::paint ( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *pWidget )
273309{
274310 Q_UNUSED ( pWidget );
275311
276- if ( !mComposition || !painter )
312+ if ( !mComposition || !painter || !painter-> device () )
277313 {
278314 return ;
279315 }
@@ -283,6 +319,9 @@ void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *,
283319 }
284320
285321 QRectF thisPaintRect = QRectF ( 0 , 0 , QGraphicsRectItem::rect ().width (), QGraphicsRectItem::rect ().height () );
322+ if ( thisPaintRect.width () == 0 || thisPaintRect.height () == 0 )
323+ return ;
324+
286325 painter->save ();
287326 painter->setClipRect ( thisPaintRect );
288327
@@ -297,22 +336,40 @@ void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *,
297336 }
298337 else if ( mComposition ->plotStyle () == QgsComposition::Preview )
299338 {
300- if ( mCacheImage .isNull () )
301- cache ();
302-
303- // Background color is already included in cached image, so no need to draw
339+ if ( !mCacheFinalImage || mCacheFinalImage ->isNull () )
340+ {
341+ // No initial render available - so draw some preview text alerting user
342+ drawBackground ( painter );
343+ painter->setBrush ( QBrush ( QColor ( 125 , 125 , 125 , 125 ) ) );
344+ painter->drawRect ( thisPaintRect );
345+ painter->setBrush ( Qt::NoBrush );
346+ QFont messageFont;
347+ messageFont.setPointSize ( 12 );
348+ painter->setFont ( messageFont );
349+ painter->setPen ( QColor ( 255 , 255 , 255 , 255 ) );
350+ painter->drawText ( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr ( " Rendering map" ) );
351+ if ( !mPainterJob )
352+ {
353+ // this is the map's very first paint - trigger a cache update
354+ cache ();
355+ }
356+ }
357+ else
358+ {
359+ // Background color is already included in cached image, so no need to draw
304360
305- double imagePixelWidth = mCacheImage . width (); // how many pixels of the image are for the map extent?
306- double scale = rect ().width () / imagePixelWidth;
361+ double imagePixelWidth = mCacheFinalImage -> width (); // how many pixels of the image are for the map extent?
362+ double scale = rect ().width () / imagePixelWidth;
307363
308- painter->save ();
364+ painter->save ();
309365
310- painter->translate ( mXOffset , mYOffset );
311- painter->scale ( scale, scale );
312- painter->drawImage ( 0 , 0 , mCacheImage );
366+ painter->translate ( mLastRenderedImageOffsetX + mXOffset , mLastRenderedImageOffsetY + mYOffset );
367+ painter->scale ( scale, scale );
368+ painter->drawImage ( 0 , 0 , * mCacheFinalImage );
313369
314- // restore rotation
315- painter->restore ();
370+ // restore rotation
371+ painter->restore ();
372+ }
316373 }
317374 else if ( mComposition ->plotStyle () == QgsComposition::Print ||
318375 mComposition ->plotStyle () == QgsComposition::Postscript )
@@ -565,6 +622,8 @@ void QgsComposerMap::resize( double dx, double dy )
565622
566623void QgsComposerMap::moveContent ( double dx, double dy )
567624{
625+ mLastRenderedImageOffsetX -= dx;
626+ mLastRenderedImageOffsetY -= dy;
568627 if ( !mDrawing )
569628 {
570629 transformShift ( dx, dy );
@@ -673,7 +732,7 @@ void QgsComposerMap::setSceneRect( const QRectF &rectangle )
673732 mCacheUpdated = false ;
674733
675734 updateBoundingRect ();
676- update ();
735+ updateItem ();
677736 emit itemChanged ();
678737 emit extentChanged ();
679738}
0 commit comments