QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
qgswmsrendercontext.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgswmsrendercontext.cpp
3 ---------------------
4 begin : March 22, 2019
5 copyright : (C) 2019 by Paul Blottiere
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgswmsrendercontext.h"
19
20#include "qgslayertree.h"
21#include "qgsrasterlayer.h"
24
25#include <QString>
26
27using namespace Qt::StringLiterals;
28
29using namespace QgsWms;
30
31const double OGC_PX_M = 0.00028; // OGC reference pixel size in meter
33 : mProject( project )
34 , mInterface( interface )
35 , mFlags()
36{}
37
39{
40 qDeleteAll( mExternalLayers );
41 mExternalLayers.clear();
42}
43
45{
46 mParameters = parameters;
47
48 initRestrictedLayers();
49 initNicknameLayers();
50
51 searchLayersToRender();
52 removeUnwantedLayers();
53
54 std::reverse( mLayersToRender.begin(), mLayersToRender.end() );
55}
56
57bool QgsWmsRenderContext::addLayerToRender( QgsMapLayer *layer )
58{
59 const bool allowed = checkLayerReadPermissions( layer );
60 if ( allowed )
61 {
62 mLayersToRender.append( layer );
63 }
64 return allowed;
65}
66
67
68void QgsWmsRenderContext::setFlag( const Flag flag, const bool on )
69{
70 if ( on )
71 {
72 mFlags |= flag;
73 }
74 else
75 {
76 mFlags &= ~flag;
77 }
78}
79
81{
82 return mFlags.testFlag( flag );
83}
84
86{
87 return mParameters;
88}
89
91{
92 return *mInterface->serverSettings();
93}
94
96{
97 return mProject;
98}
99
100QDomElement QgsWmsRenderContext::sld( const QgsMapLayer &layer ) const
101{
102 QDomElement sld;
103
104 const QString nickname = layerNickname( layer );
105 if ( mSlds.contains( nickname ) )
106 {
107 sld = mSlds[nickname];
108 }
109
110 return sld;
111}
112
114{
115 QString style;
116
117 const QString nickname = layerNickname( layer );
118 if ( mStyles.contains( nickname ) )
119 {
120 style = mStyles[nickname];
121 }
122
123 return style;
124}
125
127{
129
130 const QList<QgsWmsParametersLayer> cLayerParams { mParameters.layersParameters() };
131
132 for ( const auto &params : std::as_const( cLayerParams ) )
133 {
134 if ( params.mNickname == layerNickname( layer ) )
135 {
136 parameters = params;
137 break;
138 }
139 }
140
141 return parameters;
142}
143
145{
147
148 if ( !mParameters.imageQuality().isEmpty() )
149 {
150 imageQuality = mParameters.imageQualityAsInt();
151 }
152
153 return imageQuality;
154}
155
157{
158 int tileBuffer = 0;
159
160 if ( mParameters.tiledAsBool() )
161 {
163 }
164
165 return tileBuffer;
166}
167
172
174{
176
177 if ( mParameters.wmsPrecisionAsInt() > -1 )
178 {
179 precision = mParameters.wmsPrecisionAsInt();
180 }
181
182 return precision;
183}
184
186{
187 // Apply DPI parameter if present. This is an extension of QGIS Server
188 // compared to WMS 1.3.
189 // Because of backwards compatibility, this parameter is optional
190 qreal dpm = 1 / OGC_PX_M;
191
192 if ( !mParameters.dpi().isEmpty() )
193 {
194 dpm = mParameters.dpiAsDouble() / 0.0254;
195 }
196
197 return dpm / 1000.0;
198}
199
200QStringList QgsWmsRenderContext::flattenedQueryLayers( const QStringList &layerNames ) const
201{
202 QStringList result;
203 std::function<QStringList( const QString &name )> findLeaves = [&]( const QString &name ) -> QStringList {
204 QStringList _result;
205 if ( mLayerGroups.contains( name ) )
206 {
207 const auto &layers { mLayerGroups[name] };
208 for ( const auto &l : layers )
209 {
210 // Only add allowed layers
211 if ( checkLayerReadPermissions( l ) )
212 {
213 const auto nick { layerNickname( *l ) };
214 // This handles the case for root (fake) group
215 if ( mLayerGroups.contains( nick ) )
216 {
217 _result.append( name );
218 }
219 else
220 {
221 _result.append( findLeaves( nick ) );
222 }
223 }
224 }
225 }
226 else
227 {
228 _result.append( name );
229 }
230 return _result;
231 };
232
233 for ( const auto &name : std::as_const( layerNames ) )
234 {
235 result.append( findLeaves( name ) );
236 }
237 return result;
238}
239
240QList<QgsMapLayer *> QgsWmsRenderContext::layersToRender() const
241{
242 return mLayersToRender;
243}
244
245QList<QgsMapLayer *> QgsWmsRenderContext::layers() const
246{
247 return mNicknameLayers.values();
248}
249
251{
252 double denominator = -1;
253
254 if ( mScaleDenominator >= 0 )
255 {
256 denominator = mScaleDenominator;
257 }
258 else if ( mFlags & UseScaleDenominator && !mParameters.scale().isEmpty() )
259 {
260 denominator = mParameters.scaleAsDouble();
261 }
262
263 return denominator;
264}
265
267{
268 mScaleDenominator = scaleDenominator;
269 removeUnwantedLayers();
270}
271
273{
274 bool update = false;
275
276 if ( mFlags & UpdateExtent && !mParameters.bbox().isEmpty() )
277 {
278 update = true;
279 }
280
281 return update;
282}
283
285{
286 QString name = layer.serverProperties()->shortName();
287 // For external layers we cannot use the layer id because it's not known to the client, use layer name instead.
289 && std::find_if( mExternalLayers.cbegin(), mExternalLayers.cend(), [&layer]( const QgsMapLayer *l ) { return l->id() == layer.id(); } ) == mExternalLayers.cend() )
290 {
291 name = layer.id();
292 }
293 else if ( name.isEmpty() )
294 {
295 name = layer.name();
296 }
297
298 return name;
299}
300
301QgsMapLayer *QgsWmsRenderContext::layer( const QString &nickname ) const
302{
303 QgsMapLayer *mlayer = nullptr;
304
305 for ( auto layer : mLayersToRender )
306 {
307 if ( layerNickname( *layer ).compare( nickname ) == 0 )
308 {
309 mlayer = layer;
310 break;
311 }
312 }
313
314 return mlayer;
315}
316
317bool QgsWmsRenderContext::isValidLayer( const QString &nickname ) const
318{
319 return layer( nickname );
320}
321
322QList<QgsMapLayer *> QgsWmsRenderContext::layersFromGroup( const QString &nickname ) const
323{
324 return mLayerGroups.value( nickname );
325}
326
327bool QgsWmsRenderContext::isValidGroup( const QString &name ) const
328{
329 return mLayerGroups.contains( name );
330}
331
332void QgsWmsRenderContext::initNicknameLayers()
333{
334 for ( QgsMapLayer *ml : mProject->mapLayers() )
335 {
336 mNicknameLayers.insert( layerNickname( *ml ), ml );
337 }
338
339 // init groups
340 const QString rootName { QgsServerProjectUtils::wmsRootName( *mProject ) };
341 const QgsLayerTreeGroup *root = mProject->layerTreeRoot();
342
343 initLayerGroupsRecursive( root, rootName.isEmpty() ? mProject->title() : rootName );
344}
345
346void QgsWmsRenderContext::initLayerGroupsRecursive( const QgsLayerTreeGroup *group, const QString &groupName )
347{
348 if ( !groupName.isEmpty() )
349 {
350 QList<QgsMapLayer *> layerGroup;
351 const auto projectLayerTreeRoot { mProject->layerTreeRoot() };
352 const auto treeGroupLayers { group->findLayers() };
353 // Fast track if there is no custom layer order,
354 // otherwise reorder layers.
355 if ( !projectLayerTreeRoot->hasCustomLayerOrder() )
356 {
357 for ( const auto &tl : treeGroupLayers )
358 {
359 layerGroup.push_back( tl->layer() );
360 }
361 }
362 else
363 {
364 const auto projectLayerOrder { projectLayerTreeRoot->layerOrder() };
365 // Flat list containing the layers from the tree nodes
366 QList<QgsMapLayer *> groupLayersList;
367 for ( const auto &tl : treeGroupLayers )
368 {
369 groupLayersList << tl->layer();
370 }
371 for ( const auto &l : projectLayerOrder )
372 {
373 if ( groupLayersList.contains( l ) )
374 {
375 layerGroup.push_back( l );
376 }
377 }
378 }
379
380 if ( !layerGroup.empty() )
381 {
382 mLayerGroups[groupName] = layerGroup;
383 }
384 }
385
386 for ( const QgsLayerTreeNode *child : group->children() )
387 {
388 if ( child->nodeType() == QgsLayerTreeNode::NodeGroup )
389 {
390 auto group = static_cast<const QgsLayerTreeGroup *>( child );
391 QString name = group ? group->serverProperties()->shortName() : QString();
392
393 if ( name.isEmpty() )
394 name = child->name();
395
396 initLayerGroupsRecursive( group, name );
397 }
398 }
399}
400
401void QgsWmsRenderContext::initRestrictedLayers()
402{
403 mRestrictedLayers.clear();
404
405 // get name of restricted layers/groups in project
406 const QStringList restricted = QgsServerProjectUtils::wmsRestrictedLayers( *mProject );
407
408 // extract restricted layers from excluded groups
409 QStringList restrictedLayersNames;
410 QgsLayerTreeGroup *root = mProject->layerTreeRoot();
411
412 for ( const QString &l : std::as_const( restricted ) )
413 {
414 const QgsLayerTreeGroup *group = root->findGroup( l );
415 if ( group )
416 {
417 const QList<QgsLayerTreeLayer *> groupLayers = group->findLayers();
418 for ( QgsLayerTreeLayer *treeLayer : groupLayers )
419 {
420 restrictedLayersNames.append( treeLayer->name() );
421 }
422 }
423 else
424 {
425 restrictedLayersNames.append( l );
426 }
427 }
428
429 // build output with names, ids or short name according to the configuration
430 const QList<QgsLayerTreeLayer *> layers = root->findLayers();
431 for ( QgsLayerTreeLayer *layer : layers )
432 {
433 if ( restrictedLayersNames.contains( layer->name() ) )
434 {
435 mRestrictedLayers.append( layerNickname( *layer->layer() ) );
436 }
437 }
438}
439
440void QgsWmsRenderContext::searchLayersToRender()
441{
442 mLayersToRender.clear();
443 mStyles.clear();
444 mSlds.clear();
445
446 if ( !mParameters.sldBody().isEmpty() )
447 {
448 searchLayersToRenderSld();
449 }
450 else
451 {
452 searchLayersToRenderStyle();
453 }
454
455 if ( mFlags & AddQueryLayers )
456 {
457 const QStringList queryLayerNames = flattenedQueryLayers( mParameters.queryLayersNickname() );
458 for ( const QString &layerName : queryLayerNames )
459 {
460 const QList<QgsMapLayer *> layers = mNicknameLayers.values( layerName );
461 for ( QgsMapLayer *lyr : layers )
462 {
463 if ( !mLayersToRender.contains( lyr ) )
464 {
465 if ( !addLayerToRender( lyr ) )
466 {
467 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
468 }
469 }
470 }
471 }
472 }
473
474 if ( mFlags & AddAllLayers )
475 {
476 const QStringList queryLayerNames = flattenedQueryLayers( mParameters.allLayersNickname() );
477 for ( const QString &layerName : queryLayerNames )
478 {
479 const QList<QgsMapLayer *> layers = mNicknameLayers.values( layerName );
480 for ( QgsMapLayer *lyr : layers )
481 {
482 if ( !mLayersToRender.contains( lyr ) )
483 {
484 if ( !addLayerToRender( lyr ) )
485 {
486 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
487 }
488 }
489 }
490 }
491 }
492}
493
494void QgsWmsRenderContext::searchLayersToRenderSld()
495{
496 const QString sld = mParameters.sldBody();
497
498 if ( sld.isEmpty() )
499 {
500 return;
501 }
502
503 QDomDocument doc;
504 ( void ) doc.setContent( sld, true );
505 QDomElement docEl = doc.documentElement();
506
507 QDomElement root = doc.firstChildElement( "StyledLayerDescriptor" );
508 QDomElement namedElem = root.firstChildElement( "NamedLayer" );
509
510 if ( docEl.isNull() )
511 {
512 return;
513 }
514
515 QDomNodeList named = docEl.elementsByTagName( "NamedLayer" );
516 for ( int i = 0; i < named.size(); ++i )
517 {
518 QDomNodeList names = named.item( i ).toElement().elementsByTagName( "Name" );
519 if ( !names.isEmpty() )
520 {
521 QString lname = names.item( 0 ).toElement().text();
522 if ( mNicknameLayers.contains( lname ) )
523 {
524 mSlds[lname] = namedElem;
525 for ( const auto layer : mNicknameLayers.values( lname ) )
526 {
527 if ( !addLayerToRender( layer ) )
528 {
529 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( layer->name() ) );
530 }
531 }
532 }
533 else if ( mLayerGroups.contains( lname ) )
534 {
536 {
537 QgsWmsParameter param( QgsWmsParameter::LAYER );
538 param.mValue = lname;
539 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
540 }
541
542 bool layerAdded = false;
543 for ( QgsMapLayer *layer : mLayerGroups[lname] )
544 {
545 // Insert only allowed layers
546 if ( checkLayerReadPermissions( layer ) )
547 {
548 const QString name = layerNickname( *layer );
549 mSlds[name] = namedElem;
550 mLayersToRender.insert( 0, layer );
551 layerAdded = true;
552 }
553 }
554 // No layers have been added, consider the group
555 // as non-existent.
556 if ( !layerAdded )
557 {
558 QgsWmsParameter param( QgsWmsParameter::LAYER );
559 param.mValue = lname;
560 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
561 }
562 }
563 else
564 {
565 QgsWmsParameter param( QgsWmsParameter::LAYER );
566 param.mValue = lname;
567 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
568 }
569 }
570 }
571}
572
573void QgsWmsRenderContext::searchLayersToRenderStyle()
574{
575 for ( const QgsWmsParametersLayer &param : mParameters.layersParameters() )
576 {
577 const QString nickname = param.mNickname;
578 const QString style = param.mStyle;
579
580 if ( !param.mExternalUri.isEmpty() && ( mFlags & AddExternalLayers ) )
581 {
582 std::unique_ptr<QgsMapLayer> layer = std::make_unique<QgsRasterLayer>( param.mExternalUri, param.mNickname, u"wms"_s );
583
584 if ( layer->isValid() )
585 {
586 // to delete later
587 mExternalLayers.append( layer.release() );
588 auto lyr = mExternalLayers.last();
589 if ( !addLayerToRender( lyr ) )
590 {
591 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( lyr->name() ) );
592 }
593 }
594 }
595 else if ( mNicknameLayers.contains( nickname ) )
596 {
597 if ( !style.isEmpty() )
598 {
599 mStyles[nickname] = style;
600 }
601
602 for ( const auto layer : mNicknameLayers.values( nickname ) )
603 {
604 if ( !addLayerToRender( layer ) )
605 {
606 throw QgsSecurityException( u"Your are not allowed to access the layer %1"_s.arg( layer->name() ) );
607 }
608 }
609 }
610 else if ( mLayerGroups.contains( nickname ) )
611 {
613 {
614 QgsWmsParameter param( QgsWmsParameter::LAYER );
615 param.mValue = nickname;
616 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
617 }
618 // Reverse order of layers from a group
619 QList<QString> layersFromGroup;
620 for ( QgsMapLayer *layer : mLayerGroups[nickname] )
621 {
622 const QString nickname = layerNickname( *layer );
623 if ( !style.isEmpty() )
624 {
625 mStyles[nickname] = style;
626 }
627 layersFromGroup.push_front( nickname );
628 }
629
630 bool layerAdded = false;
631 for ( const auto &name : layersFromGroup )
632 {
633 for ( const auto layer : mNicknameLayers.values( name ) )
634 {
635 if ( addLayerToRender( layer ) )
636 {
637 layerAdded = true;
638 }
639 }
640 }
641 // No layers have been added, consider the group
642 // as non-existent.
643 if ( !layerAdded )
644 {
645 QgsWmsParameter param( QgsWmsParameter::LAYER );
646 param.mValue = nickname;
647 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
648 }
649 }
650 else
651 {
652 QgsWmsParameter param( QgsWmsParameter::LAYER );
653 param.mValue = nickname;
654 throw QgsBadRequestException( QgsServiceException::OGC_LayerNotDefined, param );
655 }
656 }
657}
658
659bool QgsWmsRenderContext::layerScaleVisibility( const QString &name ) const
660{
661 bool visible = false;
662
663 if ( !mNicknameLayers.contains( name ) )
664 {
665 return visible;
666 }
667
668 const QList<QgsMapLayer *> layers = mNicknameLayers.values( name );
669 for ( QgsMapLayer *layer : layers )
670 {
671 bool scaleBasedVisibility = layer->hasScaleBasedVisibility();
672 bool useScaleConstraint = ( scaleDenominator() > 0 && scaleBasedVisibility );
673
674 if ( !useScaleConstraint || layer->isInScaleRange( scaleDenominator() ) )
675 {
676 visible = true;
677 }
678 }
679
680 return visible;
681}
682
683QMap<QString, QList<QgsMapLayer *>> QgsWmsRenderContext::layerGroups() const
684{
685 return mLayerGroups;
686}
687
689{
690 int width = mParameters.widthAsInt();
691
692 // May use SRCWIDTH to define image map size
693 if ( ( mFlags & UseSrcWidthHeight ) && mParameters.srcWidthAsInt() > 0 )
694 {
695 width = mParameters.srcWidthAsInt();
696 }
697
698 return width;
699}
700
702{
703 int height = mParameters.heightAsInt();
704
705 // May use SRCHEIGHT to define image map size
706 if ( ( mFlags & UseSrcWidthHeight ) && mParameters.srcHeightAsInt() > 0 )
707 {
708 height = mParameters.srcHeightAsInt();
709 }
710
711 return height;
712}
713
718
719bool QgsWmsRenderContext::isValidWidthHeight( int width, int height ) const
720{
721 if ( width <= 0 || height <= 0 )
722 return false;
723
724 //test if maxWidth / maxHeight are set in the project or as an env variable
725 //and WIDTH / HEIGHT parameter is in the range allowed range
726 //WIDTH
727 const int wmsMaxWidthProj = QgsServerProjectUtils::wmsMaxWidth( *mProject );
728 const int wmsMaxWidthEnv = settings().wmsMaxWidth();
729 int wmsMaxWidth;
730 if ( wmsMaxWidthEnv != -1 && wmsMaxWidthProj != -1 )
731 {
732 // both are set, so we take the more conservative one
733 wmsMaxWidth = std::min( wmsMaxWidthProj, wmsMaxWidthEnv );
734 }
735 else
736 {
737 // none or one are set, so we take the bigger one which is the one set or -1
738 wmsMaxWidth = std::max( wmsMaxWidthProj, wmsMaxWidthEnv );
739 }
740
741 if ( wmsMaxWidth != -1 && width > wmsMaxWidth )
742 {
743 return false;
744 }
745
746 //HEIGHT
747 const int wmsMaxHeightProj = QgsServerProjectUtils::wmsMaxHeight( *mProject );
748 const int wmsMaxHeightEnv = settings().wmsMaxHeight();
749 int wmsMaxHeight;
750 if ( wmsMaxHeightEnv != -1 && wmsMaxHeightProj != -1 )
751 {
752 // both are set, so we take the more conservative one
753 wmsMaxHeight = std::min( wmsMaxHeightProj, wmsMaxHeightEnv );
754 }
755 else
756 {
757 // none or one are set, so we take the bigger one which is the one set or -1
758 wmsMaxHeight = std::max( wmsMaxHeightProj, wmsMaxHeightEnv );
759 }
760
761 if ( wmsMaxHeight != -1 && height > wmsMaxHeight )
762 {
763 return false;
764 }
765
766 // Sanity check from internal QImage checks
767 // (see QImageData::calculateImageParameters() in qimage_p.h)
768 // this is to report a meaningful error message in case of
769 // image creation failure and to differentiate it from out
770 // of memory conditions.
771
772 // depth for now it cannot be anything other than 32, but I don't like
773 // to hardcode it: I hope we will support other depths in the future.
774 int depth = 32;
775 switch ( mParameters.format() )
776 {
779 default:
780 depth = 32;
781 }
782
783 if ( width > ( std::numeric_limits<int>::max() - 31 ) / depth )
784 return false;
785
786 const int bytes_per_line = ( ( width * depth + 31 ) >> 5 ) << 2; // bytes per scanline (must be multiple of 4)
787
788 if ( std::numeric_limits<int>::max() / bytes_per_line < height || std::numeric_limits<int>::max() / sizeof( uchar * ) < static_cast<uint>( height ) )
789 {
790 return false;
791 }
792
793 return true;
794}
795
797{
798 double buffer;
799 if ( mFlags & UseTileBuffer )
800 {
801 const QgsRectangle extent = mParameters.bboxAsRectangle();
802 if ( !mParameters.bbox().isEmpty() && extent.isEmpty() )
803 {
805 }
806 buffer = tileBuffer() * ( extent.width() / mapWidth );
807 }
808 else
809 {
810 buffer = 0;
811 }
812 return buffer;
813}
814
815QSize QgsWmsRenderContext::mapSize( const bool aspectRatio ) const
816{
817 int width = mapWidth();
818 int height = mapHeight();
819
820 // Adapt width / height if the aspect ratio does not correspond with the BBOX.
821 // Required by WMS spec. 1.3.
822 if ( aspectRatio && mParameters.versionAsNumber() >= QgsProjectVersion( 1, 3, 0 ) )
823 {
824 QgsRectangle extent = mParameters.bboxAsRectangle();
825 if ( !mParameters.bbox().isEmpty() && extent.isEmpty() )
826 {
828 }
829
830 QString crs = mParameters.crs();
831 if ( crs.compare( "CRS:84", Qt::CaseInsensitive ) == 0 )
832 {
833 crs = QString( "EPSG:4326" );
834 extent.invert();
835 }
836
838 if ( outputCrs.hasAxisInverted() )
839 {
840 extent.invert();
841 }
842
843 if ( !extent.isEmpty() && height > 0 && width > 0 )
844 {
845 const double mapRatio = extent.width() / extent.height();
846 const double imageRatio = static_cast<double>( width ) / static_cast<double>( height );
847 if ( !qgsDoubleNear( mapRatio, imageRatio, 0.0001 ) )
848 {
849 // inspired by MapServer, mapdraw.c L115
850 const double cellsize = ( extent.width() / static_cast<double>( width ) ) * 0.5 + ( extent.height() / static_cast<double>( height ) ) * 0.5;
851 width = extent.width() / cellsize;
852 height = extent.height() / cellsize;
853 }
854 }
855 }
856
857 if ( width <= 0 )
858 {
860 }
861 else if ( height <= 0 )
862 {
864 }
865
866 return QSize( width, height );
867}
868
869void QgsWmsRenderContext::removeUnwantedLayers()
870{
871 QList<QgsMapLayer *> layers;
872
873 for ( QgsMapLayer *layer : mLayersToRender )
874 {
875 const QString nickname = layerNickname( *layer );
876
877 if ( !isExternalLayer( nickname ) )
878 {
879 if ( !layerScaleVisibility( nickname ) )
880 continue;
881
882 if ( mRestrictedLayers.contains( nickname ) )
883 continue;
884
885 if ( mFlags & UseWfsLayersOnly )
886 {
888 {
889 continue;
890 }
891
892 const QStringList wfsLayers = QgsServerProjectUtils::wfsLayerIds( *mProject );
893 if ( !wfsLayers.contains( layer->id() ) )
894 {
895 continue;
896 }
897 }
898 }
899
900 layers.append( layer );
901 }
902
903 mLayersToRender = layers;
904}
905
906bool QgsWmsRenderContext::isExternalLayer( const QString &name ) const
907{
908 for ( const auto &layer : mExternalLayers )
909 {
910 if ( layerNickname( *layer ).compare( name ) == 0 )
911 return true;
912 }
913
914 return false;
915}
916
917bool QgsWmsRenderContext::checkLayerReadPermissions( QgsMapLayer *layer ) const
918{
919#ifdef HAVE_SERVER_PYTHON_PLUGINS
920 if ( !accessControl()->layerReadPermission( layer ) )
921 {
922 QString msg = u"Checking forbidden access for layer: %1"_s.arg( layer->name() );
924 return false;
925 }
926#endif
927 Q_UNUSED( layer )
928 return true;
929}
930
931#ifdef HAVE_SERVER_PYTHON_PLUGINS
932QgsAccessControl *QgsWmsRenderContext::accessControl() const
933{
934 return mInterface->accessControls();
935}
936#endif
937
939{
940 mSocketFeedback = feedback;
941}
942
944{
945 return mSocketFeedback;
946}
@ Info
Information message.
Definition qgis.h:161
@ Vector
Vector layer.
Definition qgis.h:207
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.
Definition qgsfeedback.h:44
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.
Definition qgsmaplayer.h:83
QString name
Definition qgsmaplayer.h:87
QString id
Definition qgsmaplayer.h:86
Qgis::LayerType type
Definition qgsmaplayer.h:93
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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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,...
Definition qgsproject.h:113
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.
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 &parameters)
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).
Definition qgis.h:6975
const double OGC_PX_M