Skip to content

Commit d0d9bab

Browse files
committedFeb 7, 2017
Don't cache labeling if blend modes are used
The flattening of the label results to an image blocks blend modes applying correctly to underlying layers
1 parent 2b3805e commit d0d9bab

8 files changed

+96
-34
lines changed
 

‎src/core/qgsmaprenderercustompainterjob.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,9 @@ void QgsMapRendererCustomPainterJob::start()
8383
mLabelingEngineV2->setMapSettings( mSettings );
8484
}
8585

86+
bool canUseLabelCache = prepareLabelCache();
8687
mLayerJobs = prepareJobs( mPainter, mLabelingEngineV2 );
87-
mLabelJob = prepareLabelingJob( mPainter, mLabelingEngineV2 );
88+
mLabelJob = prepareLabelingJob( mPainter, mLabelingEngineV2, canUseLabelCache );
8889

8990
QgsDebugMsg( "Rendering prepared in (seconds): " + QString( "%1" ).arg( prepareTime.elapsed() / 1000.0 ) );
9091

‎src/core/qgsmaprendererjob.cpp

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "qgscsexception.h"
3636
#include "qgslabelingengine.h"
3737
#include "qgsmaplayerlistutils.h"
38+
#include "qgsvectorlayerlabeling.h"
3839

3940
///@cond PRIVATE
4041

@@ -70,6 +71,39 @@ const QgsMapSettings& QgsMapRendererJob::mapSettings() const
7071
return mSettings;
7172
}
7273

74+
bool QgsMapRendererJob::prepareLabelCache() const
75+
{
76+
bool canCache = mCache;
77+
78+
// calculate which layers will be labeled
79+
QSet< QgsMapLayer* > labeledLayers;
80+
Q_FOREACH ( const QgsMapLayer* ml, mSettings.layers() )
81+
{
82+
QgsVectorLayer* vl = const_cast< QgsVectorLayer* >( qobject_cast<const QgsVectorLayer *>( ml ) );
83+
if ( vl && QgsPalLabeling::staticWillUseLayer( vl ) )
84+
labeledLayers << vl;
85+
if ( vl->labeling()->requiresAdvancedEffects( vl ) )
86+
{
87+
canCache = false;
88+
break;
89+
}
90+
}
91+
92+
if ( mCache && mCache->hasCacheImage( LABEL_CACHE_ID ) )
93+
{
94+
// we may need to clear label cache and re-register labeled features - check for that here
95+
96+
// can we reuse the cached label solution?
97+
bool canUseCache = canCache && mCache->dependentLayers( LABEL_CACHE_ID ).toSet() == labeledLayers;
98+
if ( !canUseCache )
99+
{
100+
// no - participating layers have changed
101+
mCache->clearCacheImage( LABEL_CACHE_ID );
102+
}
103+
}
104+
return canCache;
105+
}
106+
73107

74108
bool QgsMapRendererJob::reprojectToLayerExtent( const QgsMapLayer *ml, const QgsCoordinateTransform& ct, QgsRectangle &extent, QgsRectangle &r2 )
75109
{
@@ -190,30 +224,7 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsLabelingEn
190224
QgsDebugMsg( QString( "CACHE VALID: %1" ).arg( cacheValid ) );
191225
}
192226

193-
bool hasCachedLabels = false;
194-
if ( cacheValid && mCache->hasCacheImage( LABEL_CACHE_ID ) )
195-
{
196-
// we may need to clear label cache and re-register labeled features - check for that here
197-
198-
// calculate which layers will be labeled
199-
QSet< QgsMapLayer* > labeledLayers;
200-
Q_FOREACH ( const QgsMapLayer* ml, mSettings.layers() )
201-
{
202-
QgsVectorLayer* vl = const_cast< QgsVectorLayer* >( qobject_cast<const QgsVectorLayer *>( ml ) );
203-
if ( vl && QgsPalLabeling::staticWillUseLayer( vl ) )
204-
labeledLayers << vl;
205-
}
206-
207-
// can we reuse the cached label solution?
208-
bool canUseCache = mCache->dependentLayers( LABEL_CACHE_ID ).toSet() == labeledLayers;
209-
if ( !canUseCache )
210-
{
211-
// no - participating layers have changed
212-
mCache->clearCacheImage( LABEL_CACHE_ID );
213-
}
214-
215-
hasCachedLabels = canUseCache;
216-
}
227+
bool requiresLabelRedraw = !( mCache && mCache->hasCacheImage( LABEL_CACHE_ID ) );
217228

