Merge pull request #4510 from qgis/revert-4494-composer_async

Revert "Asyncronously render composer map previews "
This commit is contained in:
Nyall Dawson 2017-05-07 10:25:59 +10:00 committed by GitHub
commit ddbb1702ba
3 changed files with 31 additions and 109 deletions

View File

@ -115,16 +115,9 @@ QgsComposerMap::~QgsComposerMap()
{ {
delete mOverviewStack; delete mOverviewStack;
delete mGridStack; delete mGridStack;
if ( mPainterJob )
{
disconnect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished );
mPainterJob->cancel();
mPainter->end();
}
} }
/* This function is called by paint() to render the map. It does not override any functions /* This function is called by paint() and cache() to render the map. It does not override any functions
from QGraphicsItem. */ from QGraphicsItem. */
void QgsComposerMap::draw( QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi, double *forceWidthScale ) void QgsComposerMap::draw( QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi, double *forceWidthScale )
{ {
@ -213,28 +206,12 @@ void QgsComposerMap::cache()
return; return;
} }
if ( mPainterJob ) if ( mDrawing )
{ {
disconnect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished ); return;
QgsMapRendererCustomPainterJob *oldJob = mPainterJob.release();
QPainter *oldPainter = mPainter.release();
QImage *oldImage = mCacheRenderingImage.release();
connect( oldJob, &QgsMapRendererCustomPainterJob::finished, this, [oldPainter, oldJob, oldImage]
{
oldJob->deleteLater();
delete oldPainter;
delete oldImage;
} );
oldJob->cancelWithoutBlocking();
}
else
{
mCacheRenderingImage.reset( nullptr );
} }
Q_ASSERT( !mPainterJob ); mDrawing = true;
Q_ASSERT( !mPainter );
Q_ASSERT( !mCacheRenderingImage );
double horizontalVScaleFactor = horizontalViewScaleFactor(); double horizontalVScaleFactor = horizontalViewScaleFactor();
if ( horizontalVScaleFactor < 0 ) if ( horizontalVScaleFactor < 0 )
@ -265,51 +242,38 @@ void QgsComposerMap::cache()
} }
} }
if ( w <= 0 || h <= 0 ) mCacheImage = QImage( w, h, QImage::Format_ARGB32 );
return;
mCacheRenderingImage.reset( new QImage( w, h, QImage::Format_ARGB32 ) );
// set DPI of the image // set DPI of the image
mCacheRenderingImage->setDotsPerMeterX( 1000 * w / widthMM ); mCacheImage.setDotsPerMeterX( 1000 * w / widthMM );
mCacheRenderingImage->setDotsPerMeterY( 1000 * h / heightMM ); mCacheImage.setDotsPerMeterY( 1000 * h / heightMM );
if ( hasBackground() ) if ( hasBackground() )
{ {
//Initially fill image with specified background color. This ensures that layers with blend modes will //Initially fill image with specified background color. This ensures that layers with blend modes will
//preview correctly //preview correctly
mCacheRenderingImage->fill( backgroundColor().rgba() ); mCacheImage.fill( backgroundColor().rgba() );
} }
else else
{ {
//no background, but start with empty fill to avoid artifacts //no background, but start with empty fill to avoid artifacts
mCacheRenderingImage->fill( QColor( 255, 255, 255, 0 ).rgba() ); mCacheImage.fill( QColor( 255, 255, 255, 0 ).rgba() );
} }
mPainter.reset( new QPainter( mCacheRenderingImage.get() ) ); QPainter p( &mCacheImage );
QgsMapSettings settings( mapSettings( ext, QSizeF( w, h ), mCacheRenderingImage->logicalDpiX() ) );
mPainterJob.reset( new QgsMapRendererCustomPainterJob( settings, mPainter.get() ) );
connect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished );
mPainterJob->start();
}
void QgsComposerMap::painterJobFinished() draw( &p, ext, QSizeF( w, h ), mCacheImage.logicalDpiX() );
{ p.end();
mPainter->end();
mPainterJob.reset( nullptr );
mPainter.reset( nullptr );
mCacheUpdated = true; mCacheUpdated = true;
mCacheFinalImage = std::move( mCacheRenderingImage );
mLastRenderedImageOffsetX = 0; mDrawing = false;
mLastRenderedImageOffsetY = 0;
updateItem();
} }
void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *pWidget ) void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *pWidget )
{ {
Q_UNUSED( pWidget ); Q_UNUSED( pWidget );
if ( !mComposition || !painter || !painter->device() ) if ( !mComposition || !painter )
{ {
return; return;
} }
@ -319,9 +283,6 @@ void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *,
} }
QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() ); QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
if ( thisPaintRect.width() == 0 || thisPaintRect.height() == 0 )
return;
painter->save(); painter->save();
painter->setClipRect( thisPaintRect ); painter->setClipRect( thisPaintRect );
@ -336,40 +297,22 @@ void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *,
} }
else if ( mComposition->plotStyle() == QgsComposition::Preview ) else if ( mComposition->plotStyle() == QgsComposition::Preview )
{ {
if ( !mCacheFinalImage || mCacheFinalImage->isNull() ) if ( mCacheImage.isNull() )
{ cache();
// No initial render available - so draw some preview text alerting user
drawBackground( painter );
painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
painter->drawRect( thisPaintRect );
painter->setBrush( Qt::NoBrush );
QFont messageFont;
messageFont.setPointSize( 12 );
painter->setFont( messageFont );
painter->setPen( QColor( 255, 255, 255, 255 ) );
painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering map" ) );
if ( !mPainterJob )
{
// this is the map's very first paint - trigger a cache update
cache();
}
}
else
{
//Background color is already included in cached image, so no need to draw
double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent? //Background color is already included in cached image, so no need to draw
double scale = rect().width() / imagePixelWidth;
painter->save(); double imagePixelWidth = mCacheImage.width(); //how many pixels of the image are for the map extent?
double scale = rect().width() / imagePixelWidth;
painter->translate( mLastRenderedImageOffsetX + mXOffset, mLastRenderedImageOffsetY + mYOffset ); painter->save();
painter->scale( scale, scale );
painter->drawImage( 0, 0, *mCacheFinalImage );
//restore rotation painter->translate( mXOffset, mYOffset );
painter->restore(); painter->scale( scale, scale );
} painter->drawImage( 0, 0, mCacheImage );
//restore rotation
painter->restore();
} }
else if ( mComposition->plotStyle() == QgsComposition::Print || else if ( mComposition->plotStyle() == QgsComposition::Print ||
mComposition->plotStyle() == QgsComposition::Postscript ) mComposition->plotStyle() == QgsComposition::Postscript )
@ -622,8 +565,6 @@ void QgsComposerMap::resize( double dx, double dy )
void QgsComposerMap::moveContent( double dx, double dy ) void QgsComposerMap::moveContent( double dx, double dy )
{ {
mLastRenderedImageOffsetX -= dx;
mLastRenderedImageOffsetY -= dy;
if ( !mDrawing ) if ( !mDrawing )
{ {
transformShift( dx, dy ); transformShift( dx, dy );
@ -732,7 +673,7 @@ void QgsComposerMap::setSceneRect( const QRectF &rectangle )
mCacheUpdated = false; mCacheUpdated = false;
updateBoundingRect(); updateBoundingRect();
updateItem(); update();
emit itemChanged(); emit itemChanged();
emit extentChanged(); emit extentChanged();
} }

View File

@ -43,7 +43,6 @@ class QgsFillSymbol;
class QgsLineSymbol; class QgsLineSymbol;
class QgsVectorLayer; class QgsVectorLayer;
class QgsAnnotation; class QgsAnnotation;
class QgsMapRendererCustomPainterJob;
/** \ingroup core /** \ingroup core
* \class QgsComposerMap * \class QgsComposerMap
@ -492,8 +491,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
private slots: private slots:
void layersAboutToBeRemoved( QList<QgsMapLayer *> layers ); void layersAboutToBeRemoved( QList<QgsMapLayer *> layers );
void painterJobFinished();
private: private:
//! Unique identifier //! Unique identifier
@ -516,15 +513,8 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
// to manually tweak each atlas preview page without affecting the actual original map extent. // to manually tweak each atlas preview page without affecting the actual original map extent.
QgsRectangle mAtlasFeatureExtent; QgsRectangle mAtlasFeatureExtent;
// We have two images used for rendering/storing cached map images. // Cache used in composer preview
// the first (mCacheFinalImage) is used ONLY for storing the most recent completed map render. It's always QImage mCacheImage;
// used when drawing map item previews. The second (mCacheRenderingImage) is used temporarily while
// rendering a new preview image in the background. If (and only if) the background render completes, then
// mCacheRenderingImage is pushed into mCacheFinalImage, and used from then on when drawing the item preview.
// This ensures that something is always shown in the map item, even while refreshing the preview image in the
// background
std::unique_ptr< QImage > mCacheFinalImage;
std::unique_ptr< QImage > mCacheRenderingImage;
// Is cache up to date // Is cache up to date
bool mCacheUpdated = false; bool mCacheUpdated = false;
@ -543,9 +533,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
//! Offset in y direction for showing map cache image //! Offset in y direction for showing map cache image
double mYOffset = 0.0; double mYOffset = 0.0;
double mLastRenderedImageOffsetX = 0.0;
double mLastRenderedImageOffsetY = 0.0;
//! Map rotation //! Map rotation
double mMapRotation = 0; double mMapRotation = 0;
@ -600,10 +587,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
//! Margin size for atlas driven extents (percentage of feature size) - when in auto scaling mode //! Margin size for atlas driven extents (percentage of feature size) - when in auto scaling mode
double mAtlasMargin = 0.10; double mAtlasMargin = 0.10;
std::unique_ptr< QPainter > mPainter;
std::unique_ptr< QgsMapRendererCustomPainterJob > mPainterJob;
bool mPainterCancelWait = false;
void init(); void init();
//! Resets the item tooltip to reflect current map id //! Resets the item tooltip to reflect current map id

View File

@ -23,7 +23,7 @@ import sys
import os import os
import subprocess import subprocess
from qgis.PyQt.QtCore import QRect, QRectF, QSize, QSizeF, qDebug, QThreadPool from qgis.PyQt.QtCore import QRect, QRectF, QSize, QSizeF, qDebug
from qgis.PyQt.QtGui import QImage, QColor, QPainter from qgis.PyQt.QtGui import QImage, QColor, QPainter
from qgis.PyQt.QtPrintSupport import QPrinter from qgis.PyQt.QtPrintSupport import QPrinter
from qgis.PyQt.QtSvg import QSvgRenderer, QSvgGenerator from qgis.PyQt.QtSvg import QSvgRenderer, QSvgGenerator
@ -88,8 +88,6 @@ class TestComposerBase(TestQgsPalLabeling):
TestQgsPalLabeling.tearDownClass() TestQgsPalLabeling.tearDownClass()
cls.removeMapLayer(cls.layer) cls.removeMapLayer(cls.layer)
cls.layer = None cls.layer = None
# avoid crash on finish, probably related to https://bugreports.qt.io/browse/QTBUG-35760
QThreadPool.globalInstance().waitForDone()
def setUp(self): def setUp(self):
"""Run before each test.""" """Run before each test."""