77 #include <QStringList> 
   78 #include <QTemporaryFile> 
   81 #include <nlohmann/json.hpp> 
  106     : mContext( context )
 
  108     mProject = mContext.project();
 
  110     mWmsParameters = mContext.parameters();
 
  111     mWmsParameters.dump();
 
  116     removeTemporaryLayers();
 
  122     std::unique_ptr<QgsWmsRestorer> restorer;
 
  134     std::unique_ptr<QImage> image;
 
  136     const QSizeF minSize = renderer.minimumSize();
 
  137     const QSize size( 
static_cast<int>( minSize.width() * dpmm ), 
static_cast<int>( minSize.height() * dpmm ) );
 
  142     image.reset( createImage( size ) );
 
  145     QPainter painter( image.get() );
 
  156     renderer.drawLegend( context );
 
  159     return image.release();
 
  165     std::unique_ptr<QgsWmsRestorer> restorer;
 
  166     restorer.reset( 
new QgsWmsRestorer( mContext ) );
 
  179     std::unique_ptr<QImage> image( createImage( size ) );
 
  183     std::unique_ptr<QPainter> painter;
 
  184     painter.reset( 
new QPainter( image.get() ) );
 
  185     painter->setRenderHint( QPainter::Antialiasing, 
true );
 
  186     painter->scale( dpmm, dpmm );
 
  192     nodeModel.
drawSymbol( settings, &ctx, size.height() / dpmm );
 
  195     return image.release();
 
  201     std::unique_ptr<QgsWmsRestorer> restorer;
 
  202     restorer.reset( 
new QgsWmsRestorer( mContext ) );
 
  214     return renderer.exportLegendToJson( renderContext );
 
  217   void QgsRenderer::runHitTest( 
const QgsMapSettings &mapSettings, HitTest &hitTest )
 const 
  221     for ( 
const QString &
id : mapSettings.
layerIds() )
 
  238       runHitTestLayer( vl, usedSymbols, context );
 
  244     std::unique_ptr< QgsFeatureRenderer > r( vl->
renderer()->
clone() );
 
  246     r->startRender( context, vl->
fields() );
 
  254       if ( moreSymbolsPerFeature )
 
  256         for ( 
QgsSymbol *s : r->originalSymbolsForFeature( f, context ) )
 
  262     r->stopRender( context );
 
  271                                     QStringLiteral( 
"The requested map size is too large" ) );
 
  275     std::unique_ptr<QgsWmsRestorer> restorer;
 
  276     restorer.reset( 
new QgsWmsRestorer( mContext ) );
 
  285     std::unique_ptr<QPainter> painter;
 
  286     std::unique_ptr<QImage> image( createImage( mContext.
mapSize() ) );
 
  289     configureMapSettings( image.get(), mapSettings );
 
  296     runHitTest( mapSettings, 
symbols );
 
  304     std::unique_ptr<QgsWmsRestorer> restorer;
 
  309     if ( templateName.isEmpty() )
 
  330     if ( sourceLayout->pageCollection()->pageCount() < 1 )
 
  333                                     QStringLiteral( 
"The template has no pages" ) );
 
  336     std::unique_ptr<QgsPrintLayout> layout( sourceLayout->clone() );
 
  340     QStringList atlasPk = mWmsParameters.
atlasPk();
 
  341     if ( !atlasPk.isEmpty() ) 
 
  343       atlas = layout->atlas();
 
  344       if ( !atlas || !atlas->
enabled() )
 
  348                                       QStringLiteral( 
"The template has no atlas enabled" ) );
 
  355                                       QStringLiteral( 
"The atlas has no coverage layer" ) );
 
  359       if ( atlasPk.size() == 1 && atlasPk.at( 0 ) == QLatin1String( 
"*" ) )
 
  363         if ( atlas->
count() > maxAtlasFeatures )
 
  366                                         QString( 
"The project configuration allows printing maximum %1 atlas features at a time" ).arg( maxAtlasFeatures ) );
 
  372         if ( pkIndexes.size() == 0 )
 
  374           QgsDebugMsgLevel( QStringLiteral( 
"Atlas print: layer %1 has no primary key attributes" ).arg( cLayer->
name() ), 2 );
 
  378         const int pkIndexesSize {std::max( pkIndexes.size(), 1 )};
 
  380         QStringList pkAttributeNames;
 
  381         for ( 
int pkIndex : std::as_const( pkIndexes ) )
 
  383           pkAttributeNames.append( cLayer->
fields().
at( pkIndex ).
name() );
 
  386         const int nAtlasFeatures = atlasPk.size() / pkIndexesSize;
 
  387         if ( nAtlasFeatures * pkIndexesSize != atlasPk.size() ) 
 
  390                                         QStringLiteral( 
"Wrong number of ATLAS_PK parameters" ) );
 
  394         if ( nAtlasFeatures > maxAtlasFeatures )
 
  397                                         QString( 
"%1 atlas features have been requested, but the project configuration only allows printing %2 atlas features at a time" )
 
  398                                         .arg( nAtlasFeatures ).arg( maxAtlasFeatures ) );
 
  401         QString filterString;
 
  402         int currentAtlasPk = 0;
 
  404         for ( 
int i = 0; i < nAtlasFeatures; ++i )
 
  408             filterString.append( 
" OR " );
 
  411           filterString.append( 
"( " );
 
  414           if ( pkAttributeNames.isEmpty() )
 
  416             filterString.append( QStringLiteral( 
"$id = %1" ).arg( atlasPk.at( currentAtlasPk ) ) );
 
  421             for ( 
int j = 0; j < pkIndexes.size(); ++j )
 
  425                 filterString.append( 
" AND " );
 
  432           filterString.append( 
" )" );
 
  438         if ( !errorString.isEmpty() )
 
  440           throw QgsException( QStringLiteral( 
"An error occurred during the Atlas print: %1" ).arg( errorString ) );
 
  452     std::unique_ptr<QImage> image( 
new QImage() );
 
  453     configureMapSettings( image.get(), mapSettings );
 
  459     configurePrintLayout( layout.get(), mapSettings, atlas );
 
  463     const QList<QgsMapLayer *> lyrs = mapSettings.
layers();
 
  465 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  466     mContext.accessControl()->resolveFilterFeatures( lyrs );
 
  470     QHash<const QgsVectorLayer *, QStringList> fltrs;
 
  475         fltrs.insert( vl, dimensionFilter( vl ) );
 
  487     QTemporaryFile tempOutputFile( QDir::tempPath() +  
'/' + QStringLiteral( 
"XXXXXX.%1" ).arg( extension ) );
 
  488     if ( !tempOutputFile.open() )
 
  490       throw QgsException( QStringLiteral( 
"Could not open temporary file for the GetPrint request." ) );
 
  499       if ( !mWmsParameters.
dpi().isEmpty() )
 
  502         double dpi( mWmsParameters.
dpi().toDouble( &ok ) );
 
  504           exportSettings.
dpi = dpi;
 
  515           atlasSvgExport.exportToSvg( tempOutputFile.fileName(), exportSettings );
 
  521         exporter.exportToSvg( tempOutputFile.fileName(), exportSettings );
 
  530       double dpi( layout->renderContext().dpi( ) );
 
  531       if ( !mWmsParameters.
dpi().isEmpty() )
 
  534         double _dpi = mWmsParameters.
dpi().toDouble( &ok );
 
  538       exportSettings.
dpi = dpi;
 
  542       QgsLayoutSize layoutSize( layout->pageCollection()->page( 0 )->sizeWithUnits() );
 
  544       QgsLayoutMeasurement width( layout->convertFromLayoutUnits( layoutSize.width(), QgsUnitTypes::LayoutUnit::LayoutMillimeters ) );
 
  545       QgsLayoutMeasurement height( layout->convertFromLayoutUnits( layoutSize.height(), QgsUnitTypes::LayoutUnit::LayoutMillimeters ) );
 
  547       const QSize imageSize = QSize( 
static_cast<int>( width.length() * dpi / 25.4 ), 
static_cast<int>( height.length() * dpi / 25.4 ) );
 
  549       const QString paramWidth = mWmsParameters.
width();
 
  550       const QString paramHeight = mWmsParameters.
height();
 
  555       if ( !paramWidth.isEmpty() && !paramHeight.isEmpty() )
 
  557         exportSettings.
imageSize = QSize( paramWidth.toInt(), paramHeight.toInt() );
 
  559       else if ( !paramWidth.isEmpty() && paramHeight.isEmpty() )
 
  561         exportSettings.
imageSize = QSize( paramWidth.toInt(), 
static_cast<double>( paramWidth.toInt() ) / imageSize.width() * imageSize.height() );
 
  563       else if ( paramWidth.isEmpty() && !paramHeight.isEmpty() )
 
  565         exportSettings.
imageSize = QSize( 
static_cast<double>( paramHeight.toInt() ) / imageSize.height() * imageSize.width(), paramHeight.toInt() );
 
  573       exportSettings.
pages.append( 0 );
 
  581           atlasPngExport.exportToImage( tempOutputFile.fileName(), exportSettings );
 
  585           throw QgsServiceException( QStringLiteral( 
"Bad request" ), QStringLiteral( 
"Atlas error: empty atlas." ), QString(), 400 );
 
  591         exporter.exportToImage( tempOutputFile.fileName(), exportSettings );
 
  599       if ( !mWmsParameters.
dpi().isEmpty() )
 
  602         double dpi( mWmsParameters.
dpi().toDouble( &ok ) );
 
  604           exportSettings.
dpi = dpi;
 
  609       exportSettings.
