Rework how composer map cache is invalidated

Avoids unnecessary redraws and defers cache update until
when item is actually visible
This commit is contained in:
Nyall Dawson 2017-05-08 16:16:22 +10:00
parent 91b046a743
commit abe8ead1a5
9 changed files with 65 additions and 99 deletions

View File

@ -640,6 +640,7 @@ and setAtlasScalingMode() instead.
- setMapCanvas() was removed. This is no longer required to draw map annotations, which are instead retrieved from the composition's
associated project's annotationManager()
- setDrawCanvasItems() and drawCanvasItems() were renamed to setDrawAnnotations() and drawAnnotations()
- setCacheUpdated(), updateCachedImage() and cache() were removed. Use invalidateCache() instead.
QgsComposerMapGrid {#qgis_api_break_3_0_QgsComposerMapGrid}

View File

@ -122,7 +122,6 @@ core/composer/qgscomposeritemcommand.sip
core/composer/qgscomposeritemgroup.sip
core/composer/qgscomposerlabel.sip
core/composer/qgscomposerlegend.sip
core/composer/qgscomposermap.sip
core/composer/qgscomposermapgrid.sip
core/composer/qgscomposermapitem.sip
core/composer/qgscomposermapoverview.sip

View File

@ -230,12 +230,14 @@ void QgsComposerItemWidget::on_mBackgroundColorButton_colorChanged( const QColor
//if the item is a composer map, we need to regenerate the map image
//because it usually is cached
QgsComposerMap *cm = dynamic_cast<QgsComposerMap *>( mItem );
if ( cm )
if ( QgsComposerMap *cm = qobject_cast<QgsComposerMap *>( mItem ) )
{
cm->cache();
cm->invalidateCache();
}
else
{
mItem->updateItem();
}
mItem->update();
mItem->endCommand();
}
@ -350,13 +352,14 @@ void QgsComposerItemWidget::on_mBackgroundGroupBox_toggled( bool state )
//if the item is a composer map, we need to regenerate the map image
//because it usually is cached
QgsComposerMap *cm = dynamic_cast<QgsComposerMap *>( mItem );
if ( cm )
if ( QgsComposerMap *cm = qobject_cast<QgsComposerMap *>( mItem ) )
{
cm->cache();
cm->invalidateCache();
}
else
{
mItem->updateItem();
}
mItem->update();
mItem->endCommand();
}

View File

