From c677303ca2ad9843db7bec8fa5e4762cd12ddbc7 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 16 Sep 2025 14:18:59 +0700 Subject: [PATCH 1/2] [dxf] Fix erroneous handling of rendering context when exporting multiple layers --- src/core/dxf/qgsdxfexport.cpp | 14 +++---- src/core/dxf/qgsdxfexport_p.h | 4 +- tests/src/core/testqgsdxfexport.cpp | 59 +++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/core/dxf/qgsdxfexport.cpp b/src/core/dxf/qgsdxfexport.cpp index 5916c0b7e5f3..17e125aaf4ea 100644 --- a/src/core/dxf/qgsdxfexport.cpp +++ b/src/core/dxf/qgsdxfexport.cpp @@ -755,7 +755,7 @@ void QgsDxfExport::writeEntities() // iterate through the maplayers for ( DxfLayerJob *job : std::as_const( mJobs ) ) { - QgsSymbolRenderContext sctx( mRenderContext, Qgis::RenderUnit::Millimeters, 1.0, false, Qgis::SymbolRenderHints(), nullptr ); + QgsSymbolRenderContext sctx( job->renderContext, Qgis::RenderUnit::Millimeters, 1.0, false, Qgis::SymbolRenderHints(), nullptr ); if ( mSymbologyExport == Qgis::FeatureSymbologyExport::PerSymbolLayer && ( job->renderer->capabilities() & QgsFeatureRenderer::SymbolLevels ) && @@ -782,12 +782,12 @@ void QgsDxfExport::writeEntities() QgsFeature fet; while ( featureIt.nextFeature( fet ) ) { - mRenderContext.expressionContext().setFeature( fet ); + job->renderContext.expressionContext().setFeature( fet ); QString lName( dxfLayerName( job->splitLayerAttribute.isNull() ? job->layerDerivedName : fet.attribute( job->splitLayerAttribute ).toString() ) ); sctx.setFeature( &fet ); - if ( !job->renderer->willRenderFeature( fet, mRenderContext ) ) + if ( !job->renderer->willRenderFeature( fet, job->renderContext ) ) continue; if ( mSymbologyExport == Qgis::FeatureSymbologyExport::NoSymbology ) @@ -796,7 +796,7 @@ void QgsDxfExport::writeEntities() } else { - const QgsSymbolList symbolList = job->renderer->symbolsForFeature( fet, mRenderContext ); + const QgsSymbolList symbolList = job->renderer->symbolsForFeature( fet, job->renderContext ); bool hasSymbology = symbolList.size() > 0; if ( hasSymbology && mSymbologyExport == Qgis::FeatureSymbologyExport::PerSymbolLayer ) // symbol layer symbology, but layer does not use symbol levels @@ -842,14 +842,14 @@ void QgsDxfExport::writeEntities() if ( job->labelProvider ) { - job->labelProvider->registerFeature( fet, mRenderContext ); + job->labelProvider->registerFeature( fet, job->renderContext ); Q_NOWARN_DEPRECATED_PUSH registerDxfLayer( job->featureSource.id(), fet.id(), lName ); Q_NOWARN_DEPRECATED_POP } else if ( job->ruleBasedLabelProvider ) { - job->ruleBasedLabelProvider->registerFeature( fet, mRenderContext ); + job->ruleBasedLabelProvider->registerFeature( fet, job->renderContext ); Q_NOWARN_DEPRECATED_PUSH registerDxfLayer( job->featureSource.id(), fet.id(), lName ); Q_NOWARN_DEPRECATED_POP @@ -2409,8 +2409,6 @@ QString QgsDxfExport::layerName( QgsVectorLayer *vl ) const void QgsDxfExport::drawLabel( const QString &layerId, QgsRenderContext &context, pal::LabelPosition *label, const QgsPalLayerSettings &settings ) { - Q_UNUSED( context ) - if ( !settings.drawLabels ) return; diff --git a/src/core/dxf/qgsdxfexport_p.h b/src/core/dxf/qgsdxfexport_p.h index cb00d13f0be8..281920616e58 100644 --- a/src/core/dxf/qgsdxfexport_p.h +++ b/src/core/dxf/qgsdxfexport_p.h @@ -33,8 +33,8 @@ */ struct DxfLayerJob { - DxfLayerJob( QgsVectorLayer *vl, const QString &layerStyleOverride, QgsRenderContext &renderContext, QgsDxfExport *dxfExport, const QString &splitLayerAttribute, const QString &layerDerivedName ) - : renderContext( renderContext ) + DxfLayerJob( QgsVectorLayer *vl, const QString &layerStyleOverride, QgsRenderContext &context, QgsDxfExport *dxfExport, const QString &splitLayerAttribute, const QString &layerDerivedName ) + : renderContext( context ) , styleOverride( vl ) , featureSource( vl ) , dxfExport( dxfExport ) diff --git a/tests/src/core/testqgsdxfexport.cpp b/tests/src/core/testqgsdxfexport.cpp index 3cd74c6a64d9..d8feba07c335 100644 --- a/tests/src/core/testqgsdxfexport.cpp +++ b/tests/src/core/testqgsdxfexport.cpp @@ -85,6 +85,7 @@ class TestQgsDxfExport : public QObject void testOutputLayerNamePrecedence(); void testMinimumLineWidthExport(); void testWritingCodepage(); + void testExpressionContext(); private: QgsVectorLayer *mPointLayer = nullptr; @@ -101,6 +102,16 @@ class TestQgsDxfExport : public QObject bool fileContainsText( const QString &path, const QString &text, QString *debugInfo = nullptr ) const; }; +void TestQgsDxfExport::setDefaultLabelParams( QgsPalLayerSettings &settings ) +{ + QgsTextFormat format; + format.setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) ).family() ); + format.setSize( 12 ); + format.setNamedStyle( QStringLiteral( "Bold" ) ); + format.setColor( QColor( 200, 0, 200 ) ); + settings.setFormat( format ); +} + void TestQgsDxfExport::initTestCase() { QgsApplication::init(); @@ -1988,6 +1999,54 @@ void TestQgsDxfExport::testWritingCodepage() QVERIFY( fileContainsText( file2, QStringLiteral( "ANSI_1252" ) ) ); } +void TestQgsDxfExport::testExpressionContext() +{ + // This test is aimed at testing whether the right expression context is passed onto symbology and labeling while we are iterating through features. + + auto vl = std::make_unique( QStringLiteral( "LineString?crs=epsg:4326&field=id:string" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ); + + QgsFeature f; + f.setAttributes( QgsAttributes() << QStringLiteral( "1" ) ); + f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString (-112.5 44.9, -88.6 44.9)" ) ) ); + QVERIFY( vl->dataProvider()->addFeature( f ) ); + + vl->setRenderer( new QgsSingleSymbolRenderer( QgsLineSymbol::createSimple( { { QStringLiteral( "color" ), QStringLiteral( "#000000" ) }, { QStringLiteral( "outline_width" ), 0.6 } } ).release() ) ); + + QgsPalLayerSettings settings; + settings.fieldName = QStringLiteral( "represent_value(\"Class\")" ); + settings.isExpression = true; + QgsTextFormat format; + format.setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) ).family() ); + format.setSize( 12 ); + format.setNamedStyle( QStringLiteral( "Bold" ) ); + format.setColor( QColor( 200, 0, 200 ) ); + settings.setFormat( format ); + mPointLayerNoSymbols->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); + mPointLayerNoSymbols->setLabelsEnabled( true ); + + QgsDxfExport d; + d.addLayers( QList() << QgsDxfExport::DxfLayer( mPointLayerNoSymbols ) << QgsDxfExport::DxfLayer( vl.get() ) ); + + QgsMapSettings mapSettings; + const QSize size( 640, 480 ); + mapSettings.setOutputSize( size ); + mapSettings.setExtent( mPointLayerNoSymbols->extent() ); + mapSettings.setLayers( QList() << mPointLayerNoSymbols << vl.get() ); + mapSettings.setOutputDpi( 96 ); + mapSettings.setDestinationCrs( mPointLayerNoSymbols->crs() ); + + d.setMapSettings( mapSettings ); + d.setSymbologyScale( 1000 ); + d.setSymbologyExport( Qgis::FeatureSymbologyExport::PerFeature ); + + const QString file = getTempFileName( "context_dxf" ); + QFile dxfFile( file ); + QCOMPARE( d.writeToFile( &dxfFile, QStringLiteral( "CP1252" ) ), QgsDxfExport::ExportResult::Success ); + dxfFile.close(); + QString debugInfo; + QVERIFY2( fileContainsText( file, "\\fQGIS Vera Sans|i0|b1;\\H3.81136;Biplane", &debugInfo ), debugInfo.toUtf8().constData() ); +} + bool TestQgsDxfExport::fileContainsText( const QString &path, const QString &text, QString *debugInfo ) const { QStringList debugLines; From 40c1cc8f99fbb5ca7cbc2d8e82e7ab3e1cc4ccea Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Wed, 17 Sep 2025 13:34:29 +0700 Subject: [PATCH 2/2] Move test to regexp --- tests/src/core/testqgsdxfexport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/core/testqgsdxfexport.cpp b/tests/src/core/testqgsdxfexport.cpp index d8feba07c335..ec8a9c39f496 100644 --- a/tests/src/core/testqgsdxfexport.cpp +++ b/tests/src/core/testqgsdxfexport.cpp @@ -2044,7 +2044,7 @@ void TestQgsDxfExport::testExpressionContext() QCOMPARE( d.writeToFile( &dxfFile, QStringLiteral( "CP1252" ) ), QgsDxfExport::ExportResult::Success ); dxfFile.close(); QString debugInfo; - QVERIFY2( fileContainsText( file, "\\fQGIS Vera Sans|i0|b1;\\H3.81136;Biplane", &debugInfo ), debugInfo.toUtf8().constData() ); + QVERIFY2( fileContainsText( file, "REGEX Biplane", &debugInfo ), debugInfo.toUtf8().constData() ); } bool TestQgsDxfExport::fileContainsText( const QString &path, const QString &text, QString *debugInfo ) const