rasterizeWholeImage = layout->customProperty( QStringLiteral( 
"rasterize" ), 
false ).toBool();
 
  619         exporter.exportToPdf( tempOutputFile.fileName(), exportSettings );
 
  630       handlePrintErrors( atlas->
layout() );
 
  634       handlePrintErrors( layout.get() );
 
  637     return tempOutputFile.readAll();
 
  645     QList<QgsLayoutItemMap *> maps;
 
  651     for ( 
const auto &map : std::as_const( maps ) )
 
  657       if ( cMapParams.mLayers.isEmpty() )
 
  662       if ( !atlasPrint || !map->atlasDriven() ) 
 
  665         if ( !cMapParams.mHasExtent )
 
  668           c->removeLayoutItem( map );
 
  686         if ( cMapParams.mScale > 0 )
 
  688           map->setScale( 
static_cast<double>( cMapParams.mScale ) );
 
  692         if ( cMapParams.mRotation )
 
  694           map->setMapRotation( cMapParams.mRotation );
 
  698       if ( !map->keepLayerSet() )
 
  700         QList<QgsMapLayer *> layerSet;
 
  702         for ( 
const auto &layer : std::as_const( cMapParams.mLayers ) )
 
  706             QList<QgsMapLayer *> layersFromGroup;
 
  708             const QList<QgsMapLayer *> cLayersFromGroup = mContext.
layersFromGroup( layer.mNickname );
 
  709             for ( 
QgsMapLayer *layerFromGroup : cLayersFromGroup )
 
  712               if ( ! layerFromGroup )
 
  717               layersFromGroup.push_front( layerFromGroup );
 
  720             if ( !layersFromGroup.isEmpty() )
 
  722               layerSet.append( layersFromGroup );
 
  734             setLayerStyle( mlayer, layer.mStyle );
 
  739         std::reverse( layerSet.begin(), layerSet.end() );
 
  744         QMap<QString, QString> layersStyle;
 
  745         if ( map->followVisibilityPreset() )
 
  747           const QString presetName = map->followVisibilityPresetName();
 
  748           if ( layerSet.isEmpty() )
 
  752             layerSet = map->layersToRender( &ex );
 
  755           map->setFollowVisibilityPreset( 
false );
 
  759           for ( 
const auto &layerMapThemeRecord : std::as_const( mapThemeRecords ) )
 
  761             if ( layerSet.contains( layerMapThemeRecord.layer() ) )
 
  763               layersStyle.insert( layerMapThemeRecord.layer()->id(),
 
  764                                   layerMapThemeRecord.layer()->styleManager()->style( layerMapThemeRecord.currentStyle ).xmlData() );
 
  770         const QList< QgsMapLayer *> highlights = highlightLayers( cMapParams.mHighlightLayers );
 
  771         for ( 
const auto &hl : std::as_const( highlights ) )
 
  773           layerSet.prepend( hl );
 
  776         map->setLayers( layerSet );
 
  777         map->setKeepLayerSet( 
true );
 
  781         if ( !layersStyle.isEmpty() )
 
  783           map->setLayerStyleOverrides( layersStyle );
 
  784           map->setKeepLayerStyles( 
true );
 
  789       if ( cMapParams.mGridX > 0 && cMapParams.mGridY > 0 )
 
  791         map->grid()->setIntervalX( 
static_cast<double>( cMapParams.mGridX ) );
 
  792         map->grid()->setIntervalY( 
static_cast<double>( cMapParams.mGridY ) );
 
  797     QList<QgsLayoutItemLabel *> labels;
 
  799     for ( 
const auto &label : std::as_const( labels ) )
 
  802       const QString labelId = label->
id();
 
  803       const QString labelParam = mWmsParameters.
layoutParameter( labelId, ok );
 
  808       if ( labelParam.isEmpty() )
 
  812         c->removeItem( label );
 
  817       label->setText( labelParam );
 
  821     QList<QgsLayoutItemHtml *> htmls;
 
  823     for ( 
const auto &html : std::as_const( htmls ) )
 
  825       if ( html->frameCount() == 0 )
 
  830       const QString htmlId = htmlFrame->
id();
 
  843         c->removeMultiFrame( html );
 
  849       html->setUrl( newUrl );
 
  855     QList<QgsLayoutItemLegend *> legends;
 
  857     for ( 
const auto &legend : std::as_const( legends ) )
 
  859       if ( legend->autoUpdateModel() )
 
  869         legend->setAutoUpdateModel( 
false );
 
  873         QStringList layerSet;
 
  874         QList<QgsMapLayer *> mapLayers;
 
  875         if ( map->
layers().isEmpty() )
 
  879           mapLayers = mProject->
mapLayers( 
true ).values();
 
  883           mapLayers = map->
layers();
 
  885         const QList<QgsMapLayer *> layerList = mapLayers;
 
  886         for ( 
const auto &layer : layerList )
 
  887           layerSet << layer->id();
 
  899         for ( 
const auto &layerId : layerIds )
 
  906           if ( !layerSet.contains( layerId ) )
 
  908             qobject_cast<QgsLayerTreeGroup *>( nodeLayer->
parent() )->removeChildNode( nodeLayer );
 
  915               qobject_cast<QgsLayerTreeGroup *>( nodeLayer->
parent() )->removeChildNode( nodeLayer );
 
  931                                     QStringLiteral( 
"The requested map size is too large" ) );
 
  935     std::unique_ptr<QgsWmsRestorer> restorer;
 
  936     restorer.reset( 
new QgsWmsRestorer( mContext ) );
 
  946     std::unique_ptr<QPainter> painter;
 
  947     std::unique_ptr<QImage> image( createImage( mContext.
mapSize() ) );
 
  950     configureMapSettings( image.get(), mapSettings );
 
  956     painter.reset( layersRendering( mapSettings, *image ) );
 
  959     annotationsRendering( painter.get(), mapSettings );
 
  965     QImage *scaledImage = scaleImage( image.get() );
 
  967       image.reset( scaledImage );
 
  970     return image.release();
 
  976     std::unique_ptr<QgsWmsRestorer> restorer;
 
  985     QList< QgsDxfExport::DxfLayer > dxfLayers;
 
  997       int layerAttribute = -1;
 
  998       if ( attributes.size() > layerIdx )
 
 1009     QString 
crs = mWmsParameters.
crs();
 
 1010     if ( 
crs.compare( QStringLiteral( 
"CRS:84" ), Qt::CaseInsensitive ) == 0 )
 
 1012       crs = QStringLiteral( 
"EPSG:4326" );
 
 1015     else if ( 
crs.isEmpty() )
 
 1017       crs = QStringLiteral( 
"EPSG:4326" );
 
 1025       QgsWmsParameter parameter;
 
 1051     std::unique_ptr<QgsDxfExport> dxf = std::make_unique<QgsDxfExport>();
 
 1052     dxf->setExtent( mapExtent );
 
 1053     dxf->setDestinationCrs( outputCRS );
 
 1054     dxf->addLayers( dxfLayers );
 
 1056     dxf->setSymbologyExport( mWmsParameters.
dxfMode() );
 
 1057     if ( mWmsParameters.
dxfFormatOptions().contains( QgsWmsParameters::DxfFormatOption::SCALE ) )
 
 1059       dxf->setSymbologyScale( mWmsParameters.
dxfScale() );
 
 1062     dxf->setForce2d( mWmsParameters.
isForce2D() );
 
 1063     QgsDxfExport::Flags flags;
 
 1064     if ( mWmsParameters.
noMText() )
 
 1065       flags.setFlag( QgsDxfExport::Flag::FlagNoMText );
 
 1067     dxf->setFlags( flags );
 
 1075     if ( i < 0 || i > mapSettings.
outputSize().width() )
 
 1083     if ( j < 0 || j > mapSettings.
outputSize().height() )
 
 1108     const bool ijDefined = !mWmsParameters.
i().isEmpty() && !mWmsParameters.
j().isEmpty();
 
 1109     const bool xyDefined = !mWmsParameters.
x().isEmpty() && !mWmsParameters.
y().isEmpty();
 
 1110     const bool filtersDefined = !mWmsParameters.
filters().isEmpty();
 
 1111     const bool filterGeomDefined = !mWmsParameters.
filterGeom().isEmpty();
 
 1113     if ( !ijDefined && !xyDefined && !filtersDefined && !filterGeomDefined )
 
 1117       if ( mWmsParameters.
j().isEmpty() )
 
 1124     if ( infoFormat == QgsWmsParameters::Format::NONE )
 
 1131     std::unique_ptr<QImage> outputImage( createImage( mContext.
mapSize() ) );
 
 1134     std::unique_ptr<QgsWmsRestorer> restorer;
 
 1135     restorer.reset( 
new QgsWmsRestorer( mContext ) );
 
 1139     bool mandatoryCrsParam = 
true;
 
 1140     if ( filtersDefined && !ijDefined && !xyDefined && mWmsParameters.
crs().isEmpty() )
 
 1142       mandatoryCrsParam = 
false;
 
 1148     configureMapSettings( outputImage.get(), mapSettings, mandatoryCrsParam );
 
 1152     const double scaleDenominator = scaleCalc.calculate( mWmsParameters.
bboxAsRectangle(), outputImage->
width() );
 
 1155     QgsWmsRenderContext context = mContext;
 
 1158     QList<QgsMapLayer *> layers = context.layersToRender();
 
 1164 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
 1165     mContext.accessControl()->resolveFilterFeatures( mapSettings.
layers() );
 
 1168     QDomDocument result = featureInfoDocument( layers, mapSettings, outputImage.get(), version );
 
 1172     if ( infoFormat == QgsWmsParameters::Format::TEXT )
 
 1173       ba = convertFeatureInfoToText( result );
 
 1174     else if ( infoFormat == QgsWmsParameters::Format::HTML )
 
 1175       ba = convertFeatureInfoToHtml( result );
 
 1176     else if ( infoFormat == QgsWmsParameters::Format::JSON )
 
 1177       ba = convertFeatureInfoToJson( layers, result );
 
 1179       ba = result.toByteArray();
 
 1184   QImage *QgsRenderer::createImage( 
const QSize &size )
 const 
 1186     std::unique_ptr<QImage> image;
 
 1194       image = std::make_unique<QImage>( size, QImage::Format_ARGB32_Premultiplied );
 
 1199       image = std::make_unique<QImage>( size, QImage::Format_RGB32 );
 
 1204     if ( image->isNull() )
 
 1206       throw QgsException( QStringLiteral( 
"createImage: image could not be created, check for out of memory conditions" ) );
 
 1209     const int dpm = 