@ -195,8 +195,7 @@ void QgsComposerMapWidget::followVisibilityPresetSelected( int currentIndex )
mFollowVisibilityPresetCheckBox->setChecked( true );
mComposerMap->setFollowVisibilityPresetName( presetName );
mComposerMap->cache();
mComposerMap->update();
mComposerMap->invalidateCache();
}
void QgsComposerMapWidget::keepLayersVisibilityPresetSelected()
@ -216,8 +215,7 @@ void QgsComposerMapWidget::keepLayersVisibilityPresetSelected()
mComposerMap->setLayerStyleOverrides( QgsProject::instance()->mapThemeCollection()->mapThemeStyleOverrides( presetName ) );
mComposerMap->cache();
mComposerMap->update();
mComposerMap->invalidateCache();
}
}
@ -301,8 +299,7 @@ void QgsComposerMapWidget::mapCrsChanged( const QgsCoordinateReferenceSystem &cr
if ( updateExtent )
mComposerMap->zoomToExtent( newExtent );
mComposerMap->endCommand();
mComposerMap->cache();
mComposerMap->update();
mComposerMap->invalidateCache();
}
void QgsComposerMapWidget::on_mAtlasCheckBox_toggled( bool checked )
@ -369,8 +366,7 @@ void QgsComposerMapWidget::updateMapForAtlas()
else
{
//redraw map
mComposerMap->cache();
mComposerMap->update();
mComposerMap->invalidateCache();
}
}
@ -466,8 +462,7 @@ void QgsComposerMapWidget::on_mPreviewModeComboBox_activated( int i )
mUpdatePreviewButton->setEnabled( false );
}
mComposerMap->cache();
mComposerMap->update();
mComposerMap->invalidateCache();
}
void QgsComposerMapWidget::on_mScaleLineEdit_editingFinished()
@ -503,8 +498,7 @@ void QgsComposerMapWidget::rotationChanged()
mComposerMap->beginCommand( tr( "Map rotation changed" ), QgsComposerMergeCommand::ComposerMapRotation );
mComposerMap->setMapRotation( mMapRotationSpinBox->value() );
mComposerMap->endCommand();
mComposerMap->cache();
mComposerMap->update();
mComposerMap->invalidateCache();
}
void QgsComposerMapWidget::on_mSetToMapCanvasExtentButton_clicked()
@ -869,9 +863,7 @@ void QgsComposerMapWidget::on_mUpdatePreviewButton_clicked()
mUpdatePreviewButton->setEnabled( false ); //prevent crashes because of many button clicks
mComposerMap->setCacheUpdated( false );
mComposerMap->cache();
mComposerMap->update();
mComposerMap->invalidateCache();
mUpdatePreviewButton->setEnabled( true );
}
@ -891,8 +883,7 @@ void QgsComposerMapWidget::on_mFollowVisibilityPresetCheckBox_stateChanged( int
mKeepLayerListCheckBox->setCheckState( Qt::Unchecked );
mKeepLayerStylesCheckBox->setCheckState( Qt::Unchecked );
mComposerMap->cache();
mComposerMap->update();
mComposerMap->invalidateCache();
}
else
{
@ -924,7 +915,7 @@ void QgsComposerMapWidget::on_mKeepLayerListCheckBox_stateChanged( int state )
else
{
mKeepLayerStylesCheckBox->setChecked( Qt::Unchecked );
mComposerMap->updateCachedImage();
mComposerMap->invalidateCache();
}
mKeepLayerStylesCheckBox->setEnabled( state == Qt::Checked );
@ -959,9 +950,7 @@ void QgsComposerMapWidget::on_mDrawCanvasItemsCheckBox_stateChanged( int state )
mComposerMap->beginCommand( tr( "Canvas items toggled" ) );
mComposerMap->setDrawAnnotations( state == Qt::Checked );
mUpdatePreviewButton->setEnabled( false ); //prevent crashes because of many button clicks
mComposerMap->setCacheUpdated( false );
mComposerMap->cache();
mComposerMap->update();
mComposerMap->invalidateCache();
mUpdatePreviewButton->setEnabled( true );
mComposerMap->endCommand();
}

View File

@ -267,7 +267,7 @@ void QgsAtlasComposition::updateAtlasMaps()
continue;
}
currentMap->cache();
currentMap->invalidateCache();
}
}
@ -426,7 +426,7 @@ bool QgsAtlasComposition::prepareForFeature( const int featureI, const bool upda
{
// map is not atlas driven, so manually force a redraw (to reflect possibly atlas
// dependent symbology)
( *mit )->cache();
( *mit )->invalidateCache();
}
}

View File