218229
mGeometryCaches.clear();
219230

@@ -258,9 +269,9 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsLabelingEn
258269
if ( mCache && ml->type() == QgsMapLayer::VectorLayer )
259270
{
260271
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
261-
bool requiresLabelRedraw = false;
262-
requiresLabelRedraw = ( labelingEngine2 && QgsPalLabeling::staticWillUseLayer( vl ) ) && !hasCachedLabels;
263-
if ( vl->isEditable() || requiresLabelRedraw )
272+
bool requiresLabeling = false;
273+
requiresLabeling = ( labelingEngine2 && QgsPalLabeling::staticWillUseLayer( vl ) ) && requiresLabelRedraw;
274+
if ( vl->isEditable() || requiresLabeling )
264275
{
265276
mCache->clearCacheImage( ml->id() );
266277
}
@@ -345,7 +356,7 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsLabelingEn
345356
return layerJobs;
346357
}
347358

348-
LabelRenderJob QgsMapRendererJob::prepareLabelingJob( QPainter* painter, QgsLabelingEngine* labelingEngine2 )
359+
LabelRenderJob QgsMapRendererJob::prepareLabelingJob( QPainter* painter, QgsLabelingEngine* labelingEngine2, bool canUseLabelCache )
349360
{
350361
LabelRenderJob job;
351362
job.context = QgsRenderContext::fromMapSettings( mSettings );
@@ -354,8 +365,8 @@ LabelRenderJob QgsMapRendererJob::prepareLabelingJob( QPainter* painter, QgsLabe
354365
job.context.setExtent( mSettings.visibleExtent() );
355366

356367
// if we can use the cache, let's do it and avoid rendering!
357-
bool canUseCache = mCache && mCache->hasCacheImage( LABEL_CACHE_ID );
358-
if ( canUseCache )
368+
bool hasCache = canUseLabelCache && mCache && mCache->hasCacheImage( LABEL_CACHE_ID );
369+
if ( hasCache )
359370
{
360371
job.cached = true;
361372
job.complete = true;
@@ -364,7 +375,7 @@ LabelRenderJob QgsMapRendererJob::prepareLabelingJob( QPainter* painter, QgsLabe
364375
}
365376
else
366377
{
367-
if ( mCache || !painter )
378+
if ( canUseLabelCache && ( mCache || !painter ) )
368379
{
369380
// Flattened image for drawing labels
370381
QImage * mypFlattenedImage = nullptr;

‎src/core/qgsmaprendererjob.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ struct LabelRenderJob
7070
QImage* img = nullptr;
7171
//! If true, img already contains cached image from previous rendering
7272
bool cached = false;
73+
//! Will be true if labeling is eligible for caching
74+
bool canUseCache = false;
7375
//! If true then label render is complete
7476
bool complete = false;
7577
//! Time it took to render the labels in ms (it is -1 if not rendered or still rendering)
@@ -218,6 +220,13 @@ class CORE_EXPORT QgsMapRendererJob : public QObject
218220

219221
int mRenderingTime = 0;
220222

223+
/**
224+
* Prepares the cache for storing the result of labeling. Returns false if
225+
* the render cannot use cached labels and should not cache the result.
226+
* @note not available in Python bindings
227+
*/
228+
bool prepareLabelCache() const;
229+
221230
//! @note not available in python bindings
222231
LayerRenderJobs prepareJobs( QPainter* painter, QgsLabelingEngine* labelingEngine2 );
223232

@@ -226,7 +235,7 @@ class CORE_EXPORT QgsMapRendererJob : public QObject
226235
* @note not available in python bindings
227236
* @note added in QGIS 3.0
228237
*/
229-
LabelRenderJob prepareLabelingJob( QPainter* painter, QgsLabelingEngine* labelingEngine2 );
238+
LabelRenderJob prepareLabelingJob( QPainter* painter, QgsLabelingEngine* labelingEngine2, bool canUseLabelCache = true );
230239

231240
//! @note not available in python bindings
232241
static QImage composeImage( const QgsMapSettings& settings, const LayerRenderJobs& jobs, const LabelRenderJob& labelJob );

‎src/core/qgsmaprendererparalleljob.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ void QgsMapRendererParallelJob::start()
6363
mLabelingEngineV2->setMapSettings( mSettings );
6464
}
6565

66+
bool canUseLabelCache = prepareLabelCache();
6667
mLayerJobs = prepareJobs( nullptr, mLabelingEngineV2 );
67-
mLabelJob = prepareLabelingJob( nullptr, mLabelingEngineV2 );
68+
mLabelJob = prepareLabelingJob( nullptr, mLabelingEngineV2, canUseLabelCache );
6869

6970
QgsDebugMsg( QString( "QThreadPool max thread count is %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
7071

‎src/core/qgsrulebasedlabeling.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,20 @@ void QgsRuleBasedLabeling::Rule::updateElseRules()
119119
}
120120
}
121121

122+
bool QgsRuleBasedLabeling::Rule::requiresAdvancedEffects() const
123+
{
124+
if ( mSettings && mSettings->format().containsAdvancedEffects() )
125+
return true;
126+
127+
Q_FOREACH ( Rule* rule, mChildren )
128+
{
129+
if ( rule->requiresAdvancedEffects() )
130+
return true;
131+
}
132+
133+
return false;
134+
}
135+
122136
void QgsRuleBasedLabeling::Rule::subProviderIds( QStringList& list ) const
123137
{
124138
Q_FOREACH ( const Rule* rule, mChildren )
@@ -437,3 +451,8 @@ QgsPalLayerSettings QgsRuleBasedLabeling::settings( QgsVectorLayer* layer, const
437451

438452
return QgsPalLayerSettings();
439453
}
454+
455+
bool QgsRuleBasedLabeling::requiresAdvancedEffects( QgsVectorLayer* ) const
456+
{
457+
return mRootRule->requiresAdvancedEffects();
458+
}

‎src/core/qgsrulebasedlabeling.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
260260
//! register individual features
261261
RegisterResult registerFeature( QgsFeature& feature, QgsRenderContext& context, RuleToProviderMap& subProviders, QgsGeometry* obstacleGeometry = nullptr );
262262

263+
/**
264+
* Returns true if this rule or any of its children requires advanced composition effects
265+
* to render.
266+
*/
267+
bool requiresAdvancedEffects() const;
268+
263269
protected:
264270

265271
/**
@@ -326,6 +332,7 @@ class CORE_EXPORT QgsRuleBasedLabeling : public QgsAbstractVectorLayerLabeling
326332
virtual QgsVectorLayerLabelProvider *provider( QgsVectorLayer* layer ) const override;
327333
virtual QStringList subProviders() const override;
328334
virtual QgsPalLayerSettings settings( QgsVectorLayer* layer, const QString& providerId = QString() ) const override;
335+
bool requiresAdvancedEffects( QgsVectorLayer* layer ) const override;
329336

330337
protected:
331338
Rule* mRootRule;

‎src/core/qgsvectorlayerlabeling.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,8 @@ QgsPalLayerSettings QgsVectorLayerSimpleLabeling::settings( QgsVectorLayer* laye
6060
else
6161
return QgsPalLayerSettings();
6262
}
63+
64+
bool QgsVectorLayerSimpleLabeling::requiresAdvancedEffects( QgsVectorLayer* layer ) const
65+
{
66+
return settings( layer ).format().containsAdvancedEffects();
67+
}

‎src/core/qgsvectorlayerlabeling.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ class CORE_EXPORT QgsAbstractVectorLayerLabeling
5656
//! they are identified by their ID (e.g. in case of rule-based labeling, provider ID == rule key)
5757
virtual QgsPalLayerSettings settings( QgsVectorLayer* layer, const QString& providerId = QString() ) const = 0;
5858

59+
/**
60+
* Returns true if drawing labels requires advanced effects like composition
61+
* modes, which could prevent it being used as an isolated cached image
62+
* or exported to a vector format.
63+
* @note added in QGIS 3.0
64+
*/
65+
virtual bool requiresAdvancedEffects( QgsVectorLayer* layer ) const = 0;
66+
5967
// static stuff
6068

6169
//! Try to create instance of an implementation based on the XML data
@@ -79,6 +87,7 @@ class CORE_EXPORT QgsVectorLayerSimpleLabeling : public QgsAbstractVectorLayerLa
7987
virtual QgsVectorLayerLabelProvider* provider( QgsVectorLayer* layer ) const override;
8088
virtual QDomElement save( QDomDocument& doc ) const override;
8189
virtual QgsPalLayerSettings settings( QgsVectorLayer* layer, const QString& providerId = QString() ) const override;
90+
bool requiresAdvancedEffects( QgsVectorLayer* layer ) const override;
8291
};
8392

8493
#endif // QGSVECTORLAYERLABELING_H

0 commit comments

Comments
 (0)
Please sign in to comment.