static_cast<int>( mContext.
dotsPerMm() * 1000.0 );
 
 1210     image->setDotsPerMeterX( dpm );
 
 1211     image->setDotsPerMeterY( dpm );
 
 1213     return image.release();
 
 1216   void QgsRenderer::configureMapSettings( 
const QPaintDevice *paintDevice, 
QgsMapSettings &mapSettings, 
bool mandatoryCrsParam )
 
 1220       throw QgsException( QStringLiteral( 
"configureMapSettings: no paint device" ) );
 
 1223     mapSettings.
setOutputSize( QSize( paintDevice->width(), paintDevice->height() ) );
 
 1230     if ( !mWmsParameters.
bbox().isEmpty() && mapExtent.
isEmpty() )
 
 1236     QString 
crs = mWmsParameters.
crs();
 
 1237     if ( 
crs.compare( 
"CRS:84", Qt::CaseInsensitive ) == 0 )
 
 1239       crs = QString( 
"EPSG:4326" );
 
 1242     else if ( 
crs.isEmpty() && !mandatoryCrsParam )
 
 1244       crs = QString( 
"EPSG:4326" );
 
 1254       QgsWmsParameter parameter;
 
 1296     else if ( backgroundColor.isValid() )
 
 1319     const QString timeString { mWmsParameters.
dimensionValues().value( QStringLiteral( 
"TIME" ), QString() ) };
 
 1320     if ( ! timeString.isEmpty() )
 
 1322       bool isValidTemporalRange { 
true };
 
 1323       QgsDateTimeRange range;
 
 1325       const QDateTime dt { QDateTime::fromString( timeString, Qt::DateFormat::ISODateWithMs ) };
 
 1328         range = QgsDateTimeRange( dt, dt );
 
 1338           isValidTemporalRange = 
false;
 
 1339           QgsMessageLog::logMessage( QStringLiteral( 
"Could not parse TIME parameter into a temporal range" ), 
"Server", Qgis::MessageLevel::Warning );
 
 1343       if ( isValidTemporalRange )
 
 1353   QDomDocument QgsRenderer::featureInfoDocument( QList<QgsMapLayer *> &layers, 
const QgsMapSettings &mapSettings,
 
 1354       const QImage *outputImage, 
const QString &version )
 const 
 1358     bool ijDefined = ( !mWmsParameters.
i().isEmpty() && !mWmsParameters.
j().isEmpty() );
 
 1360     bool xyDefined = ( !mWmsParameters.
x().isEmpty() && !mWmsParameters.
y().isEmpty() );
 
 1362     bool filtersDefined = !mWmsParameters.
filters().isEmpty();
 
 1364     bool filterGeomDefined = !mWmsParameters.
filterGeom().isEmpty();
 
 1367     if ( featureCount < 1 )
 
 1372     int i = mWmsParameters.
iAsInt();
 
 1373     int j = mWmsParameters.
jAsInt();
 
 1374     if ( xyDefined && !ijDefined )
 
 1376       i = mWmsParameters.
xAsInt();
 
 1377       j = mWmsParameters.
yAsInt();
 
 1381     if ( ( i != -1 && j != -1 && width != 0 && height != 0 ) && ( width != outputImage->width() || height != outputImage->height() ) )
 
 1383       i *= ( outputImage->width() /  
static_cast<double>( width ) );
 
 1384       j *= ( outputImage->height() / 
static_cast<double>( height ) );
 
 1388     std::unique_ptr<QgsRectangle> featuresRect;
 
 1389     std::unique_ptr<QgsGeometry> filterGeom;
 
 1390     std::unique_ptr<QgsPointXY> infoPoint;
 
 1392     if ( i != -1 && j != -1 )
 
 1395       infoPointToMapCoordinates( i, j, infoPoint.get(), mapSettings );
 
 1397     else if ( filtersDefined )
 
 1401     else if ( filterGeomDefined )
 
 1406     QDomDocument result;
 
 1408     QDomElement getFeatureInfoElement;
 
 1410     if ( infoFormat == QgsWmsParameters::Format::GML )
 
 1412       getFeatureInfoElement = result.createElement( QStringLiteral( 
"wfs:FeatureCollection" ) );
 
 1413       getFeatureInfoElement.setAttribute( QStringLiteral( 
"xmlns:wfs" ), QStringLiteral( 
"http://www.opengis.net/wfs" ) );
 
 1414       getFeatureInfoElement.setAttribute( QStringLiteral( 
"xmlns:ogc" ), QStringLiteral( 
"http://www.opengis.net/ogc" ) );
 
 1415       getFeatureInfoElement.setAttribute( QStringLiteral( 
"xmlns:gml" ), QStringLiteral( 
"http://www.opengis.net/gml" ) );
 
 1416       getFeatureInfoElement.setAttribute( QStringLiteral( 
"xmlns:ows" ), QStringLiteral( 
"http://www.opengis.net/ows" ) );
 
 1417       getFeatureInfoElement.setAttribute( QStringLiteral( 
"xmlns:xlink" ), QStringLiteral( 
"http://www.w3.org/1999/xlink" ) );
 
 1418       getFeatureInfoElement.setAttribute( QStringLiteral( 
"xmlns:qgs" ), QStringLiteral( 
"http://qgis.org/gml" ) );
 
 1419       getFeatureInfoElement.setAttribute( QStringLiteral( 
"xmlns:xsi" ), QStringLiteral( 
"http://www.w3.org/2001/XMLSchema-instance" ) );
 
 1420       getFeatureInfoElement.setAttribute( QStringLiteral( 
"xsi:schemaLocation" ), QStringLiteral( 
"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd http://qgis.org/gml" ) );
 
 1425       if ( featureInfoElemName.isEmpty() )
 
 1427         featureInfoElemName = QStringLiteral( 
"GetFeatureInfoResponse" );
 
 1430       if ( featureInfoElemNs.isEmpty() )
 
 1432         getFeatureInfoElement = result.createElement( featureInfoElemName );
 
 1436         getFeatureInfoElement = result.createElementNS( featureInfoElemNs, featureInfoElemName );
 
 1440       if ( !featureInfoSchema.isEmpty() )
 
 1442         getFeatureInfoElement.setAttribute( QStringLiteral( 
"xmlns:xsi" ), QStringLiteral( 
"http://www.w3.org/2001/XMLSchema-instance" ) );
 
 1443         getFeatureInfoElement.setAttribute( QStringLiteral( 
"xsi:schemaLocation" ), featureInfoSchema );
 
 1446     result.appendChild( getFeatureInfoElement );
 
 1456     for ( 
const QString &queryLayer : queryLayers )
 
 1458       bool validLayer = 
false;
 
 1459       bool queryableLayer = 
true;
 
 1460       for ( 
QgsMapLayer *layer : std::as_const( layers ) )
 
 1466           if ( !queryableLayer )
 
 1471           QDomElement layerElement;
 
 1472           if ( infoFormat == QgsWmsParameters::Format::GML )
 
 1474             layerElement = getFeatureInfoElement;
 
 1478             layerElement = result.createElement( QStringLiteral( 
"Layer" ) );
 
 1479             QString layerName = queryLayer;
 
 1482             QHash<QString, QString>::const_iterator layerAliasIt = layerAliasMap.constFind( layerName );
 
 1483             if ( layerAliasIt != layerAliasMap.constEnd() )
 
 1485               layerName = layerAliasIt.value();
 
 1488             layerElement.setAttribute( QStringLiteral( 
"name" ), layerName );
 
 1489             getFeatureInfoElement.appendChild( layerElement );
 
 1492               layerElement.setAttribute( QStringLiteral( 
"id" ), layer->id() );
 
 1498             QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
 
 1501               ( void )featureInfoFromVectorLayer( vectorLayer, infoPoint.get(), featureCount, result, layerElement, mapSettings, renderContext, version, featuresRect.get(), filterGeom.get() );
 
 1507             QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer );
 
 1516             QgsPointXY layerInfoPoint = mapSettings.mapToLayerCoordinates( layer, *( infoPoint.get() ) );
 
 1521             if ( infoFormat == QgsWmsParameters::Format::GML )
 
 1523               layerElement = result.createElement( QStringLiteral( 
"gml:featureMember" ) );
 
 1524               getFeatureInfoElement.appendChild( layerElement );
 
 1527             ( void )featureInfoFromRasterLayer( rasterLayer, mapSettings, &layerInfoPoint, result, layerElement, version );
 
 1535         param.mValue = queryLayer;
 
 1539       else if ( ( validLayer && !queryableLayer ) || ( !validLayer && mContext.
isValidGroup( queryLayer ) ) )
 
 1542         param.mValue = queryLayer;
 
 1544         bool hasGroupAndQueryable { 
false };
 
 1549           for ( 
const QString &ql : constNicks )
 
 1553               const QList<QgsMapLayer *> constLayers { mContext.
layerGroups()[ql] };
 
 1556                 if ( ( ! ml->shortName().isEmpty() &&  ml->shortName() == queryLayer ) || ( ml->name() == queryLayer ) )
 
 1562                   hasGroupAndQueryable = 