@ -206,7 +206,7 @@ QgsMapSettings QgsComposerMap::mapSettings( const QgsRectangle &extent, QSizeF s
return jobMapSettings;
}
void QgsComposerMap::cache()
void QgsComposerMap::recreateCachedImageInBackground()
{
if ( mPreviewMode == Rectangle )
{
@ -286,6 +286,7 @@ void QgsComposerMap::cache()
mCacheRenderingImage->fill( QColor( 255, 255, 255, 0 ).rgba() );
}
mCacheInvalidated = false;
mPainter.reset( new QPainter( mCacheRenderingImage.get() ) );
QgsMapSettings settings( mapSettings( ext, QSizeF( w, h ), mCacheRenderingImage->logicalDpiX() ) );
mPainterJob.reset( new QgsMapRendererCustomPainterJob( settings, mPainter.get() ) );
@ -298,7 +299,6 @@ void QgsComposerMap::painterJobFinished()
mPainter->end();
mPainterJob.reset( nullptr );
mPainter.reset( nullptr );
mCacheUpdated = true;
mCacheFinalImage = std::move( mCacheRenderingImage );
mLastRenderedImageOffsetX = 0;
mLastRenderedImageOffsetY = 0;
@ -351,11 +351,17 @@ void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *,
if ( !mPainterJob )
{
// this is the map's very first paint - trigger a cache update
cache();
recreateCachedImageInBackground();
}
}
else
{
if ( mCacheInvalidated )
{
// cache was invalidated - trigger a background update
recreateCachedImageInBackground();
}
//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?
@ -436,6 +442,12 @@ void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *,
painter->restore();
}
void QgsComposerMap::invalidateCache()
{
mCacheInvalidated = true;
updateItem();
}
int QgsComposerMap::numberExportLayers() const
{
return
@ -495,26 +507,14 @@ bool QgsComposerMap::shouldDrawPart( PartType part ) const
return true; // for Layer
}
void QgsComposerMap::updateCachedImage()
{
mCacheUpdated = false;
cache();
update();
}
void QgsComposerMap::renderModeUpdateCachedImage()
{
if ( mPreviewMode == Render )
{
updateCachedImage();
invalidateCache();
}
}
void QgsComposerMap::setCacheUpdated( bool u )
{
mCacheUpdated = u;
}
QList<QgsMapLayer *> QgsComposerMap::layersToRender( const QgsExpressionContext *context ) const
{
QgsExpressionContext scopedContext = createExpressionContext();
@ -635,8 +635,7 @@ void QgsComposerMap::moveContent( double dx, double dy )
//in case data defined extents are set, these override the calculated values
refreshMapExtents();
cache();
update();
invalidateCache();
emit itemChanged();
emit extentChanged();
}
@ -709,8 +708,7 @@ void QgsComposerMap::zoomContent( const double factor, const QPointF point, cons
//recalculate data defined scale and extents, since that may override zoom
refreshMapExtents();
cache();
update();
invalidateCache();
emit itemChanged();
emit extentChanged();
}
@ -729,10 +727,8 @@ void QgsComposerMap::setSceneRect( const QRectF &rectangle )
//recalculate data defined scale and extents
refreshMapExtents();
mCacheUpdated = false;
updateBoundingRect();
updateItem();
invalidateCache();
emit itemChanged();
emit extentChanged();
}
@ -796,8 +792,7 @@ void QgsComposerMap::zoomToExtent( const QgsRectangle &extent )
//recalculate data defined scale and extents, since that may override extent
refreshMapExtents();
mCacheUpdated = false;
updateItem();
invalidateCache();
emit itemChanged();
emit extentChanged();
}
@ -836,9 +831,8 @@ void QgsComposerMap::setNewAtlasFeatureExtent( const QgsRectangle &extent )
//recalculate data defined scale and extents, since that may override extents
refreshMapExtents();
mCacheUpdated = false;
emit preparedForAtlas();
updateItem();
invalidateCache();
emit itemChanged();
emit extentChanged();
}
@ -913,11 +907,9 @@ void QgsComposerMap::setNewScale( double scaleDenominator, bool forceUpdate )
mExtent.scale( scaleRatio );
}
mCacheUpdated = false;
invalidateCache();
if ( forceUpdate )
{
cache();
update();
emit itemChanged();
}
emit extentChanged();
@ -939,9 +931,9 @@ void QgsComposerMap::setMapRotation( double r )
{
mMapRotation = r;
mEvaluatedMapRotation = mMapRotation;
invalidateCache();
emit mapRotationChanged( r );
emit itemChanged();
update();
}
double QgsComposerMap::mapRotation( QgsComposerObject::PropertyValueType valueType ) const
@ -1078,21 +1070,6 @@ void QgsComposerMap::refreshMapExtents( const QgsExpressionContext *context )
mEvaluatedMapRotation = mapRotation;
emit mapRotationChanged( mapRotation );
}
}
void QgsComposerMap::updateItem()
{
if ( !updatesEnabled() )
{
return;
}
if ( mPreviewMode != QgsComposerMap::Rectangle && !mCacheUpdated )
{
cache();
}
QgsComposerItem::updateItem();
}
bool QgsComposerMap::containsWmsLayer() const
@ -1182,7 +1159,7 @@ void QgsComposerMap::connectUpdateSlot()
connect( project, &QgsProject::layersRemoved, this, &QgsComposerMap::renderModeUpdateCachedImage );
connect( project, &QgsProject::legendLayersAdded, this, &QgsComposerMap::renderModeUpdateCachedImage );
}
connect( mComposition, &QgsComposition::refreshItemsTriggered, this, &QgsComposerMap::updateCachedImage );
connect( mComposition, &QgsComposition::refreshItemsTriggered, this, &QgsComposerMap::invalidateCache );
}
bool QgsComposerMap::writeXml( QDomElement &elem, QDomDocument &doc ) const
@ -1448,7 +1425,7 @@ bool QgsComposerMap::readXml( const QDomElement &itemElem, const QDomDocument &d
mDrawing = false;
mNumCachedLayers = 0;
mCacheUpdated = false;
mCacheInvalidated = true;
//overviews
mOverviewStack->readXml( itemElem, doc );
@ -1870,7 +1847,7 @@ void QgsComposerMap::refreshDataDefinedProperty( const QgsComposerObject::DataDe
}
//force redraw
mCacheUpdated = false;
mCacheInvalidated = true;
QgsComposerItem::refreshDataDefinedProperty( property, evalContext );
}

