30 , mInterface( interface )
37 qDeleteAll( mExternalLayers );
38 mExternalLayers.clear();
45 initRestrictedLayers();
48 searchLayersToRender();
49 removeUnwantedLayers();
51 std::reverse( mLayersToRender.begin(), mLayersToRender.end() );
54bool QgsWmsRenderContext::addLayerToRender(
QgsMapLayer *layer )
56 const bool allowed = checkLayerReadPermissions(
layer );
59 mLayersToRender.append(
layer );
79 return mFlags.testFlag( flag );
89 return *mInterface->serverSettings();
102 if ( mSlds.contains( nickname ) )
104 sld = mSlds[nickname];
115 if ( mStyles.contains( nickname ) )
117 style = mStyles[nickname];
127 const QList<QgsWmsParametersLayer> cLayerParams { mParameters.layersParameters() };
129 for (
const auto ¶ms : std::as_const( cLayerParams ) )
145 if ( !mParameters.imageQuality().isEmpty() )
157 if ( mParameters.tiledAsBool() )
174 if ( mParameters.wmsPrecisionAsInt() > -1 )
176 precision = mParameters.wmsPrecisionAsInt();
189 if ( !mParameters.dpi().isEmpty() )
191 dpm = mParameters.dpiAsDouble() / 0.0254;
200 std::function<QStringList(
const QString &name )> findLeaves = [&](
const QString &name ) -> QStringList {
202 if ( mLayerGroups.contains( name ) )
204 const auto &
layers { mLayerGroups[name] };
205 for (
const auto &l :
layers )
208 if ( checkLayerReadPermissions( l ) )
212 if ( mLayerGroups.contains( nick ) )
214 _result.append( name );
218 _result.append( findLeaves( nick ) );
225 _result.append( name );
230 for (
const auto &name : std::as_const( layerNames ) )
232 result.append( findLeaves( name ) );
239 return mLayersToRender;
244 return mNicknameLayers.values();
249 double denominator = -1;
251 if ( mScaleDenominator >= 0 )
253 denominator = mScaleDenominator;
257 denominator = mParameters.scaleAsDouble();
266 removeUnwantedLayers();
273 if ( mFlags &
UpdateExtent && !mParameters.bbox().isEmpty() )
283 QString name =
layer.serverProperties()->shortName();
286 return l->id() == layer.id();
288 == mExternalLayers.cend() )
292 else if ( name.isEmpty() )
304 for (
auto layer : mLayersToRender )
318 return layer( nickname );
323 return mLayerGroups.value( nickname );
328 return mLayerGroups.contains( name );
331void QgsWmsRenderContext::initNicknameLayers()
340 const QgsLayerTreeGroup *root = mProject->layerTreeRoot();
342 initLayerGroupsRecursive( root, rootName.isEmpty() ? mProject->title() : rootName );
345void QgsWmsRenderContext::initLayerGroupsRecursive(
const QgsLayerTreeGroup *group,
const QString &groupName )
347 if ( !groupName.isEmpty() )
349 QList<QgsMapLayer *> layerGroup;
350 const auto projectLayerTreeRoot { mProject->layerTreeRoot() };
351 const auto treeGroupLayers { group->
findLayers() };
354 if ( !projectLayerTreeRoot->hasCustomLayerOrder() )
356 for (
const auto &tl : treeGroupLayers )
358 layerGroup.push_back( tl->layer() );
363 const auto projectLayerOrder { projectLayerTreeRoot->layerOrder() };
365 QList<QgsMapLayer *> groupLayersList;
366 for (
const auto &tl : treeGroupLayers )
368 groupLayersList << tl->layer();
370 for (
const auto &l : projectLayerOrder )
372 if ( groupLayersList.contains( l ) )
374 layerGroup.push_back( l );
379 if ( !layerGroup.empty() )
381 mLayerGroups[groupName] = layerGroup;
385 for (
const QgsLayerTreeNode *child : group->
children() )
389 auto group =
static_cast<const QgsLayerTreeGroup *
>( child );
392 if ( name.isEmpty() )
393 name = child->name();
395 initLayerGroupsRecursive( group, name );
400void QgsWmsRenderContext::initRestrictedLayers()
402 mRestrictedLayers.clear();
408 QStringList restrictedLayersNames;
409 QgsLayerTreeGroup *root = mProject->layerTreeRoot();
411 for (
const QString &l : std::as_const( restricted ) )
413 const QgsLayerTreeGroup *group = root->
findGroup( l );
416 const QList<QgsLayerTreeLayer *> groupLayers = group->
findLayers();
417 for ( QgsLayerTreeLayer *treeLayer : groupLayers )
419 restrictedLayersNames.append( treeLayer->name() );
424 restrictedLayersNames.append( l );
432 if ( restrictedLayersNames.contains(
layer->name() ) )
439void QgsWmsRenderContext::searchLayersToRender()
441 mLayersToRender.clear();
445 if ( !mParameters.sldBody().isEmpty() )
447 searchLayersToRenderSld();
451 searchLayersToRenderStyle();
457 for (
const QString &layerName : queryLayerNames )
459 const QList<QgsMapLayer *>
layers = mNicknameLayers.values( layerName );
460 for ( QgsMapLayer *lyr :
layers )
462 if ( !mLayersToRender.contains( lyr ) )
464 if ( !addLayerToRender( lyr ) )
466 throw QgsSecurityException( QStringLiteral(
"Your are not allowed to access the layer %1" ).arg( lyr->name() ) );
476 for (
const QString &layerName : queryLayerNames )
478 const QList<QgsMapLayer *>
layers = mNicknameLayers.values( layerName );
479 for ( QgsMapLayer *lyr :
layers )
481 if ( !mLayersToRender.contains( lyr ) )
483 if ( !addLayerToRender( lyr ) )
485 throw QgsSecurityException( QStringLiteral(
"Your are not allowed to access the layer %1" ).arg( lyr->name() ) );
493void QgsWmsRenderContext::searchLayersToRenderSld()
495 const QString
sld = mParameters.sldBody();
503 ( void ) doc.setContent(
sld,
true );
504 QDomElement docEl = doc.documentElement();
506 QDomElement root = doc.firstChildElement(
"StyledLayerDescriptor" );
507 QDomElement namedElem = root.firstChildElement(
"NamedLayer" );
509 if ( docEl.isNull() )
514 QDomNodeList named = docEl.elementsByTagName(
"NamedLayer" );
515 for (
int i = 0; i < named.size(); ++i )
517 QDomNodeList names = named.item( i ).toElement().elementsByTagName(
"Name" );
518 if ( !names.isEmpty() )
520 QString lname = names.item( 0 ).toElement().text();
521 if ( mNicknameLayers.contains( lname ) )
523 mSlds[lname] = namedElem;
524 for (
const auto layer : mNicknameLayers.values( lname ) )
526 if ( !addLayerToRender(
layer ) )
528 throw QgsSecurityException( QStringLiteral(
"Your are not allowed to access the layer %1" ).arg(
layer->name() ) );
532 else if ( mLayerGroups.contains( lname ) )
537 param.mValue = lname;
541 bool layerAdded =
false;
542 for ( QgsMapLayer *
layer : mLayerGroups[lname] )
545 if ( checkLayerReadPermissions(
layer ) )
548 mSlds[name] = namedElem;
549 mLayersToRender.insert( 0,
layer );
558 param.mValue = lname;
565 param.mValue = lname;
572void QgsWmsRenderContext::searchLayersToRenderStyle()
574 for (
const QgsWmsParametersLayer ¶m : mParameters.layersParameters() )
576 const QString nickname = param.mNickname;
577 const QString
style = param.mStyle;
581 std::unique_ptr<QgsMapLayer>
layer = std::make_unique<QgsRasterLayer>( param.mExternalUri, param.mNickname, QStringLiteral(
"wms" ) );
583 if (
layer->isValid() )
586 mExternalLayers.append(
layer.release() );
587 auto lyr = mExternalLayers.last();
588 if ( !addLayerToRender( lyr ) )
590 throw QgsSecurityException( QStringLiteral(
"Your are not allowed to access the layer %1" ).arg( lyr->name() ) );
594 else if ( mNicknameLayers.contains( nickname ) )
596 if ( !
style.isEmpty() )
598 mStyles[nickname] =
style;
601 for (
const auto layer : mNicknameLayers.values( nickname ) )
603 if ( !addLayerToRender(
layer ) )
605 throw QgsSecurityException( QStringLiteral(
"Your are not allowed to access the layer %1" ).arg(
layer->name() ) );
609 else if ( mLayerGroups.contains( nickname ) )
614 param.mValue = nickname;
619 for ( QgsMapLayer *
layer : mLayerGroups[nickname] )
622 if ( !
style.isEmpty() )
624 mStyles[nickname] =
style;
629 bool layerAdded =
false;
632 for (
const auto layer : mNicknameLayers.values( name ) )
634 if ( addLayerToRender(
layer ) )
645 param.mValue = nickname;
652 param.mValue = nickname;
658bool QgsWmsRenderContext::layerScaleVisibility(
const QString &name )
const
660 bool visible =
false;
662 if ( !mNicknameLayers.contains( name ) )
667 const QList<QgsMapLayer *>
layers = mNicknameLayers.values( name );
670 bool scaleBasedVisibility =
layer->hasScaleBasedVisibility();
671 bool useScaleConstraint = (
scaleDenominator() > 0 && scaleBasedVisibility );
689 int width = mParameters.widthAsInt();
694 width = mParameters.srcWidthAsInt();
702 int height = mParameters.heightAsInt();
707 height = mParameters.srcHeightAsInt();
720 if ( width <= 0 || height <= 0 )
729 if ( wmsMaxWidthEnv != -1 && wmsMaxWidthProj != -1 )
732 wmsMaxWidth = std::min( wmsMaxWidthProj, wmsMaxWidthEnv );
737 wmsMaxWidth = std::max( wmsMaxWidthProj, wmsMaxWidthEnv );
740 if ( wmsMaxWidth != -1 && width > wmsMaxWidth )
749 if ( wmsMaxHeightEnv != -1 && wmsMaxHeightProj != -1 )
752 wmsMaxHeight = std::min( wmsMaxHeightProj, wmsMaxHeightEnv );
757 wmsMaxHeight = std::max( wmsMaxHeightProj, wmsMaxHeightEnv );
760 if ( wmsMaxHeight != -1 && height > wmsMaxHeight )
774 switch ( mParameters.format() )
782 if ( width > ( std::numeric_limits<int>::max() - 31 ) / depth )
785 const int bytes_per_line = ( ( width * depth + 31 ) >> 5 ) << 2;
787 if ( std::numeric_limits<int>::max() / bytes_per_line < height
788 || std::numeric_limits<int>::max() /
sizeof( uchar * ) <
static_cast<uint
>( height ) )
801 const QgsRectangle extent = mParameters.bboxAsRectangle();
802 if ( !mParameters.bbox().isEmpty() && extent.
isEmpty() )
826 if ( !mParameters.bbox().isEmpty() && extent.
isEmpty() )
831 QString crs = mParameters.crs();
832 if ( crs.compare(
"CRS:84", Qt::CaseInsensitive ) == 0 )
834 crs = QString(
"EPSG:4326" );
844 if ( !extent.
isEmpty() && height > 0 && width > 0 )
846 const double mapRatio = extent.
width() / extent.
height();
847 const double imageRatio =
static_cast<double>( width ) /
static_cast<double>( height );
851 const double cellsize = ( extent.
width() /
static_cast<double>( width ) ) * 0.5 + ( extent.
height() /
static_cast<double>( height ) ) * 0.5;
852 width = extent.
width() / cellsize;
853 height = extent.
height() / cellsize;
862 else if ( height <= 0 )
867 return QSize( width, height );
870void QgsWmsRenderContext::removeUnwantedLayers()
872 QList<QgsMapLayer *>
layers;
880 if ( !layerScaleVisibility( nickname ) )
883 if ( mRestrictedLayers.contains( nickname ) )
894 if ( !wfsLayers.contains(
layer->
id() ) )
909 for (
const auto &
layer : mExternalLayers )
918bool QgsWmsRenderContext::checkLayerReadPermissions(
QgsMapLayer *layer )
const
920#ifdef HAVE_SERVER_PYTHON_PLUGINS
921 if ( !accessControl()->layerReadPermission(
layer ) )
923 QString msg = QStringLiteral(
"Checking forbidden access for layer: %1" ).arg(
layer->
name() );
932#ifdef HAVE_SERVER_PYTHON_PLUGINS
933QgsAccessControl *QgsWmsRenderContext::accessControl()
const
935 return mInterface->accessControls();
941 mSocketFeedback = feedback;
946 return mSocketFeedback;
@ Info
Information message.
Represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool hasAxisInverted() const
Returns whether the axis order is inverted for the CRS compared to the order east/north (longitude/la...
Base class for feedback objects to be used for cancellation of something running in a worker thread.
QgsLayerTreeGroup * findGroup(const QString &name)
Find group node with specified name.
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the layer tree group.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
@ NodeGroup
Container of other groups and layers.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
Base class for all map layer types.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Describes the version of a project.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
A rectangle specified with double values.
void invert()
Swap x/y coordinates in the rectangle.
Defines interfaces exposed by QGIS Server and made available to plugins.
static int wmsTileBuffer(const QgsProject &project)
Returns the tile buffer in pixels for WMS images defined in a QGIS project.
static QString wmsRootName(const QgsProject &project)
Returns the WMS root layer name defined in a QGIS project.
static bool wmsSkipNameForGroup(const QgsProject &project)
Returns if name attribute should be skipped for groups in WMS capabilities document.
static int wmsFeatureInfoPrecision(const QgsProject &project)
Returns the geometry precision for GetFeatureInfo request.
static bool wmsUseLayerIds(const QgsProject &project)
Returns if layer ids are used as name in WMS.
static QStringList wfsLayerIds(const QgsProject &project)
Returns the Layer ids list defined in a QGIS project as published in WFS.
static bool wmsRenderMapTiles(const QgsProject &project)
Returns true if WMS requests should use the QgsMapSettings::RenderMapTile flag, so that no visible ar...
static QStringList wmsRestrictedLayers(const QgsProject &project)
Returns the restricted layer name list.
static int wmsImageQuality(const QgsProject &project)
Returns the quality for WMS images defined in a QGIS project.
static int wmsMaxWidth(const QgsProject &project)
Returns the maximum width for WMS images defined in a QGIS project.
static int wmsMaxHeight(const QgsProject &project)
Returns the maximum height for WMS images defined in a QGIS project.
Provides a way to retrieve settings by prioritizing according to environment variables,...
int wmsMaxWidth() const
Returns the server-wide max width of a WMS GetMap request.
int wmsMaxHeight() const
Returns the server-wide max height of a WMS GetMap request.
Exception thrown in case of malformed request.
@ QGIS_InvalidParameterValue
Provides an interface to retrieve and manipulate WMS parameters received from the client.
QSize mapSize(bool aspectRatio=true) const
Returns the size (in pixels) of the map to render, according to width and height WMS parameters as we...
bool isExternalLayer(const QString &name) const
Returns true if the layer is an external layer, false otherwise.
bool isValidGroup(const QString &name) const
Returns true if name is a group.
QStringList flattenedQueryLayers(const QStringList &layerNames) const
Returns a list of query layer names where group names are replaced by the names of their layer compon...
QgsFeedback * socketFeedback() const
Returns the response feedback if any.
QgsWmsRenderContext(const QgsProject *project, QgsServerInterface *interface)
Constructor for QgsWmsRenderContext.
QList< QgsMapLayer * > layers() const
Returns a list of all layers read from the project.
void setParameters(const QgsWmsParameters ¶meters)
Sets WMS parameters.
QList< QgsMapLayer * > layersToRender() const
Returns a list of all layers to actually render according to the current configuration.
int mapWidth() const
Returns WIDTH or SRCWIDTH according to UseSrcWidthHeight flag.
QgsMapLayer * layer(const QString &nickname) const
Returns the layer corresponding to the nickname, or a nullptr if not found or if the layer do not nee...
int tileBuffer() const
Returns the tile buffer value to use for rendering according to the current configuration.
bool updateExtent() const
Returns true if the extent has to be updated before the rendering, false otherwise.
const QgsServerSettings & settings() const
Returns settings of the server.
void setFlag(Flag flag, bool on=true)
Sets or unsets a rendering flag according to the on value.
bool isValidWidthHeight() const
Returns true if width and height are valid according to the maximum values defined within the project...
QList< QgsMapLayer * > layersFromGroup(const QString &nickname) const
Returns the group's layers list corresponding to the nickname, or an empty list if not found.
QgsWmsParameters parameters() const
Returns WMS parameters.
void setScaleDenominator(double scaleDenominator)
Sets a custom scale denominator.
QString style(const QgsMapLayer &layer) const
Returns a style's name for a specific layer.
QMap< QString, QList< QgsMapLayer * > > layerGroups() const
Returns a map having layer group names as keys and a list of layers as values.
double mapTileBuffer(int mapWidth) const
Returns the tile buffer in geographical units for the given map width in pixels.
QString layerNickname(const QgsMapLayer &layer) const
Returns the nickname (short name, id or name) of the layer according to the current configuration.
void setSocketFeedback(QgsFeedback *feedback)
Sets the response feedback.
double scaleDenominator() const
Returns the scale denominator to use for rendering according to the current configuration.
qreal dotsPerMm() const
Returns default dots per mm according to the current configuration.
bool testFlag(Flag flag) const
Returns the status of a rendering flag.
QDomElement sld(const QgsMapLayer &layer) const
Returns a SLD document for a specific layer.
bool isValidLayer(const QString &nickname) const
Returns true if the layer has to be rendered, false otherwise.
const QgsProject * project() const
Returns the project.
int precision() const
Returns the precision to use according to the current configuration.
int imageQuality() const
Returns the image quality to use for rendering according to the current configuration.
int mapHeight() const
Returns HEIGHT or SRCHEIGHT according to UseSrcWidthHeight flag.
bool renderMapTiles() const
Returns true if WMS requests should use the QgsMapSettings::RenderMapTile flag, so that no visible ar...
Flag
Available rendering options.
@ AddAllLayers
For GetPrint: add layers from LAYER(S) parameter.
Median cut implementation.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).