true;
 
 1571         if ( ! hasGroupAndQueryable )
 
 1581       if ( infoFormat == QgsWmsParameters::Format::GML )
 
 1583         QDomElement bBoxElem = result.createElement( QStringLiteral( 
"gml:boundedBy" ) );
 
 1584         QDomElement boxElem;
 
 1586         if ( gmlVersion < 3 )
 
 1598           boxElem.setAttribute( QStringLiteral( 
"srsName" ), 
crs.
authid() );
 
 1600         bBoxElem.appendChild( boxElem );
 
 1601         getFeatureInfoElement.insertBefore( bBoxElem, QDomNode() ); 
 
 1605         QDomElement bBoxElem = result.createElement( QStringLiteral( 
"BoundingBox" ) );
 
 1606         bBoxElem.setAttribute( QStringLiteral( 
"CRS" ), mapSettings.destinationCrs().authid() );
 
 1607         bBoxElem.setAttribute( QStringLiteral( 
"minx" ), 
qgsDoubleToString( featuresRect->xMinimum(), 8 ) );
 
 1608         bBoxElem.setAttribute( QStringLiteral( 
"maxx" ), 
qgsDoubleToString( featuresRect->xMaximum(), 8 ) );
 
 1609         bBoxElem.setAttribute( QStringLiteral( 
"miny" ), 
qgsDoubleToString( featuresRect->yMinimum(), 8 ) );
 
 1610         bBoxElem.setAttribute( QStringLiteral( 
"maxy" ), 
qgsDoubleToString( featuresRect->yMaximum(), 8 ) );
 
 1611         getFeatureInfoElement.insertBefore( bBoxElem, QDomNode() ); 
 
 1615     if ( sia2045 && infoFormat == QgsWmsParameters::Format::XML )
 
 1617       convertFeatureInfoToSia2045( result );
 
 1623   bool QgsRenderer::featureInfoFromVectorLayer( 
QgsVectorLayer *layer,
 
 1626       QDomDocument &infoDocument,
 
 1627       QDomElement &layerElement,
 
 1630       const QString &version,
 
 1642     std::unique_ptr<QgsGeometry> layerFilterGeom;
 
 1645       layerFilterGeom.reset( 
new QgsGeometry( *filterGeom ) );
 
 1659       searchRect = featureInfoSearchRect( layer, mapSettings, renderContext, *infoPoint );
 
 1661     else if ( layerFilterGeom )
 
 1663       searchRect = layerFilterGeom->boundingBox();
 
 1665     else if ( !mWmsParameters.
bbox().isEmpty() )
 
 1667       searchRect = layerRect;
 
 1674     int featureCounter = 0;
 
 1693     if ( layerFilterGeom )
 
 1695       fReq.
setFilterExpression( QString( 
"intersects( $geometry, geom_from_wkt('%1') )" ).arg( layerFilterGeom->asWkt() ) );
 
 1700 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
 1701     mContext.accessControl()->filterFeatures( layer, fReq );
 
 1703     QStringList attributes;
 
 1708     attributes = mContext.accessControl()->layerAttributes( layer, attributes );
 
 1713     std::unique_ptr< QgsFeatureRenderer > r2( layer->
renderer() ? layer->
renderer()->
clone() : 
nullptr );
 
 1716       r2->startRender( renderContext, layer->
fields() );
 
 1719     bool featureBBoxInitialized = 
false;
 
 1728       if ( featureCounter > nFeatures )
 
 1743         bool render = r2->willRenderFeature( feature, renderContext );
 
 1756           if ( !featureBBoxInitialized && featureBBox->
isEmpty() )
 
 1759             featureBBoxInitialized = 
true;
 
 1774       if ( mWmsParameters.
infoFormat() == QgsWmsParameters::Format::GML )
 
 1779         QDomElement elem = createFeatureGML(
 
 1781 #ifdef HAVE_SERVER_PYTHON_PLUGINS
 
 1785         QDomElement featureMemberElem = infoDocument.createElement( QStringLiteral( 
"gml:featureMember" ) );
 
 1786         featureMemberElem.appendChild( elem );
 
 1787         layerElement.appendChild( featureMemberElem );
 
 1792         QDomElement featureElement = infoDocument.createElement( QStringLiteral( 
"Feature" ) );
 
 1794         layerElement.appendChild( featureElement );
 
 1800           writeAttributesTabLayout( editConfig, layer, fields, featureAttributes, infoDocument, featureElement, renderContext
 
 1801 #ifdef HAVE_SERVER_PYTHON_PLUGINS
 
 1808           for ( 
int i = 0; i < featureAttributes.count(); ++i )
 
 1810             writeVectorLayerAttribute( i, layer, fields, featureAttributes, infoDocument, featureElement, renderContext
 
 1811 #ifdef HAVE_SERVER_PYTHON_PLUGINS
 
 1820         if ( !mapTip.isEmpty() && mWmsParameters.
withMapTip() )
 
 1822           QDomElement maptipElem = infoDocument.createElement( QStringLiteral( 
"Attribute" ) );
 
 1823           maptipElem.setAttribute( QStringLiteral( 
"name" ), QStringLiteral( 
"maptip" ) );
 
 1825           featureElement.appendChild( maptipElem );
 
 1832           QDomElement bBoxElem = infoDocument.createElement( QStringLiteral( 
"BoundingBox" ) );
 
 1833           bBoxElem.setAttribute( version == QLatin1String( 
"1.1.1" ) ? 
"SRS" : 
"CRS", 
outputCrs.
authid() );
 
 1838           featureElement.appendChild( bBoxElem );
 
 1854             if ( segmentizeWktGeometry )
 
 1862                   geom.
set( segmentizedGeom );
 
 1866             QDomElement geometryElement = infoDocument.createElement( QStringLiteral( 
"Attribute" ) );
 
 1867             geometryElement.setAttribute( QStringLiteral( 
"name" ), QStringLiteral( 
"geometry" ) );
 
 1868             geometryElement.setAttribute( QStringLiteral( 
"value" ), geom.
asWkt( mContext.
precision() ) );
 
 1869             geometryElement.setAttribute( QStringLiteral( 
"type" ), QStringLiteral( 
"derived" ) );
 
 1870             featureElement.appendChild( geometryElement );
 
 1877       r2->stopRender( renderContext );
 
 1888       QString groupName = container->
name();
 
 1889       QDomElement nameElem;
 
 1891       if ( !groupName.isEmpty() )
 
 1893         nameElem = doc.createElement( groupName );
 
 1894         parentElem.appendChild( nameElem );
 
 1897       const QList<QgsAttributeEditorElement *> children =  container->
children();
 
 1902           writeAttributesTabGroup( child, layer, fields, featureAttributes, doc, nameElem.isNull() ? parentElem : nameElem, renderContext );
 
 1912               writeVectorLayerAttribute( idx, layer, fields, featureAttributes, doc, nameElem.isNull() ? parentElem : nameElem, renderContext, attributes );
 
 1923     if ( !editorContainer )
 
 1928     writeAttributesTabGroup( editorContainer, layer, fields, featureAttributes, doc, featureElem, renderContext, attributes );
 
 1931   void QgsRenderer::writeVectorLayerAttribute( 
int attributeIndex,  
QgsVectorLayer *layer, 
const QgsFields &fields, 
QgsAttributes &featureAttributes, QDomDocument &doc, QDomElement &featureElem, 
QgsRenderContext &renderContext, QStringList *attributes )
 const 
 1933 #ifndef HAVE_SERVER_PYTHON_PLUGINS 
 1934     Q_UNUSED( attributes );
 
 1947 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
 1949     if ( attributes && !attributes->contains( fields.
at( attributeIndex ).
name() ) )
 
 1956     QDomElement attributeElement = doc.createElement( QStringLiteral( 
"Attribute" ) );
 
 1957     attributeElement.setAttribute( QStringLiteral( 
"name" ), attributeName );
 
 1959     attributeElement.setAttribute( QStringLiteral( 
"value" ),
 
 1961                                      replaceValueMapAndRelation(
 
 1962                                        layer, attributeIndex,
 
 1963                                        featureAttributes[attributeIndex] ),
 
 1966     featureElem.appendChild( attributeElement );
 
 1969   bool QgsRenderer::featureInfoFromRasterLayer( 
QgsRasterLayer *layer,
 
 1972       QDomDocument &infoDocument,
 
 1973       QDomElement &layerElement,
 
 1974       const QString &version )
 const 
 1993       ? QgsRaster::IdentifyFormat::IdentifyFormatFeature
 
 1994       : QgsRaster::IdentifyFormat::IdentifyFormatValue );
 
 2006                                       .arg( layer->
name() ) );
 
 2015     if ( !identifyResult.
isValid() )
 
 2018     QMap<int, QVariant> attributes = identifyResult.
results();
 
 2020     if ( mWmsParameters.
infoFormat() == QgsWmsParameters::Format::GML )
 
 2032         for ( 
auto it = attributes.constBegin(); it != attributes.constEnd(); ++it )
 
 2035           feature.
setAttribute( index++, QString::number( it.value().toDouble() ) );
 
 2038         QDomElement elem = createFeatureGML(
 
 2039                              &feature, 
nullptr, infoDocument, layerCrs, mapSettings, 
typeName, 
false, gmlVersion, 
nullptr );
 
 2040         layerElement.appendChild( elem );
 
 2044         const auto values = identifyResult.
results();
 
 2045         for ( 
auto it = values.constBegin(); it != values.constEnd(); ++it )
 
 2047           QVariant value = it.value();
 
 2048           if ( value.type() == QVariant::Bool && !value.toBool() )
 
 2054           if ( value.type() == QVariant::String )
 
 2065             for ( 
const QgsFeature &feature : storeFeatures )
 
 2067               QDomElement elem = createFeatureGML(
 
 2068                                    &feature, 
nullptr, infoDocument, layerCrs, mapSettings, 
typeName, 
false, gmlVersion, 
nullptr );
 
 2069               layerElement.appendChild( elem );
 
 2079         for ( 
auto it = attributes.constBegin(); it != attributes.constEnd(); ++it )
 
 2081           QDomElement attributeElement = infoDocument.createElement( QStringLiteral( 
"Attribute" ) );
 
 2082           attributeElement.setAttribute( QStringLiteral( 
"name" ), layer->
bandName( it.key() ) );
 
 2085           if ( ! it.value().isNull() )
 
 2087             value  = QString::number( it.value().toDouble() );
 
 2090           attributeElement.setAttribute( QStringLiteral( 
"value" ), value );
 
 2091           layerElement.appendChild( attributeElement );
 
 2096         const auto values = identifyResult.
results();
 
 2097         for ( 
auto it = values.constBegin(); it != values.constEnd(); ++it )
 
 2099           QVariant value = it.value();
 
 2100           if ( value.type() == QVariant::Bool && !value.toBool() )
 
 2106           if ( value.type() == QVariant::String )
 
 2116             for ( 
const QgsFeature &feature : storeFeatures )
 
 2118               for ( 
const auto &fld : feature.
fields() )
 
 2120                 const auto val { feature.
attribute( fld.name() )};
 
 2121                 if ( val.isValid() )
 
 2123                   QDomElement attributeElement = infoDocument.createElement( QStringLiteral( 
"Attribute" ) );
 
 2124                   attributeElement.setAttribute( QStringLiteral( 
"name" ), fld.name() );
 
 2125                   attributeElement.setAttribute( QStringLiteral( 
"value" ), val.toString() );
 
 2126                   layerElement.appendChild( attributeElement );
 
 2137   bool QgsRenderer::testFilterStringSafety( 
const QString &filter )
 const 
 2140     if ( filter.contains( QLatin1String( 
";" ) ) )
 
 2145 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
 2146     QStringList tokens = filter.split( 
' ', QString::SkipEmptyParts );
 
 2148     QStringList tokens = filter.split( 
' ', Qt::SkipEmptyParts );
 
 2150     groupStringList( tokens, QStringLiteral( 
"'" ) );
 
 2151     groupStringList( tokens, QStringLiteral( 
"\"" ) );
 
 2153     for ( 
auto tokenIt = tokens.constBegin() ; tokenIt != tokens.constEnd(); ++tokenIt )
 
 2156       if ( tokenIt->compare( QLatin1String( 
"," ) ) == 0
 
 2157            || tokenIt->compare( QLatin1String( 
"(" ) ) == 0
 
 2158            || tokenIt->compare( QLatin1String( 
")" ) ) == 0
 
 2159            || tokenIt->compare( QLatin1String( 
"=" ) ) == 0
 
 2160            || tokenIt->compare( QLatin1String( 
"!=" ) ) == 0
 
 2161            || tokenIt->compare( QLatin1String( 
"<" ) ) == 0
 
 2162            || tokenIt->compare( QLatin1String( 
"<=" ) ) == 0
 
 2163            || tokenIt->compare( QLatin1String( 
">" ) ) == 0
 
 2164            || tokenIt->compare( QLatin1String( 
">=" ) ) == 0
 
 2165            || tokenIt->compare( QLatin1String( 
"%" ) ) == 0
 
 2166            || tokenIt->compare( QLatin1String( 
"IS" ), Qt::CaseInsensitive ) == 0
 
 2167            || tokenIt->compare( QLatin1String( 
"NOT" ), Qt::CaseInsensitive ) == 0
 
 2168            || tokenIt->compare( QLatin1String( 
"NULL" ), Qt::CaseInsensitive ) == 0
 
 2169            || tokenIt->compare( QLatin1String( 
"AND" ), Qt::CaseInsensitive ) == 0
 
 2170            || tokenIt->compare( QLatin1String( 
"OR" ), Qt::CaseInsensitive ) == 0
 
 2171            || tokenIt->compare( QLatin1String( 
"IN" ), Qt::CaseInsensitive ) == 0
 
 2172            || tokenIt->compare( QLatin1String( 
"LIKE" ), Qt::CaseInsensitive ) == 0
 
 2173            || tokenIt->compare( QLatin1String( 
"ILIKE" ), Qt::CaseInsensitive ) == 0
 
 2174            || tokenIt->compare( QLatin1String( 
"DMETAPHONE" ), Qt::CaseInsensitive ) == 0
 
 2175            || tokenIt->compare( QLatin1String( 
"SOUNDEX" ), Qt::CaseInsensitive ) == 0 )
 
 2182       tokenIt->toDouble( &isNumeric );
 
 2191       if ( *tokenIt == QLatin1String( 
"''" ) )
 
 2197       if ( tokenIt->size() > 2
 
 2198            && ( *tokenIt )[0] == QChar( 
'\'' )
 
 2199            && ( *tokenIt )[tokenIt->size() - 1] == QChar( 
'\'' )
 
 2200            && ( *tokenIt )[1] != QChar( 
'\'' )
 
 2201            && ( *tokenIt )[tokenIt->size() - 2] != QChar( 
'\'' ) )
 
 2207       if ( tokenIt->size() > 2
 
 2208            && ( *tokenIt )[0] == QChar( 
'"' )
 
 2209            && ( *tokenIt )[tokenIt->size() - 1] == QChar( 
'"' )
 
 2210            && ( *tokenIt )[1] != QChar( 
'"' )
 
 2211            && ( *tokenIt )[tokenIt->size() - 2] != QChar( 
'"' ) )
 
 2222   void QgsRenderer::groupStringList( QStringList &list, 
const QString &groupString )
 
 2225     bool groupActive = 
false;
 
 2226     int startGroup = -1;
 
 2227     QString concatString;
 
 2229     for ( 
int i = 0; i < list.size(); ++i )
 
 2231       QString &
str = list[i];
 
 2232       if ( 
str.startsWith( groupString ) )
 
 2236         concatString.clear();
 
 2241         if ( i != startGroup )
 
 2243           concatString.append( 
" " );
 
 2245         concatString.append( 
str );
 
 2248       if ( 
str.endsWith( groupString ) )
 
 2251         groupActive = 
false;
 
 2253         if ( startGroup != -1 )
 
 2255           list[startGroup] = concatString;
 
 2256           for ( 
int j = startGroup + 1; j <= endGroup; ++j )
 
 2258             list.removeAt( startGroup + 1 );
 
 2263         concatString.clear();
 
 2269   void QgsRenderer::convertFeatureInfoToSia2045( QDomDocument &doc )
 const 
 2271     QDomDocument SIAInfoDoc;
 
 2272     QDomElement infoDocElement = doc.documentElement();
 
 2273     QDomElement SIAInfoDocElement = SIAInfoDoc.importNode( infoDocElement, 
false ).toElement();
 
 2274     SIAInfoDoc.appendChild( SIAInfoDocElement );
 
 2276     QString currentAttributeName;
 
 2277     QString currentAttributeValue;
 
 2278     QDomElement currentAttributeElem;
 
 2279     QString currentLayerName;
 
 2280     QDomElement currentLayerElem;
 
 2281     QDomNodeList layerNodeList = infoDocElement.elementsByTagName( QStringLiteral( 
"Layer" ) );
 
 2282     for ( 
int i = 0; i < layerNodeList.size(); ++i )
 
 2284       currentLayerElem = layerNodeList.at( i ).toElement();
 
 2285       currentLayerName = currentLayerElem.attribute( QStringLiteral( 
"name" ) );
 
 2287       QDomElement currentFeatureElem;
 
 2289       QDomNodeList featureList = currentLayerElem.elementsByTagName( QStringLiteral( 
"Feature" ) );
 
 2290       if ( featureList.isEmpty() )
 
 2293         QDomNodeList attributeList = currentLayerElem.elementsByTagName( QStringLiteral( 
"Attribute" ) );
 
 2294         QDomElement rasterLayerElem;
 
 2295         if ( !attributeList.isEmpty() )
 
 2297           rasterLayerElem = SIAInfoDoc.createElement( currentLayerName );
 
 2299         for ( 
int j = 0; j < attributeList.size(); ++j )
 
 2301           currentAttributeElem = attributeList.at( j ).toElement();
 
 2302           currentAttributeName = currentAttributeElem.attribute( QStringLiteral( 
"name" ) );
 
 2303           currentAttributeValue = currentAttributeElem.attribute( QStringLiteral( 
"value" ) );
 
 2304           QDomElement outAttributeElem = SIAInfoDoc.createElement( currentAttributeName );
 
 2305           QDomText outAttributeText = SIAInfoDoc.createTextNode( currentAttributeValue );
 
 2306           outAttributeElem.appendChild( outAttributeText );
 
 2307           rasterLayerElem.appendChild( outAttributeElem );
 
 2309         if ( !attributeList.isEmpty() )
 
 2311           SIAInfoDocElement.appendChild( rasterLayerElem );
 
 2317         QSet<QString> layerPropertyAttributes;
 
 2318         QString currentLayerId = currentLayerElem.attribute( QStringLiteral( 
"id" ) );
 
 2319         if ( !currentLayerId.isEmpty() )
 
 2324             QString WMSPropertyAttributesString = currentLayer->
customProperty( QStringLiteral( 
"WMSPropertyAttributes" ) ).toString();
 
 2325             if ( !WMSPropertyAttributesString.isEmpty() )
 
 2327               QStringList propertyList = WMSPropertyAttributesString.split( QStringLiteral( 
"//" ) );
 
 2328               for ( 
auto propertyIt = propertyList.constBegin() ; propertyIt != propertyList.constEnd(); ++propertyIt )
 
 2330                 layerPropertyAttributes.insert( *propertyIt );
 
 2336         QDomElement propertyRefChild; 
 
 2337         for ( 
int j = 0; j < featureList.size(); ++j )
 
 2339           QDomElement SIAFeatureElem = SIAInfoDoc.createElement( currentLayerName );
 
 2340           currentFeatureElem = featureList.at( j ).toElement();
 
 2341           QDomNodeList attributeList = currentFeatureElem.elementsByTagName( QStringLiteral( 
"Attribute" ) );
 
 2343           for ( 
int k = 0; k < attributeList.size(); ++k )
 
 2345             currentAttributeElem = attributeList.at( k ).toElement();
 
 2346             currentAttributeName = currentAttributeElem.attribute( QStringLiteral( 
"name" ) );
 
 2347             currentAttributeValue = currentAttributeElem.attribute( QStringLiteral( 
"value" ) );
 
 2348             if ( layerPropertyAttributes.contains( currentAttributeName ) )
 
 2350               QDomElement propertyElem = SIAInfoDoc.createElement( QStringLiteral( 
"property" ) );
 
 2351               QDomElement identifierElem = SIAInfoDoc.createElement( QStringLiteral( 
"identifier" ) );
 
 2352               QDomText identifierText = SIAInfoDoc.createTextNode( currentAttributeName );
 
 2353               identifierElem.appendChild( identifierText );
 
 2354               QDomElement valueElem = SIAInfoDoc.createElement( QStringLiteral( 
"value" ) );
 
 2355               QDomText valueText = SIAInfoDoc.createTextNode( currentAttributeValue );
 
 2356               valueElem.appendChild( valueText );
 
 2357               propertyElem.appendChild( identifierElem );
 
 2358               propertyElem.appendChild( valueElem );
 
 2359               if ( propertyRefChild.isNull() )
 
 2361                 SIAFeatureElem.insertBefore( propertyElem, QDomNode() );
 
 2362                 propertyRefChild = propertyElem;
 
 2366                 SIAFeatureElem.insertAfter( propertyElem, propertyRefChild );
 
 2371               QDomElement SIAAttributeElem = SIAInfoDoc.createElement( currentAttributeName );
 
 2372               QDomText SIAAttributeText = SIAInfoDoc.createTextNode( currentAttributeValue );
 
 2373               SIAAttributeElem.appendChild( SIAAttributeText );
 
 2374               SIAFeatureElem.appendChild( SIAAttributeElem );
 
 2377           SIAInfoDocElement.appendChild( SIAFeatureElem );
 
 2384   QByteArray QgsRenderer::convertFeatureInfoToHtml( 
const QDomDocument &doc )
 const 
 2386     QString featureInfoString;
 
 2389     featureInfoString.append( 
"<HEAD>\n" );
 
 2390     featureInfoString.append( 
"<TITLE> GetFeatureInfo results </TITLE>\n" );
 
 2391     featureInfoString.append( 
"<META http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\n" );
 
 2392     featureInfoString.append( 
"</HEAD>\n" );
 
 2395     featureInfoString.append( 
"<BODY>\n" );
 
 2397     QDomNodeList layerList = doc.elementsByTagName( QStringLiteral( 
"Layer" ) );
 
 2400     for ( 
int i = 0; i < layerList.size(); ++i )
 
 2402       QDomElement layerElem = layerList.at( i ).toElement();
 
 2404       featureInfoString.append( 
"<TABLE border=1 width=100%>\n" );
 
 2405       featureInfoString.append( 
"<TR><TH width=25%>Layer</TH><TD>" + layerElem.attribute( QStringLiteral( 
"name" ) ) + 
"</TD></TR>\n" );
 
 2406       featureInfoString.append( 
"</BR>" );
 
 2409       QDomNodeList featureNodeList = layerElem.elementsByTagName( QStringLiteral( 
"Feature" ) );
 
 2410       QDomElement currentFeatureElement;
 
 2412       if ( !featureNodeList.isEmpty() ) 
 
 2414         for ( 
int j = 0; j < featureNodeList.size(); ++j )
 
 2416           QDomElement featureElement = featureNodeList.at( j ).toElement();
 
 2417           featureInfoString.append( 
"<TABLE border=1 width=100%>\n" );
 
 2418           featureInfoString.append( 
"<TR><TH>Feature</TH><TD>" + featureElement.attribute( QStringLiteral( 
"id" ) ) +
 
 2422           QDomNodeList attributeNodeList = featureElement.elementsByTagName( QStringLiteral( 
"Attribute" ) );
 
 2423           for ( 
int k = 0; k < attributeNodeList.size(); ++k )
 
 2425             QDomElement attributeElement = attributeNodeList.at( k ).toElement();
 
 2426             featureInfoString.append( 
"<TR><TH>" + attributeElement.attribute( QStringLiteral( 
"name" ) ) +
 
 2427                                       "</TH><TD>" + attributeElement.attribute( QStringLiteral( 
"value" ) ) + 
"</TD></TR>\n" );
 
 2430           featureInfoString.append( 
"</TABLE>\n</BR>\n" );
 
 2435         QDomNodeList attributeNodeList = layerElem.elementsByTagName( QStringLiteral( 
"Attribute" ) );
 
 2436         for ( 
int j = 0; j < attributeNodeList.size(); ++j )
 
 2438           QDomElement attributeElement = attributeNodeList.at( j ).toElement();
 
 2439           QString value = attributeElement.attribute( QStringLiteral( 
"value" ) );
 
 2440           if ( value.isEmpty() )
 
 2442             value = QStringLiteral( 
"no data" );
 
 2444           featureInfoString.append( 
"<TR><TH>" + attributeElement.attribute( QStringLiteral( 
"name" ) ) +
 
 2445                                     "</TH><TD>" + value + 
"</TD></TR>\n" );
 
 2449       featureInfoString.append( 
"</TABLE>\n<BR></BR>\n" );
 
 2453     featureInfoString.append( 
"</BODY>\n" );
 
 2455     return featureInfoString.toUtf8();
 
 2458   QByteArray QgsRenderer::convertFeatureInfoToText( 
const QDomDocument &doc )
 const 
 2460     QString featureInfoString;
 
 2463     featureInfoString.append( 
"GetFeatureInfo results\n" );
 
 2464     featureInfoString.append( 
"\n" );
 
 2466     QDomNodeList layerList = doc.elementsByTagName( QStringLiteral( 
"Layer" ) );
 
 2469     for ( 
int i = 0; i < layerList.size(); ++i )
 
 2471       QDomElement layerElem = layerList.at( i ).toElement();
 
 2473       featureInfoString.append( 
"Layer '" + layerElem.attribute( QStringLiteral( 
"name" ) ) + 
"'\n" );
 
 2476       QDomNodeList featureNodeList = layerElem.elementsByTagName( QStringLiteral( 
"Feature" ) );
 
 2477       QDomElement currentFeatureElement;
 
 2479       if ( !featureNodeList.isEmpty() ) 
 
 2481         for ( 
int j = 0; j < featureNodeList.size(); ++j )
 
 2483           QDomElement featureElement = featureNodeList.at( j ).toElement();
 
 2484           featureInfoString.append( 
"Feature " + featureElement.attribute( QStringLiteral( 
"id" ) ) + 
"\n" );
 
 2487           QDomNodeList attributeNodeList = featureElement.elementsByTagName( QStringLiteral( 
"Attribute" ) );
 
 2488           for ( 
int k = 0; k < attributeNodeList.size(); ++k )
 
 2490             QDomElement attributeElement = attributeNodeList.at( k ).toElement();
 
 2491             featureInfoString.append( attributeElement.attribute( QStringLiteral( 
"name" ) ) + 
" = '" +
 
 2492                                       attributeElement.attribute( QStringLiteral( 
"value" ) ) + 
"'\n" );
 
 2498         QDomNodeList attributeNodeList = layerElem.elementsByTagName( QStringLiteral( 
"Attribute" ) );
 
 2499         for ( 
int j = 0; j < attributeNodeList.size(); ++j )
 
 2501           QDomElement attributeElement = attributeNodeList.at( j ).toElement();
 
 2502           QString value = attributeElement.attribute( QStringLiteral( 
"value" ) );
 
 2503           if ( value.isEmpty() )
 
 2505             value = QStringLiteral( 
"no data" );
 
 2507           featureInfoString.append( attributeElement.attribute( QStringLiteral( 
"name" ) ) + 
" = '" +
 
 2512       featureInfoString.append( 
"\n" );
 
 2515     return featureInfoString.toUtf8();
 
 2518   QByteArray QgsRenderer::convertFeatureInfoToJson( 
const QList<QgsMapLayer *> &layers, 
const QDomDocument &doc )
 const 
 2522       { 
"type", 
"FeatureCollection" },
 
 2523       { 
"features", json::array() },
 
 2527     const QDomNodeList layerList = doc.elementsByTagName( QStringLiteral( 
"Layer" ) );
 
 2528     for ( 
int i = 0; i < layerList.size(); ++i )
 
 2530       const QDomElement layerElem = layerList.at( i ).toElement();
 
 2531       const QString layerName = layerElem.attribute( QStringLiteral( 
"name" ) );
 
 2536         if ( mContext.
layerNickname( *l ).compare( layerName ) == 0 )
 
 2552         const QDomNodeList featuresNode = layerElem.elementsByTagName( QStringLiteral( 
"Feature" ) );
 
 2553         if ( featuresNode.isEmpty() )
 
 2556         QMap<QgsFeatureId, QString> fidMap;
 
 2558         for ( 
int j = 0; j < featuresNode.size(); ++j )
 
 2560           const QDomElement featureNode = featuresNode.at( j ).toElement();
 
 2561           const QString fid = featureNode.attribute( QStringLiteral( 
"id" ) );
 
 2564           if ( expression.isEmpty() )
 
 2566             feature = vl->
getFeature( fid.toLongLong() );
 
 2571             request.setFlags( QgsFeatureRequest::Flag::NoGeometry );
 
 2575           fidMap.insert( feature.
id(), fid );
 
 2580             const QDomNodeList attrs = featureNode.elementsByTagName( 
"Attribute" );
 
 2581             for ( 
int k = 0; k < attrs.count(); k++ )
 
 2583               const QDomElement elm = attrs.at( k ).toElement();
 
 2584               if ( elm.attribute( QStringLiteral( 
"name" ) ).compare( 
"geometry" ) == 0 )
 
 2586                 wkt = elm.attribute( 
"value" );
 
 2591             if ( ! wkt.isEmpty() )
 
 2597           features << feature;
 
 2600           if ( !attributes.isEmpty() )
 
 2603           const QDomNodeList attributesNode = featureNode.elementsByTagName( QStringLiteral( 
"Attribute" ) );
 
 2604           for ( 
int k = 0; k < attributesNode.size(); ++k )
 
 2606             const QDomElement attributeElement = attributesNode.at( k ).toElement();
 
 2607             const QString fieldName = attributeElement.
attribute( QStringLiteral( 
"name" ) );
 
 2609             attributes << feature.fieldNameIndex( fieldName );
 
 2615         exporter.setAttributeDisplayName( 
true );
 
 2616         exporter.setAttributes( attributes );
 
 2617         exporter.setIncludeGeometry( withGeometry );
 
 2618         exporter.setTransformGeometries( 
false );
 
 2620         for ( 
const auto &feature : std::as_const( features ) )
 
 2622           const QString 
id = QStringLiteral( 
"%1.%2" ).arg( layerName ).arg( fidMap.value( feature.id() ) );
 
 2623           json[
"features"].push_back( exporter.exportFeatureToJsonObject( feature, QVariantMap(), 
id ) );
 
 2628         auto properties = json::object();
 
 2629         const QDomNodeList attributesNode = layerElem.elementsByTagName( QStringLiteral( 
"Attribute" ) );
 
 2630         for ( 
int j = 0; j < attributesNode.size(); ++j )
 
 2632           const QDomElement attrElmt = attributesNode.at( j ).toElement();
 
 2633           const QString name = attrElmt.attribute( QStringLiteral( 
"name" ) );
 
 2635           QString value = attrElmt.attribute( QStringLiteral( 
"value" ) );
 
 2636           if ( value.isEmpty() )
 
 2638             value = QStringLiteral( 
"null" );
 
 2641           properties[name.toStdString()] = value.toStdString();
 
 2644         json[
"features"].push_back(
 
 2646           {
"type", 
"Feature" },
 
 2647           {
"id", layerName.toStdString() },
 
 2648           {
"properties", properties }
 
 2654     return QByteArray::fromStdString( json.dump( 2 ) );
 
 2656     return QByteArray::fromStdString( json.dump() );
 
 2660   QDomElement QgsRenderer::createFeatureGML(
 
 2669     QStringList *attributes )
 const 
 2672     QDomElement typeNameElement = doc.createElement( 
"qgs:" + 
typeName  );
 
 2679     typeNameElement.setAttribute( QStringLiteral( 
"fid" ), QStringLiteral( 
"%1.%2" ).arg( 
typeName, fid ) );
 
 2682     if ( layer && layer->
crs() != 
crs )
 
 2715       QDomElement bbElem = doc.createElement( QStringLiteral( 
"gml:boundedBy" ) );
 
 2716       QDomElement boxElem;
 
 2728         boxElem.setAttribute( QStringLiteral( 
"srsName" ), 
crs.
authid() );
 
 2730       bbElem.appendChild( boxElem );
 
 2731       typeNameElement.appendChild( bbElem );
 
 2743       QDomElement geomElem = doc.createElement( QStringLiteral( 
"qgs:geometry" ) );
 
 2744       QDomElement gmlElem;
 
 2754       if ( !gmlElem.isNull() )
 
 2758           gmlElem.setAttribute( QStringLiteral( 
"srsName" ), 
crs.
authid() );
 
 2760         geomElem.appendChild( gmlElem );
 
 2761         typeNameElement.appendChild( geomElem );
 
 2768     for ( 
int i = 0; i < fields.
count(); ++i )
 
 2770       QString attributeName = fields.
at( i ).
name();
 
 2777       if ( attributes && !attributes->contains( attributeName ) )
 
 2782       QDomElement fieldElem = doc.createElement( 
"qgs:" + attributeName.replace( 
' ', 
'_' ) );
 
 2783       QString fieldTextString = featureAttributes.at( i ).toString();
 
 2788       QDomText fieldText = doc.createTextNode( fieldTextString );
 
 2789       fieldElem.appendChild( fieldText );
 
 2790       typeNameElement.appendChild( fieldElem );
 
 2798       if ( !mapTip.isEmpty() && mWmsParameters.
withMapTip() )
 
 2801         QDomElement fieldElem = doc.createElement( QStringLiteral( 
"qgs:maptip" ) );
 
 2802         QDomText maptipText = doc.createTextNode( fieldTextString );
 
 2803         fieldElem.appendChild( maptipText );
 
 2804         typeNameElement.appendChild( fieldElem );
 
 2808     return typeNameElement;
 
 2811   QString QgsRenderer::replaceValueMapAndRelation( 
QgsVectorLayer *vl, 
int idx, 
const QVariant &attributeVal )
 
 2815     QString value( fieldFormatter->
representValue( vl, idx, setup.
config(), QVariant(), attributeVal ) );
 
 2817     if ( setup.
config().value( QStringLiteral( 
"AllowMulti" ) ).toBool() && value.startsWith( QLatin1Char( 
'{' ) ) && value.endsWith( QLatin1Char( 
'}' ) ) )
 
 2819       value = value.mid( 1, value.size() - 2 );
 
 2831     double mapUnitTolerance = 0.0;
 
 2841         mapUnitTolerance = mapSettings.
extent().
width() / 400.0;
 
 2853         mapUnitTolerance = mapSettings.
extent().
width() / 200.0;
 
 2865         mapUnitTolerance = mapSettings.
extent().
width() / 100.0;
 
 2869     QgsRectangle mapRectangle( infoPoint.
x() - mapUnitTolerance, infoPoint.
y() - mapUnitTolerance,
 
 2870                                infoPoint.
x() + mapUnitTolerance, infoPoint.
y() + mapUnitTolerance );
 
 2874   QList<QgsMapLayer *> QgsRenderer::highlightLayers( QList<QgsWmsParametersHighlightLayer> params )
 
 2876     QList<QgsMapLayer *> highlightLayers;
 
 2879     QString 
crs = mWmsParameters.
crs();
 
 2880     for ( 
const QgsWmsParametersHighlightLayer ¶m : params )
 
 2883       QDomDocument sldDoc;
 
 2887       if ( !sldDoc.setContent( param.mSld, 
true, &errorMsg, &errorLine, &errorColumn ) )
 
 2894                                    QStringLiteral( 
"Server" ), Qgis::MessageLevel::Warning );
 
 2899       std::unique_ptr<QgsFeatureRenderer> renderer;
 
 2900       QDomElement el = sldDoc.documentElement();
 
 2911       if ( ! param.mLabel.isEmpty() )
 
 2913         url += 
"&field=label:string";
 
 2918       std::unique_ptr<QgsVectorLayer> layer = std::make_unique<QgsVectorLayer>( url, param.mName, QLatin1String( 
"memory" ), options );
 
 2919       if ( !layer->isValid() )
 
 2926       if ( ! param.mLabel.isEmpty() )
 
 2928         fet.setAttribute( 0, param.mLabel );
 
 2936         palSettings.
dist = param.mLabelDistance;
 
 2945         switch ( param.mGeom.type() )
 
 2958               QVariant x( pt.
x() );
 
 2961               QVariant y( pt.
y() );
 
 2978             QVariant x( pt.
x() );
 
 2982             QVariant y( pt.
y() );
 
 2986             QVariant hali( 
"Center" );
 
 2990             QVariant vali( 
"Half" );
 
 3005         if ( param.mColor.isValid() )
 
 3007           textFormat.
setColor( param.mColor );
 
 3010         if ( param.mSize > 0 )
 
 3012           textFormat.
setSize( param.mSize );
 
 3020         if ( ! param.mFont.isEmpty() )
 
 3022           textFormat.
setFont( param.mFont );
 
 3025         if ( param.mBufferColor.isValid() )
 
 3027           bufferSettings.
setColor( param.mBufferColor );
 
 3030         if ( param.mBufferSize > 0 )
 
 3033           bufferSettings.
setSize( 
static_cast<double>( param.mBufferSize ) );
 
 3040         layer->setLabeling( simpleLabeling );
 
 3041         layer->setLabelsEnabled( 
true );
 
 3043       fet.setGeometry( param.mGeom );
 
 3047       layer->setRenderer( renderer.release() );
 
 3050       if ( layer->isValid() )
 
 3052         highlightLayers.append( layer.release() );
 
 3056     mTemporaryLayers.append( highlightLayers );
 
 3057     return highlightLayers;
 
 3060   void QgsRenderer::removeTemporaryLayers()
 
 3062     qDeleteAll( mTemporaryLayers );
 
 3063     mTemporaryLayers.clear();
 
 3066   QPainter *QgsRenderer::layersRendering( 
const QgsMapSettings &mapSettings, QImage &image )
 const 
 3068     QPainter *painter = 
nullptr;
 
 3072 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
 3073     mContext.accessControl()->resolveFilterFeatures( mapSettings.
layers() );
 
 3077     renderJob.render( mapSettings, &image );
 
 3078     painter = renderJob.takePainter();
 
 3080     if ( !renderJob.errors().isEmpty() )
 
 3082       QString layerWMSName;
 
 3083       QString firstErrorLayerId = renderJob.errors().at( 0 ).layerID;
 
 3090       throw QgsException( QStringLiteral( 
"Map rendering error in layer '%1'" ).arg( layerWMSName ) );
 
 3096   void QgsRenderer::setLayerOpacity( 
QgsMapLayer *layer, 
int opacity )
 const 
 3098     if ( opacity >= 0 && opacity <= 255 )
 
 3100       switch ( layer->
type() )
 
 3113           rasterRenderer->
setOpacity( opacity / 255. );
 
 3128   void QgsRenderer::setLayerFilter( 
QgsMapLayer *layer, 
const QList<QgsWmsParametersFilter> &filters )
 
 3132       QgsVectorLayer *filteredLayer = qobject_cast<QgsVectorLayer *>( layer );
 
 3133       QStringList expList;
 
 3134       for ( 
const QgsWmsParametersFilter &filter : filters )
 
 3139           QDomDocument filterXml;
 
 3141           if ( !filterXml.setContent( filter.mFilter, 
true, &errorMsg ) )
 
 3144                                           QStringLiteral( 
"Filter string rejected. Error message: %1. The XML string was: %2" ).arg( errorMsg, filter.mFilter ) );
 
 3146           QDomElement filterElem = filterXml.firstChildElement();
 
 3151             expList << filterExp->dump();
 
 3157           if ( !testFilterStringSafety( filter.mFilter ) )
 
 3159             throw QgsSecurityException( QStringLiteral( 
"The filter string %1" 
 3160                                         " has been rejected because of security reasons." 
 3161                                         " Note: Text strings have to be enclosed in single or double quotes." 
 3162                                         " A space between each word / special character is mandatory." 
 3163                                         " Allowed Keywords and special characters are " 
 3164                                         " IS,NOT,NULL,AND,OR,IN,=,<,>=,>,>=,!=,',',(,),DMETAPHONE,SOUNDEX." 
 3165                                         " Not allowed are semicolons in the filter expression." ).arg(
 
 3169           QString newSubsetString = filter.mFilter;
 
 3172             newSubsetString.prepend( 
") AND (" );
 
 3173             newSubsetString.append( 
")" );
 
 3174             newSubsetString.prepend( filteredLayer->
subsetString() );
 
 3175             newSubsetString.prepend( 
"(" );
 
 3179             QgsMessageLog::logMessage( QStringLiteral( 
"Error setting subset string from filter for layer %1, filter: %2" ).arg( layer->
name(), newSubsetString ),
 
 3180                                        QStringLiteral( 
"Server" ),
 
 3181                                        Qgis::MessageLevel::Warning );
 
 3183                                           QStringLiteral( 
"Filter not valid for layer %1: check the filter syntax and the field names." ).arg( layer->
name() ) );
 
 3189       expList.append( dimensionFilter( filteredLayer ) );
 
 3193       if ( expList.size() == 1 )
 
 3197       else if ( expList.size() > 1 )
 
 3199         exp = QStringLiteral( 
"( %1 )" ).arg( expList.join( QLatin1String( 
" ) AND ( " ) ) );
 
 3201       if ( !exp.isEmpty() )
 
 3203         std::unique_ptr<QgsExpression> expression( 
new QgsExpression( exp ) );
 
 3206           mFeatureFilter.
setFilter( filteredLayer, *expression );
 
 3212   QStringList QgsRenderer::dimensionFilter( 
QgsVectorLayer *layer )
 const 
 3214     QStringList expList;
 
 3217     const QList<QgsMapLayerServerProperties::WmsDimensionInfo> wmsDims = serverProperties->
wmsDimensions();
 
 3218     if ( wmsDims.isEmpty() )
 
 3233       if ( fieldIndex == -1 )
 
 3238       int endFieldIndex = -1;
 
 3239       if ( !dim.endFieldName.isEmpty() )
 
 3241         endFieldIndex = layer->
fields().
indexOf( dim.endFieldName );
 
 3242         if ( endFieldIndex == -1 )
 
 3248       if ( !dimParamValues.contains( dim.name.toUpper() ) )
 
 3258           defValue = dim.referenceValue;
 
 3263           QSet<QVariant> uniqueValues = layer->
uniqueValues( fieldIndex );
 
 3264           if ( endFieldIndex != -1 )
 
 3266             uniqueValues.unite( layer->
uniqueValues( endFieldIndex ) );
 
 3269           QList<QVariant> values = qgis::setToList( uniqueValues );
 
 3270           std::sort( values.begin(), values.end() );
 
 3273             defValue = values.first();
 
 3277             defValue = values.last();
 
 3281         if ( endFieldIndex == -1 )
 
 3287           QStringList expElems;
 
 3292           expList << expElems.join( 
' ' );
 
 3300         QString dimParamValue = dimParamValues[dim.name.toUpper()];
 
 3302         QStringList dimExplist;
 
 3304         QStringList dimValues = dimParamValue.split( 
',' );
 
 3305         for ( 
int i = 0; i < dimValues.size(); ++i )
 
 3307           QString dimValue = dimValues[i];
 
 3309           if ( dimValue.size() > 1 )
 
 3311             dimValue = dimValue.trimmed();
 
 3314           if ( dimValue.contains( 
'/' ) )
 
 3316             QStringList rangeValues = dimValue.split( 
'/' );
 
 3318             if ( rangeValues.size() != 2 )
 
 3323             QVariant rangeMin = QVariant( rangeValues[0] );
 
 3324             QVariant rangeMax = QVariant( rangeValues[1] );
 
 3335             QStringList expElems;
 
 3336             if ( endFieldIndex == -1 )
 
 3356                        << QStringLiteral( 
")" );
 
 3358             dimExplist << expElems.join( 
' ' );
 
 3362             QVariant dimVariant = QVariant( dimValue );
 
 3368             if ( endFieldIndex == -1 )
 
 3377               QStringList expElems;
 
 3382               dimExplist << expElems.join( 
' ' );
 
 3387         if ( dimExplist.size() == 1 )
 
 3389           expList << dimExplist;
 
 3391         else if ( dimExplist.size() > 1 )
 
 3393           expList << QStringLiteral( 
"( %1 )" ).arg( dimExplist.join( QLatin1String( 
" ) OR ( " ) ) );
 
 3400   void QgsRenderer::setLayerSelection( 
QgsMapLayer *layer, 
const QStringList &fids )
 const 
 3410       if ( selectedIds.empty() )
 
 3421   void QgsRenderer::setLayerAccessControlFilter( 
QgsMapLayer *layer )
 const 
 3423 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
 3441   void QgsRenderer::annotationsRendering( QPainter *painter, 
const QgsMapSettings &mapSettings )
 const 
 3444     const QList< QgsAnnotation * > annotations = annotationManager->
annotations();
 
 3450       if ( !annotation || !annotation->isVisible() )
 
 3456       if ( annotation->hasFixedMapPosition() )
 
 3458         QgsPointXY mapPos = annotation->mapPosition();
 
 3459         if ( mapSettings.
destinationCrs() != annotation->mapPositionCrs() )
 
 3464             mapPos = coordTransform.transform( mapPos );
 
 3472         offsetX = devicePos.
x();
 
 3473         offsetY = devicePos.
y();
 
 3477         const QPointF relativePos = annotation->relativePosition();
 
 3478         offsetX = mapSettings.
outputSize().width() * relativePos.x();
 
 3479         offsetY = mapSettings.
outputSize().height() * relativePos.y();
 
 3483       painter->translate( offsetX, offsetY );
 
 3484       annotation->render( renderContext );
 
 3489   QImage *QgsRenderer::scaleImage( 
const QImage *image )
 const 
 3494     QImage *scaledImage = 
nullptr;
 
 3495     const int width = mWmsParameters.
widthAsInt();
 
 3497     if ( width != image->width() || height != image->height() )
 
 3499       scaledImage = 
new QImage( image->scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
 
 3505   void QgsRenderer::handlePrintErrors( 
const QgsLayout *layout )
 const 
 3511     QList< QgsLayoutItemMap * > mapList;
 
 3514     QList< QgsLayoutItemMap * >::const_iterator mapIt = mapList.constBegin();
 
 3515     for ( ; mapIt != mapList.constEnd(); ++mapIt )
 
 3517       if ( !( *mapIt )->renderingErrors().isEmpty() )
 
 3529     for ( 
auto layer : layers )
 
 3531       const QgsWmsParametersLayer param = mContext.
parameters( *layer );
 
 3542           setLayerOpacity( layer, param.mOpacity );
 
 3549         setLayerSld( layer, mContext.
sld( *layer ) );
 
 3553         setLayerStyle( layer, mContext.
style( *layer ) );
 
 3558         setLayerOpacity( layer, param.mOpacity );
 
 3563         setLayerFilter( layer, param.mFilter );
 
 3568         setLayerAccessControlFilter( layer );
 
 3573         setLayerSelection( layer, param.mSelection );
 
 3578         updateExtent( layer, *settings );
 
 3588   void QgsRenderer::setLayerStyle( 
QgsMapLayer *layer, 
const QString &style )
 const 
 3590     if ( style.isEmpty() )
 
 3599                                     QStringLiteral( 
"Style '%1' does not exist for layer '%2'" ).arg( style, layer->
name() ) );
 
 3603   void QgsRenderer::setLayerSld( 
QgsMapLayer *layer, 
const QDomElement &sld )
 const 
 3608     QString sldStyleName = 
"__sld_style";
 
 3609     while ( styles.contains( sldStyleName ) )
 
 3611       sldStyleName.append( 
'@' );
 
 3624     if ( !mWmsParameters.
bbox().isEmpty() )
 
 3628       std::unique_ptr<QImage> tmp( createImage( mContext.
mapSize( 
false ) ) );
 
 3629       configureMapSettings( tmp.get(), mapSettings );