View File

@ -99,9 +99,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
//! \brief Reimplementation of QCanvasItem::paint - draw on canvas
void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) override;
//! \brief Create cache image
void cache();
/** Return map settings that would be used for drawing of the map
* \since QGIS 2.6 */
QgsMapSettings mapSettings( const QgsRectangle &extent, QSizeF size, int dpi ) const;
@ -279,9 +276,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
* \since QGIS 2.16 */
void setFollowVisibilityPresetName( const QString &name ) { mFollowVisibilityPresetName = name; }
// Set cache outdated
void setCacheUpdated( bool u = false );
QgsRectangle extent() const {return mExtent;}
//! Sets offset values to shift image (useful for live updates when moving item content)
@ -355,8 +349,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
*/
double mapRotation( QgsComposerObject::PropertyValueType valueType = QgsComposerObject::EvaluatedValue ) const;
void updateItem() override;
/**
* Sets whether annotations are drawn within the composer map.
* \see drawAnnotations()
@ -476,8 +468,11 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
public slots:
//! Forces an update of the cached map image
void updateCachedImage();
/**
* Forces a deferred update of the cached map image on next paint.
* \since QGIS 3.0
*/
void invalidateCache();
/** Updates the cached map image if the map is set to Render mode
* \see updateCachedImage
@ -526,8 +521,8 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
std::unique_ptr< QImage > mCacheFinalImage;
std::unique_ptr< QImage > mCacheRenderingImage;
// Is cache up to date
bool mCacheUpdated = false;
//! True if cached map image must be recreated
bool mCacheInvalidated = true;
//! \brief Preview style
PreviewMode mPreviewMode = QgsComposerMap::Cache;
@ -572,6 +567,9 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
* is true. May be overridden by data-defined expression. */
QString mFollowVisibilityPresetName;
//! \brief Create cache image
void recreateCachedImage();
//! Establishes signal/slot connection for update in case of layer change
void connectUpdateSlot();

View File

@ -311,11 +311,11 @@ void QgsComposerMapOverview::overviewExtentChanged()
mComposerMap->refreshDataDefinedProperty( QgsComposerObject::MapScale );
//must invalidate cache so that map gets redrawn
mComposerMap->cache();
mComposerMap->invalidateCache();
}
//repaint map so that overview gets updated
mComposerMap->update();
mComposerMap->updateItem();
}

View File

@ -2059,10 +2059,9 @@ void QgsComposerView::wheelZoom( QWheelEvent *event )
QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
for ( ; itemIt != itemList.end(); ++itemIt )
{
QgsComposerMap *mypItem = dynamic_cast<QgsComposerMap *>( *itemIt );
if ( ( mypItem ) && ( mypItem->previewMode() == QgsComposerMap::Render ) )
if ( QgsComposerMap *mypItem = qobject_cast<QgsComposerMap *>( *itemIt ) )
{
mypItem->updateCachedImage();
mypItem->invalidateCache();
}
}
}