Skip to content

Commit

Permalink
Non-default blend mode should force raster render of layer
Browse files Browse the repository at this point in the history
Fixes rendering of vector tile and annotation layers with non
default blend modes in layouts

Fixes #55629
  • Loading branch information
nyalldawson committed Oct 10, 2024
1 parent de16c30 commit 9ed009f
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 2 deletions.
12 changes: 11 additions & 1 deletion src/core/annotations/qgsannotationlayerrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ QgsAnnotationLayerRenderer::QgsAnnotationLayerRenderer( QgsAnnotationLayer *laye
: QgsMapLayerRenderer( layer->id(), &context )
, mFeedback( std::make_unique< QgsFeedback >() )
, mLayerOpacity( layer->opacity() )
, mLayerBlendMode( layer->blendMode() )
{
if ( QgsMapLayer *linkedLayer = layer->linkedVisibilityLayer() )
{
Expand Down Expand Up @@ -123,5 +124,14 @@ bool QgsAnnotationLayerRenderer::render()

bool QgsAnnotationLayerRenderer::forceRasterRender() const
{
return renderContext()->testFlag( Qgis::RenderContextFlag::UseAdvancedEffects ) && ( !qgsDoubleNear( mLayerOpacity, 1.0 ) );
if ( !renderContext()->testFlag( Qgis::RenderContextFlag::UseAdvancedEffects ) )
return false;

if ( !qgsDoubleNear( mLayerOpacity, 1.0 ) )
return true;

if ( mLayerBlendMode != QPainter::CompositionMode_SourceOver )
return true;

return false;
}
1 change: 1 addition & 0 deletions src/core/annotations/qgsannotationlayerrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class CORE_EXPORT QgsAnnotationLayerRenderer : public QgsMapLayerRenderer
std::vector < std::pair< QString, std::unique_ptr< QgsAnnotationItem > > > mItems;
std::unique_ptr< QgsFeedback > mFeedback;
double mLayerOpacity = 1.0;
QPainter::CompositionMode mLayerBlendMode = QPainter::CompositionMode::CompositionMode_SourceOver;
std::unique_ptr< QgsPaintEffect > mPaintEffect;

};
Expand Down
12 changes: 11 additions & 1 deletion src/core/vectortile/qgsvectortilelayerrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ QgsVectorTileLayerRenderer::QgsVectorTileLayerRenderer( QgsVectorTileLayer *laye
, mLayerName( layer->name() )
, mDataProvider( qgis::down_cast< const QgsVectorTileDataProvider* >( layer->dataProvider() )->clone() )
, mRenderer( layer->renderer()->clone() )
, mLayerBlendMode( layer->blendMode() )
, mDrawTileBoundaries( layer->isTileBorderRenderingEnabled() )
, mLabelsEnabled( layer->labelsEnabled() )
, mFeedback( new QgsFeedback )
Expand Down Expand Up @@ -237,7 +238,16 @@ bool QgsVectorTileLayerRenderer::render()

bool QgsVectorTileLayerRenderer::forceRasterRender() const
{
return renderContext()->testFlag( Qgis::RenderContextFlag::UseAdvancedEffects ) && ( !qgsDoubleNear( mLayerOpacity, 1.0 ) );
if ( !renderContext()->testFlag( Qgis::RenderContextFlag::UseAdvancedEffects ) )
return false;

if ( !qgsDoubleNear( mLayerOpacity, 1.0 ) )
return true;

if ( mLayerBlendMode != QPainter::CompositionMode_SourceOver )
return true;

return false;
}

void QgsVectorTileLayerRenderer::decodeAndDrawTile( const QgsVectorTileRawData &rawTile )
Expand Down
2 changes: 2 additions & 0 deletions src/core/vectortile/qgsvectortilelayerrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ class QgsVectorTileLayerRenderer : public QgsMapLayerRenderer
//! Tile renderer object to do rendering of individual tiles
std::unique_ptr<QgsVectorTileRenderer> mRenderer;

QPainter::CompositionMode mLayerBlendMode = QPainter::CompositionMode::CompositionMode_SourceOver;

/**
* Label provider that handles registration of labels.
* No need to delete: if exists it is owned by labeling engine.
Expand Down
19 changes: 19 additions & 0 deletions tests/src/python/test_qgsannotationlayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,25 @@ def test_render_via_job_with_transform(self):
self.assertTrue(compareWkt(result, expected, tol=1000), "mismatch Expected:\n{}\nGot:\n{}\n".format(expected,
result))

def test_force_raster_render(self):
layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()))
self.assertTrue(layer.isValid())
settings = QgsMapSettings()
rc = QgsRenderContext.fromMapSettings(settings)
renderer = layer.createMapRenderer(rc)
self.assertFalse(renderer.forceRasterRender())

# layer opacity should force raster render
layer.setOpacity(0.5)
renderer = layer.createMapRenderer(rc)
self.assertTrue(renderer.forceRasterRender())
layer.setOpacity(1.0)

# alternate blend mode should force raster render
layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Multiply)
renderer = layer.createMapRenderer(rc)
self.assertTrue(renderer.forceRasterRender())

def testRenderWithDisabledItems(self):
layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()))
self.assertTrue(layer.isValid())
Expand Down
22 changes: 22 additions & 0 deletions tests/src/python/test_qgsvectortile.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from pathlib import Path

from qgis.PyQt.QtTest import QSignalSpy
from qgis.PyQt.QtGui import QPainter
from qgis.core import (
Qgis,
QgsDataSourceUri,
Expand All @@ -29,6 +30,8 @@
QgsVectorLayer,
QgsVectorTileLayer,
QgsVectorTileWriter,
QgsMapSettings,
QgsRenderContext
)
import unittest
from qgis.testing import start_app, QgisTestCase
Expand Down Expand Up @@ -294,6 +297,25 @@ def testSelection(self):
self.assertCountEqual({f.geometry().asWkt(-3) for f in layer.selectedFeatures()}, {'Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))'})
self.assertEqual(len(spy), 11)

def test_force_raster_render(self):
layer = QgsVectorTileLayer(f"type=vtpk&url={unitTestDataPath() + '/testvtpk.vtpk'}", 'tiles')
self.assertTrue(layer.isValid())
settings = QgsMapSettings()
rc = QgsRenderContext.fromMapSettings(settings)
renderer = layer.createMapRenderer(rc)
self.assertFalse(renderer.forceRasterRender())

# layer opacity should force raster render
layer.setOpacity(0.5)
renderer = layer.createMapRenderer(rc)
self.assertTrue(renderer.forceRasterRender())
layer.setOpacity(1.0)

# alternate blend mode should force raster render
layer.setBlendMode(QPainter.CompositionMode.CompositionMode_Multiply)
renderer = layer.createMapRenderer(rc)
self.assertTrue(renderer.forceRasterRender())


if __name__ == '__main__':
unittest.main()

0 comments on commit 9ed009f

Please sign in to comment.