31 #include <QTextBoundaryFinder>
36 static void _fixQPictureDPI( QPainter *p )
42 p->scale(
static_cast< double >(
qt_defaultDpiX() ) / p->device()->logicalDpiX(),
43 static_cast< double >(
qt_defaultDpiY() ) / p->device()->logicalDpiY() );
48 if ( alignment & Qt::AlignLeft )
50 else if ( alignment & Qt::AlignRight )
52 else if ( alignment & Qt::AlignHCenter )
54 else if ( alignment & Qt::AlignJustify )
63 if ( alignment & Qt::AlignTop )
65 else if ( alignment & Qt::AlignBottom )
67 else if ( alignment & Qt::AlignVCenter )
70 else if ( alignment & Qt::AlignBaseline )
78 return static_cast< int >(
c.convertToPainterUnits( size, unit, mapUnitScale ) + 0.5 );
86 tmpFormat = updateShadowPosition( tmpFormat );
88 QStringList textLines;
89 for (
const QString &line : text )
93 textLines.append(
wrappedText( context, line, rect.width(), format ) );
97 textLines.append( line );
106 drawPart( rect, rotation, alignment, vAlignment, document, context, tmpFormat,
Background );
111 drawPart( rect, rotation, alignment, vAlignment, document, context, tmpFormat,
Buffer );
114 drawPart( rect, rotation, alignment, vAlignment, document, context, tmpFormat,
Text );
122 tmpFormat = updateShadowPosition( tmpFormat );
134 drawPart( point, rotation, alignment, document, context, tmpFormat,
Buffer );
137 drawPart( point, rotation, alignment, document, context, tmpFormat,
Text );
166 drawPart( rect, rotation, alignment,
AlignTop, document, context, format, part );
177 component.dpiRatio = 1.0;
178 component.origin = rect.topLeft();
179 component.rotation = rotation;
180 component.size = rect.size();
181 component.hAlign = alignment;
194 double xc = rect.width() / 2.0;
195 double yc = rect.height() / 2.0;
197 double angle = -rotation;
198 double xd = xc * std::cos(
angle ) - yc * std::sin(
angle );
199 double yd = xc * std::sin(
angle ) + yc * std::cos(
angle );
201 component.center = QPointF( component.origin.x() + xd, component.origin.y() + yd );
205 component.center = rect.center();
208 QgsTextRenderer::drawBackground( context, component, format, document,
Rect );
222 drawTextInternal( part, context, format, component,
225 alignment, vAlignment );
234 drawPart( origin, rotation, alignment, document, context, format, part );
245 component.dpiRatio = 1.0;
246 component.origin = origin;
247 component.rotation = rotation;
248 component.hAlign = alignment;
257 QgsTextRenderer::drawBackground( context, component, format, document,
Point );
270 drawTextInternal( part, context, format, component,
282 return QFontMetricsF( format.
scaledFont( context, scaleFactor ), context.
painter() ? context.
painter()->device() :
nullptr );
288 QPainter *p = context.
painter();
293 if ( component.rotation >= -315 && component.rotation < -90 )
297 else if ( component.rotation >= -90 && component.rotation < -45 )
313 const double scaleFactor = calculateScaleFactorForFormat( context, format );
315 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
323 bool isNullSize =
false;
324 const QFont font = format.
scaledFont( context, scaleFactor, &isNullSize );
328 referenceScaleOverride.reset();
331 path.setFillRule( Qt::WindingFill );
333 switch ( orientation )
340 QFont fragmentFont = font;
343 if ( component.extraWordSpacing || component.extraLetterSpacing )
344 applyExtraSpacingForLineJustification( fragmentFont, component.extraWordSpacing, component.extraLetterSpacing );
346 path.addText( xOffset, 0, fragmentFont, fragment.
text() );
357 double letterSpacing = font.letterSpacing();
358 double partYOffset = component.offset.y() * scaleFactor;
361 QFont fragmentFont = font;
364 QFontMetricsF fragmentMetrics( fragmentFont );
365 const double labelWidth = fragmentMetrics.maxWidth();
368 for (
const QString &part : parts )
370 double partXOffset = ( labelWidth - ( fragmentMetrics.horizontalAdvance( part ) - letterSpacing ) ) / 2;
371 path.addText( partXOffset, partYOffset, fragmentFont, part );
372 partYOffset += fragmentMetrics.ascent() + letterSpacing;
375 advance = partYOffset - component.offset.y() * scaleFactor;
380 QColor bufferColor = buffer.
color();
381 bufferColor.setAlphaF( buffer.
opacity() );
382 QPen pen( bufferColor );
383 pen.setWidthF( penSize * scaleFactor );
385 QColor tmpColor( bufferColor );
389 tmpColor.setAlpha( 0 );
395 buffp.begin( &buffPict );
399 std::unique_ptr< QgsPaintEffect > tmpEffect( buffer.
paintEffect()->
clone() );
401 tmpEffect->begin( context );
402 context.
painter()->setPen( pen );
403 context.
painter()->setBrush( tmpColor );
404 if ( scaleFactor != 1.0 )
405 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
406 context.
painter()->drawPath( path );
407 if ( scaleFactor != 1.0 )
408 context.
painter()->scale( scaleFactor, scaleFactor );
409 tmpEffect->end( context );
415 if ( scaleFactor != 1.0 )
416 buffp.scale( 1 / scaleFactor, 1 / scaleFactor );
418 buffp.setBrush( tmpColor );
419 buffp.drawPath( path );
425 QgsTextRenderer::Component bufferComponent = component;
426 bufferComponent.origin = QPointF( 0.0, 0.0 );
427 bufferComponent.picture = buffPict;
428 bufferComponent.pictureBuffer = penSize / 2.0;
432 bufferComponent.offset.setY( bufferComponent.offset.y() - bufferComponent.size.height() );
434 drawShadow( context, bufferComponent, format );
442 p->setCompositionMode( buffer.
blendMode() );
446 p->scale( component.dpiRatio, component.dpiRatio );
447 _fixQPictureDPI( p );
448 p->drawPicture( 0, 0, buffPict );
450 return advance / scaleFactor;
470 path.setFillRule( Qt::WindingFill );
472 const double scaleFactor = calculateScaleFactorForFormat( context, format );
477 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
485 bool isNullSize =
false;
486 const QFont font = format.
scaledFont( context, scaleFactor, &isNullSize );
490 referenceScaleOverride.reset();
495 QFont fragmentFont = font;
498 path.addText( xOffset, 0, fragmentFont, fragment.
text() );
503 QColor bufferColor( Qt::gray );
504 bufferColor.setAlphaF( mask.
opacity() );
508 brush.setColor( bufferColor );
509 pen.setColor( bufferColor );
510 pen.setWidthF( penSize * scaleFactor );
517 p->scale( component.dpiRatio, component.dpiRatio );
523 if ( scaleFactor != 1.0 )
524 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
525 context.
painter()->setPen( pen );
526 context.
painter()->setBrush( brush );
527 context.
painter()->drawPath( path );
528 if ( scaleFactor != 1.0 )
529 context.
painter()->scale( scaleFactor, scaleFactor );
534 if ( scaleFactor != 1.0 )
535 p->scale( 1 / scaleFactor, 1 / scaleFactor );
537 p->setBrush( brush );
539 if ( scaleFactor != 1.0 )
540 p->scale( scaleFactor, scaleFactor );
557 return textWidth( context, format, doc );
563 const double scaleFactor = calculateScaleFactorForFormat( context, format );
565 bool isNullSize =
false;
566 const QFont baseFont = format.
scaledFont( context, scaleFactor, &isNullSize );
575 double maxLineWidth = 0;
578 double blockWidth = 0;
583 maxLineWidth = std::max( maxLineWidth, blockWidth );
585 width = maxLineWidth;
591 double totalLineWidth = 0;
595 double blockWidth = 0;
598 QFont fragmentFont = baseFont;
600 blockWidth = std::max( QFontMetricsF( fragmentFont ).maxWidth(), blockWidth );
603 totalLineWidth += blockIndex == 0 ? blockWidth : blockWidth * format.
lineHeight();
606 width = totalLineWidth;
617 return width / scaleFactor;
623 for (
const QString &line : textLines )
627 lines.append(
wrappedText( context, line, maxLineWidth, format ) );
631 lines.append( line );
647 const double scaleFactor = calculateScaleFactorForFormat( context, format );
648 bool isNullSize =
false;
649 const QFont baseFont = format.
scaledFont( context, scaleFactor, &isNullSize );
653 const QFontMetrics fm( baseFont );
654 const double height = ( character.isNull() ? fm.height() : fm.boundingRect( character ).height() ) / scaleFactor;
656 if ( !includeEffects )
659 double maxExtension = 0;
688 return height + maxExtension;
696 const QStringList multiLineSplit = text.split(
'\n' );
698 return currentTextWidth > width;
703 const QStringList lines = text.split(
'\n' );
704 QStringList outLines;
705 for (
const QString &line : lines )
710 const QStringList words = line.split(
' ' );
711 QStringList linesToProcess;
712 QString wordsInCurrentLine;
713 for (
const QString &word : words )
718 if ( !wordsInCurrentLine.isEmpty() )
719 linesToProcess << wordsInCurrentLine;
720 wordsInCurrentLine.clear();
721 linesToProcess << word;
725 if ( !wordsInCurrentLine.isEmpty() )
726 wordsInCurrentLine.append(
' ' );
727 wordsInCurrentLine.append( word );
730 if ( !wordsInCurrentLine.isEmpty() )
731 linesToProcess << wordsInCurrentLine;
733 for (
const QString &line : std::as_const( linesToProcess ) )
735 QString remainingText = line;
736 int lastPos = remainingText.lastIndexOf(
' ' );
737 while ( lastPos > -1 )
747 outLines << remainingText.left( lastPos );
748 remainingText = remainingText.mid( lastPos + 1 );
751 lastPos = remainingText.lastIndexOf(
' ', lastPos - 1 );
753 outLines << remainingText;
771 const double scaleFactor = calculateScaleFactorForFormat( context, format );
773 bool isNullSize =
false;
774 const QFont baseFont = format.
scaledFont( context, scaleFactor, &isNullSize );
783 double totalHeight = 0;
784 double lastLineLeading = 0;
787 double maxBlockHeight = 0;
788 double maxBlockLineSpacing = 0;
789 double maxBlockLeading = 0;
792 QFont fragmentFont = baseFont;
794 const QFontMetricsF fm( fragmentFont );
796 const double fragmentHeight = fm.ascent() + fm.descent();
798 maxBlockHeight = std::max( maxBlockHeight, fragmentHeight );
799 if ( fm.lineSpacing() > maxBlockLineSpacing )
801 maxBlockLineSpacing = fm.lineSpacing();
802 maxBlockLeading = fm.leading();
812 totalHeight += blockIndex == 0 ? maxBlockHeight : maxBlockHeight * format.
lineHeight();
818 totalHeight += blockIndex == 0 ? maxBlockHeight : maxBlockLineSpacing * format.
lineHeight();
819 if ( blockIndex > 0 )
820 lastLineLeading = maxBlockLeading;
827 return ( totalHeight - lastLineLeading ) / scaleFactor;
832 double maxBlockHeight = 0;
835 double blockHeight = 0;
836 int fragmentIndex = 0;
839 QFont fragmentFont = baseFont;
841 const QFontMetricsF fm( fragmentFont );
843 const double labelHeight = fm.ascent();
844 const double letterSpacing = fragmentFont.letterSpacing();
846 blockHeight += fragmentIndex = 0 ? labelHeight * fragment.
text().size() + ( fragment.
text().size() - 1 ) * letterSpacing
847 : fragment.
text().size() * ( labelHeight + letterSpacing );
850 maxBlockHeight = std::max( maxBlockHeight, blockHeight );
853 return maxBlockHeight / scaleFactor;
870 QPainter *prevP = context.
painter();
871 QPainter *p = context.
painter();
872 std::unique_ptr< QgsPaintEffect > tmpEffect;
876 tmpEffect->begin( context );
885 const double originAdjustRotationRadians = -component.rotation;
888 component.rotation = -( component.rotation * 180 / M_PI );
889 component.rotationOffset =
894 component.rotation = 0.0;
895 component.rotationOffset = background.
rotation();
898 const double scaleFactor = calculateScaleFactorForFormat( context, format );
903 double width =
textWidth( context, format, document );
904 double height =
textHeight( context, format, document, mode );
909 switch ( component.hAlign )
913 component.center = QPointF( component.origin.x() + width / 2.0,
914 component.origin.y() + height / 2.0 );
918 component.center = QPointF( component.origin.x() + component.size.width() / 2.0,
919 component.origin.y() + height / 2.0 );
923 component.center = QPointF( component.origin.x() + component.size.width() - width / 2.0,
924 component.origin.y() + height / 2.0 );
931 bool isNullSize =
false;
932 QFontMetricsF fm( format.
scaledFont( context, scaleFactor, &isNullSize ) );
933 double originAdjust = isNullSize ? 0 : ( fm.ascent() / scaleFactor / 2.0 - fm.leading() / scaleFactor / 2.0 );
934 switch ( component.hAlign )
938 component.center = QPointF( component.origin.x() + width / 2.0,
939 component.origin.y() - height / 2.0 + originAdjust );
943 component.center = QPointF( component.origin.x(),
944 component.origin.y() - height / 2.0 + originAdjust );
948 component.center = QPointF( component.origin.x() - width / 2.0,
949 component.origin.y() - height / 2.0 + originAdjust );
956 const double dx = component.center.x() - component.origin.x();
957 const double dy = component.center.y() - component.origin.y();
958 component.center.setX( component.origin.x() + ( std::cos( originAdjustRotationRadians ) * dx - std::sin( originAdjustRotationRadians ) * dy ) );
959 component.center.setY( component.origin.y() + ( std::sin( originAdjustRotationRadians ) * dx + std::cos( originAdjustRotationRadians ) * dy ) );
969 component.size = QSizeF( width, height );
974 switch ( background.
type() )
987 double sizeOut = 0.0;
995 sizeOut = std::max( component.size.width(), component.size.height() );
999 sizeOut += bufferSize * 2;
1004 if ( sizeOut < 1.0 )
1007 std::unique_ptr< QgsMarkerSymbol > renderedSymbol;
1011 map[QStringLiteral(
"name" )] = background.
svgFile().trimmed();
1012 map[QStringLiteral(
"size" )] = QString::number( sizeOut );
1014 map[QStringLiteral(
"angle" )] = QString::number( 0.0 );
1022 map[QStringLiteral(
"fill" )] = background.
fillColor().name();
1023 map[QStringLiteral(
"outline" )] = background.
strokeColor().name();
1024 map[QStringLiteral(
"outline-width" )] = QString::number( background.
strokeWidth() );
1031 QVariantMap shdwmap( map );
1032 shdwmap[QStringLiteral(
"fill" )] = shadow.
color().name();
1033 shdwmap[QStringLiteral(
"outline" )] = shadow.
color().name();
1034 shdwmap[QStringLiteral(
"size" )] = QString::number( sizeOut );
1039 svgp.begin( &svgPict );
1056 svgShdwM->
renderPoint( QPointF( sizeOut / 2, -sizeOut / 2 ), svgShdwContext );
1059 component.picture = svgPict;
1061 component.pictureBuffer = 0.0;
1063 component.size = QSizeF( sizeOut, sizeOut );
1064 component.offset = QPointF( 0.0, 0.0 );
1070 p->translate( component.center.x(), component.center.y() );
1071 p->rotate( component.rotation );
1074 p->translate( QPointF( xoff, yoff ) );
1075 p->rotate( component.rotationOffset );
1076 p->translate( -sizeOut / 2, sizeOut / 2 );
1078 drawShadow( context, component, format );
1080 renderedSymbol.reset( );
1088 renderedSymbol->setSize( sizeOut );
1092 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1100 p->setCompositionMode( background.
blendMode() );
1102 p->translate( component.center.x(), component.center.y() );
1103 p->rotate( component.rotation );
1106 p->translate( QPointF( xoff, yoff ) );
1107 p->rotate( component.rotationOffset );
1111 renderedSymbol->renderPoint( QPointF( 0, 0 ), &f, context );
1112 renderedSymbol->stopRender( context );
1113 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1123 double w = component.size.width();
1124 double h = component.size.height();
1145 h = std::sqrt( std::pow( w, 2 ) + std::pow( h, 2 ) );
1151 h = h * M_SQRT1_2 * 2;
1152 w = w * M_SQRT1_2 * 2;
1160 w += bufferWidth * 2;
1161 h += bufferHeight * 2;
1165 QRectF rect( -w / 2.0, - h / 2.0, w, h );
1167 if ( rect.isNull() )
1173 p->translate( QPointF( component.center.x(), component.center.y() ) );
1174 p->rotate( component.rotation );
1177 p->translate( QPointF( xoff, yoff ) );
1178 p->rotate( component.rotationOffset );
1184 QTransform t = QTransform::fromScale( 10, 10 );
1186 QTransform ti = t.inverted();
1193 path.addRoundedRect( rect, background.
radii().width(), background.
radii().height(), Qt::RelativeSize );
1199 path.addRoundedRect( rect, xRadius, yRadius );
1205 path.addEllipse( rect );
1207 QPolygonF tempPolygon = path.toFillPolygon( t );
1208 QPolygonF polygon = ti.map( tempPolygon );
1210 QPainter *oldp = context.
painter();
1213 shapep.begin( &shapePict );
1216 std::unique_ptr< QgsFillSymbol > renderedSymbol;
1218 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1222 renderedSymbol->renderPolygon( polygon,
nullptr, &f, context );
1223 renderedSymbol->stopRender( context );
1230 component.picture = shapePict;
1233 component.size = rect.size();
1234 component.offset = QPointF( rect.width() / 2, -rect.height() / 2 );
1235 drawShadow( context, component, format );
1240 p->setCompositionMode( background.
blendMode() );
1244 p->scale( component.dpiRatio, component.dpiRatio );
1245 _fixQPictureDPI( p );
1246 p->drawPicture( 0, 0, shapePict );
1247 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1254 tmpEffect->end( context );
1267 QPainter *p = context.
painter();
1268 double componentWidth = component.size.width(), componentHeight = component.size.height();
1269 double xOffset = component.offset.x(), yOffset = component.offset.y();
1270 double pictbuffer = component.pictureBuffer;
1279 radius /= ( mapUnits ? context.
scaleFactor() / component.dpiRatio : 1 );
1280 radius =
static_cast< int >( radius + 0.5 );
1284 double blurBufferClippingScale = 3.75;
1285 int blurbuffer = ( radius > 17 ? 16 : radius ) * blurBufferClippingScale;
1287 QImage blurImg( componentWidth + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1288 componentHeight + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1289 QImage::Format_ARGB32_Premultiplied );
1293 int minBlurImgSize = 1;
1297 int maxBlurImgSize = 40000;
1298 if ( blurImg.isNull()
1299 || ( blurImg.width() < minBlurImgSize || blurImg.height() < minBlurImgSize )
1300 || ( blurImg.width() > maxBlurImgSize || blurImg.height() > maxBlurImgSize ) )
1303 blurImg.fill( QColor( Qt::transparent ).rgba() );
1305 if ( !pictp.begin( &blurImg ) )
1307 pictp.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
1308 QPointF imgOffset( blurbuffer + pictbuffer + xOffset,
1309 blurbuffer + pictbuffer + componentHeight + yOffset );
1311 pictp.drawPicture( imgOffset,
1312 component.picture );
1315 pictp.setCompositionMode( QPainter::CompositionMode_SourceIn );
1316 pictp.fillRect( blurImg.rect(), shadow.
color() );
1320 if ( shadow.
blurRadius() > 0.0 && radius > 0 )
1328 picti.begin( &blurImg );
1329 picti.setBrush( Qt::Dense7Pattern );
1330 QPen imgPen( QColor( 0, 0, 255, 255 ) );
1331 imgPen.setWidth( 1 );
1332 picti.setPen( imgPen );
1333 picti.setOpacity( 0.1 );
1334 picti.drawRect( 0, 0, blurImg.width(), blurImg.height() );
1341 double angleRad = shadow.
offsetAngle() * M_PI / 180;
1349 angleRad -= ( component.rotation * M_PI / 180 + component.rotationOffset * M_PI / 180 );
1352 QPointF transPt( -offsetDist * std::cos( angleRad + M_PI_2 ),
1353 -offsetDist * std::sin( angleRad + M_PI_2 ) );
1359 p->setRenderHint( QPainter::SmoothPixmapTransform );
1362 p->setCompositionMode( shadow.
blendMode() );
1364 p->setOpacity( shadow.
opacity() );
1366 double scale = shadow.
scale() / 100.0;
1368 p->scale( scale, scale );
1369 if ( component.useOrigin )
1371 p->translate( component.origin.x(), component.origin.y() );
1373 p->translate( transPt );
1374 p->translate( -imgOffset.x(),
1376 p->drawImage( 0, 0, blurImg );
1383 p->setBrush( Qt::NoBrush );
1384 QPen imgPen( QColor( 255, 0, 0, 10 ) );
1385 imgPen.setWidth( 2 );
1386 imgPen.setStyle( Qt::DashLine );
1387 p->setPen( imgPen );
1388 p->scale( scale, scale );
1389 if ( component.useOrigin() )
1391 p->translate( component.origin().x(), component.origin().y() );
1393 p->translate( transPt );
1394 p->translate( -imgOffset.x(),
1396 p->drawRect( 0, 0, blurImg.width(), blurImg.height() );
1401 p->setBrush( Qt::NoBrush );
1402 QPen componentRectPen( QColor( 0, 255, 0, 70 ) );
1403 componentRectPen.setWidth( 1 );
1404 if ( component.useOrigin() )
1406 p->translate( component.origin().x(), component.origin().y() );
1408 p->setPen( componentRectPen );
1409 p->drawRect( QRect( -xOffset, -componentHeight - yOffset, componentWidth, componentHeight ) );
1415 void QgsTextRenderer::drawTextInternal( TextPart drawType,
1418 const Component &component,
1420 const QFontMetricsF *fontMetrics,
1421 HAlignment alignment, VAlignment vAlignment, DrawMode mode )
1428 double fontScale = 1.0;
1429 std::unique_ptr< QFontMetricsF > tmpMetrics;
1432 fontScale = calculateScaleFactorForFormat( context, format );
1434 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1435 if ( mode ==
Label )
1442 bool isNullSize =
false;
1443 const QFont f = format.
scaledFont( context, fontScale, &isNullSize );
1447 tmpMetrics = std::make_unique< QFontMetricsF >( f );
1450 referenceScaleOverride.reset();
1453 double rotation = 0;
1455 switch ( orientation )
1459 drawTextInternalHorizontal( context, format, drawType, mode, component, document, fontScale,
fontMetrics, alignment, vAlignment, rotation );
1466 drawTextInternalVertical( context, format, drawType, mode, component, document, fontScale,
fontMetrics, alignment, vAlignment, rotation );
1474 rotation = -component.rotation * 180 / M_PI;
1481 if ( rotation >= -315 && rotation < -90 )
1486 else if ( rotation >= -90 && rotation < -45 )
1502 void QgsTextRenderer::calculateExtraSpacingForLineJustification(
const double spaceToDistribute,
const QgsTextBlock &block,
double &extraWordSpace,
double &extraLetterSpace )
1505 QTextBoundaryFinder
finder( QTextBoundaryFinder::Word, blockText );
1507 int wordBoundaries = 0;
1508 while (
finder.toNextBoundary() != -1 )
1510 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1514 if ( wordBoundaries > 0 )
1517 extraWordSpace = spaceToDistribute / wordBoundaries;
1522 QTextBoundaryFinder
finder( QTextBoundaryFinder::Grapheme, blockText );
1525 int graphemeBoundaries = 0;
1526 while (
finder.toNextBoundary() != -1 )
1528 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1529 graphemeBoundaries++;
1532 if ( graphemeBoundaries > 0 )
1534 extraLetterSpace = spaceToDistribute / graphemeBoundaries;
1539 void QgsTextRenderer::applyExtraSpacingForLineJustification( QFont &font,
double extraWordSpace,
double extraLetterSpace )
1541 const double prevWordSpace = font.wordSpacing();
1542 font.setWordSpacing( prevWordSpace + extraWordSpace );
1543 const double prevLetterSpace = font.letterSpacing();
1544 font.setLetterSpacing( QFont::AbsoluteSpacing, prevLetterSpace + extraLetterSpace );
1547 void QgsTextRenderer::drawTextInternalHorizontal(
QgsRenderContext &context,
const QgsTextFormat &format, TextPart drawType, DrawMode mode,
const Component &component,
const QgsTextDocument &document,
double fontScale,
const QFontMetricsF *fontMetrics, HAlignment hAlignment,
1548 VAlignment vAlignment,
double rotation )
1551 const QStringList textLines = document.
toPlainText();
1553 double labelWidest = 0.0;
1558 for (
const QString &line : textLines )
1560 double labelWidth =
fontMetrics->horizontalAdvance( line ) / fontScale;
1561 if ( labelWidth > labelWidest )
1563 labelWidest = labelWidth;
1569 labelWidest = component.size.width();
1577 double ascentOffset = 0.25 *
fontMetrics->ascent() / fontScale;
1581 bool adjustForAlignment = hAlignment !=
AlignLeft && ( mode !=
Label || textLines.size() > 1 );
1585 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1587 const double overallHeight =
textHeight( context, format, textLines,
Rect );
1588 switch ( vAlignment )
1594 ascentOffset = -( component.size.height() - overallHeight ) * 0.5 + ascentOffset;
1598 ascentOffset = -( component.size.height() - overallHeight ) + ascentOffset;
1601 referenceScaleOverride.reset();
1604 for (
const QString &line : std::as_const( textLines ) )
1608 const bool isFinalLineInParagraph = ( i == document.
size() - 1 )
1613 context.
painter()->translate( component.origin );
1615 context.
painter()->rotate( rotation );
1620 maskPainter->save();
1621 maskPainter->translate( component.origin );
1623 maskPainter->rotate( rotation );
1627 double xMultiLineOffset = 0.0;
1628 double labelWidth =
fontMetrics->horizontalAdvance( line ) / fontScale;
1629 double extraWordSpace = 0;
1630 double extraLetterSpace = 0;
1631 if ( adjustForAlignment )
1633 double labelWidthDiff = 0;
1634 switch ( hAlignment )
1637 labelWidthDiff = ( labelWidest - labelWidth ) * 0.5;
1641 labelWidthDiff = labelWidest - labelWidth;
1645 if ( !isFinalLineInParagraph && labelWidest > labelWidth )
1647 calculateExtraSpacingForLineJustification( labelWidest - labelWidth, block, extraWordSpace, extraLetterSpace );
1648 labelWidth = labelWidest;
1660 xMultiLineOffset = labelWidthDiff;
1665 switch ( hAlignment )
1668 xMultiLineOffset = labelWidthDiff - labelWidest;
1672 xMultiLineOffset = labelWidthDiff - labelWidest / 2.0;
1684 double yMultiLineOffset = ascentOffset;
1691 yMultiLineOffset = - ascentOffset - ( textLines.size() - 1 - i ) * labelHeight * format.
lineHeight();
1696 yMultiLineOffset = - ascentOffset + labelHeight - 1 + format.
lineHeight() *
fontMetrics->lineSpacing() * i / fontScale;
1701 yMultiLineOffset = 0 - ( textLines.size() - 1 - i ) *
fontMetrics->lineSpacing() * format.
lineHeight() / fontScale;
1706 context.
painter()->translate( QPointF( xMultiLineOffset, yMultiLineOffset ) );
1708 maskPainter->translate( QPointF( xMultiLineOffset, yMultiLineOffset ) );
1710 Component subComponent;
1711 subComponent.block = block;
1712 subComponent.
size = QSizeF( labelWidth, labelHeight );
1713 subComponent.offset = QPointF( 0.0, -ascentOffset );
1714 subComponent.rotation = -component.rotation * 180 / M_PI;
1715 subComponent.rotationOffset = 0.0;
1716 subComponent.extraWordSpacing = extraWordSpace * fontScale;
1717 subComponent.extraLetterSpacing = extraLetterSpace * fontScale;
1722 QgsTextRenderer::drawMask( context, subComponent, format, mode );
1727 QgsTextRenderer::drawBuffer( context, subComponent, format, mode );
1734 textp.begin( &textPict );
1735 textp.setPen( Qt::NoPen );
1737 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1738 if ( mode ==
Label )
1744 bool isNullSize =
false;
1745 const QFont font = format.
scaledFont( context, fontScale, &isNullSize );
1746 referenceScaleOverride.reset();
1750 textp.scale( 1 / fontScale, 1 / fontScale );
1757 path.setFillRule( Qt::WindingFill );
1759 QFont fragmentFont = font;
1762 if ( extraWordSpace || extraLetterSpace )
1763 applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
1765 path.addText( xOffset, 0, fragmentFont, fragment.
text() );
1769 textp.setBrush( textColor );
1770 textp.drawPath( path );
1779 subComponent.picture = textPict;
1780 subComponent.pictureBuffer = 0.0;
1781 subComponent.origin = QPointF( 0.0, 0.0 );
1783 QgsTextRenderer::drawShadow( context, subComponent, format );
1793 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
1797 case Qgis::TextRenderFormat::AlwaysOutlines:
1800 _fixQPictureDPI( context.
painter() );
1801 context.
painter()->drawPicture( 0, 0, textPict );
1805 case Qgis::TextRenderFormat::AlwaysText:
1810 QFont fragmentFont = font;
1813 if ( extraWordSpace || extraLetterSpace )
1814 applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
1819 context.
painter()->setPen( textColor );
1820 context.
painter()->setFont( fragmentFont );
1821 context.
painter()->setRenderHint( QPainter::TextAntialiasing );
1823 context.
painter()->scale( 1 / fontScale, 1 / fontScale );
1824 context.
painter()->drawText( xOffset, 0, fragment.
text() );
1825 context.
painter()->scale( fontScale, fontScale );
1833 maskPainter->restore();
1838 void QgsTextRenderer::drawTextInternalVertical(
QgsRenderContext &context,
const QgsTextFormat &format,
QgsTextRenderer::TextPart drawType,
QgsTextRenderer::DrawMode mode,
const QgsTextRenderer::Component &component,
const QgsTextDocument &document,
double fontScale,
const QFontMetricsF *fontMetrics,
QgsTextRenderer::HAlignment hAlignment,
QgsTextRenderer::VAlignment,
double rotation )
1841 const QStringList textLines = document.
toPlainText();
1843 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1844 if ( mode ==
Label )
1851 bool isNullSize =
false;
1852 const QFont font = format.
scaledFont( context, fontScale, &isNullSize );
1856 referenceScaleOverride.reset();
1858 double letterSpacing = font.letterSpacing() / fontScale;
1860 double labelWidth =
fontMetrics->maxWidth() / fontScale;
1861 double actualLabelWidest = labelWidth + ( textLines.size() - 1 ) * labelWidth * format.
lineHeight();
1862 double labelWidest = 0.0;
1867 labelWidest = actualLabelWidest;
1871 labelWidest = component.size.width();
1875 int maxLineLength = 0;
1876 for (
const QString &line : std::as_const( textLines ) )
1878 maxLineLength = std::max( maxLineLength,
static_cast<int>( line.length() ) );
1880 double actualLabelHeight =
fontMetrics->ascent() / fontScale + (
fontMetrics->ascent() / fontScale + letterSpacing ) * ( maxLineLength - 1 );
1881 double ascentOffset =
fontMetrics->ascent() / fontScale;
1885 bool adjustForAlignment = hAlignment !=
AlignLeft && ( mode !=
Label || textLines.size() > 1 );
1892 context.
painter()->translate( component.origin );
1894 context.
painter()->rotate( rotation );
1899 maskPainter->save();
1900 maskPainter->translate( component.origin );
1902 maskPainter->rotate( rotation );
1906 double xOffset = actualLabelWidest - labelWidth - ( i * labelWidth * format.
lineHeight() );
1907 if ( adjustForAlignment )
1909 double labelWidthDiff = 0;
1910 switch ( hAlignment )
1913 labelWidthDiff = ( labelWidest - actualLabelWidest ) * 0.5;
1917 labelWidthDiff = labelWidest - actualLabelWidest;
1929 xOffset += labelWidthDiff;
1937 double yOffset = 0.0;
1943 if ( rotation >= -405 && rotation < -180 )
1945 yOffset = ascentOffset;
1947 else if ( rotation >= 0 && rotation < 45 )
1949 xOffset -= actualLabelWidest;
1950 yOffset = -actualLabelHeight + ascentOffset +
fontMetrics->descent() / fontScale;
1955 yOffset = -actualLabelHeight + ascentOffset;
1960 yOffset = -actualLabelHeight + ascentOffset;
1964 yOffset = ascentOffset;
1968 context.
painter()->translate( QPointF( xOffset, yOffset ) );
1970 double fragmentYOffset = 0;
1976 QFont fragmentFont( font );
1979 QFontMetricsF fragmentMetrics( fragmentFont );
1981 double labelHeight = fragmentMetrics.ascent() / fontScale + ( fragmentMetrics.ascent() / fontScale + letterSpacing ) * ( line.length() - 1 );
1983 Component subComponent;
1985 subComponent.size = QSizeF( labelWidth, labelHeight );
1986 subComponent.offset = QPointF( 0.0, fragmentYOffset );
1987 subComponent.rotation = -component.rotation * 180 / M_PI;
1988 subComponent.rotationOffset = 0.0;
1995 QgsTextRenderer::drawMask( context, subComponent, format );
2001 fragmentYOffset += QgsTextRenderer::drawBuffer( context, subComponent, format, mode );
2007 path.setFillRule( Qt::WindingFill );
2009 double partYOffset = 0.0;
2010 for (
const auto &part : parts )
2012 double partXOffset = ( labelWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
2013 path.addText( partXOffset * fontScale, partYOffset * fontScale, fragmentFont, part );
2014 partYOffset += fragmentMetrics.ascent() / fontScale + letterSpacing;
2020 textp.begin( &textPict );
2021 textp.setPen( Qt::NoPen );
2024 textp.setBrush( textColor );
2025 textp.scale( 1 / fontScale, 1 / fontScale );
2026 textp.drawPath( path );
2036 subComponent.picture = textPict;
2037 subComponent.pictureBuffer = 0.0;
2038 subComponent.origin = QPointF( 0.0, fragmentYOffset );
2039 const double prevY = subComponent.offset.y();
2040 subComponent.offset = QPointF( 0, -labelHeight );
2041 subComponent.useOrigin =
true;
2042 QgsTextRenderer::drawShadow( context, subComponent, format );
2043 subComponent.useOrigin =
false;
2044 subComponent.offset = QPointF( 0, prevY );
2054 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
2058 case Qgis::TextRenderFormat::AlwaysOutlines:
2061 _fixQPictureDPI( context.
painter() );
2062 context.
painter()->drawPicture( 0, fragmentYOffset, textPict );
2063 fragmentYOffset += partYOffset;
2067 case Qgis::TextRenderFormat::AlwaysText:
2069 context.
painter()->setFont( fragmentFont );
2070 context.
painter()->setPen( textColor );
2071 context.
painter()->setRenderHint( QPainter::TextAntialiasing );
2073 double partYOffset = 0.0;
2074 for (
const QString &part : parts )
2076 double partXOffset = ( labelWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
2077 context.
painter()->scale( 1 / fontScale, 1 / fontScale );
2078 context.
painter()->drawText( partXOffset * fontScale, ( fragmentYOffset + partYOffset ) * fontScale, part );
2079 context.
painter()->scale( fontScale, fontScale );
2080 partYOffset += fragmentMetrics.ascent() / fontScale + letterSpacing;
2082 fragmentYOffset += partYOffset;
2089 maskPainter->restore();
2104 if ( pixelSize < 50 )
2108 else if ( pixelSize > 200 )
2109 return 200 / pixelSize;
@ ApplyScalingWorkaroundForTextRendering
Whether a scaling workaround designed to stablise the rendering of small font sizes (or for painters ...
@ WrapLines
Automatically wrap long lines of text.
A class to manager painter saving and restoring required for effect drawing.
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
QgsFields fields() const
Convenience function for retrieving the fields for the context, if set.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
QgsFillSymbol * clone() const override
Returns a deep copy of this symbol.
Struct for storing maximum and minimum scales for measurements in map units.
A marker symbol type, for rendering Point and MultiPoint geometries.
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
bool enabled() const
Returns whether the effect is enabled.
A class to manage painter saving and restoring required for drawing on a different painter (mask pain...
static QStringList splitToGraphemes(const QString &text)
Splits a text string to a list of graphemes, which are the smallest allowable character divisions in ...
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
QPainter * maskPainter(int id=0)
Returns a mask QPainter for the render operation.
bool useAdvancedEffects() const
Returns true if advanced effects such as blend modes such be used.
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
bool isGuiPreview() const
Returns the Gui preview mode.
Qgis::TextRenderFormat textRenderFormat() const
Returns the text render format, which dictates how text is rendered (e.g.
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
int currentMaskId() const
Returns the current mask id, which can be used with maskPainter()
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
Scoped object for saving and restoring a QPainter object's state.
Scoped object for temporary override of the symbologyReferenceScale property of a QgsRenderContext.
static QString substituteVerticalCharacters(QString string)
Returns a string with characters having vertical representation form substituted.
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates the symbol.
void renderPoint(QPointF point, QgsSymbolRenderContext &context) override
Renders a marker at the specified point.
static void blurImageInPlace(QImage &image, QRect rect, int radius, bool alphaOnly)
Blurs an image in place, e.g. creating Qt-independent drop shadows.
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
Container for settings relating to a text background object.
QgsMapUnitScale strokeWidthMapUnitScale() const
Returns the map unit scale object for the shape stroke width.
RotationType rotationType() const
Returns the method used for rotating the background shape.
QString svgFile() const
Returns the absolute path to the background SVG file, if set.
QSizeF size() const
Returns the size of the background shape.
QSizeF radii() const
Returns the radii used for rounding the corners of shapes.
QgsMapUnitScale radiiMapUnitScale() const
Returns the map unit scale object for the shape radii.
QgsUnitTypes::RenderUnit strokeWidthUnit() const
Returns the units used for the shape's stroke width.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the background shape.
@ SizeBuffer
Shape size is determined by adding a buffer margin around text.
bool enabled() const
Returns whether the background is enabled.
double opacity() const
Returns the background shape's opacity.
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units used for the shape's offset.
double rotation() const
Returns the rotation for the background shape, in degrees clockwise.
QColor fillColor() const
Returns the color used for filing the background shape.
SizeType sizeType() const
Returns the method used to determine the size of the background shape (e.g., fixed size or buffer aro...
ShapeType type() const
Returns the type of background shape (e.g., square, ellipse, SVG).
double strokeWidth() const
Returns the width of the shape's stroke (stroke).
@ ShapeMarkerSymbol
Marker symbol.
@ ShapeSquare
Square - buffered sizes only.
@ ShapeRectangle
Rectangle.
QColor strokeColor() const
Returns the color used for outlining the background shape.
QgsFillSymbol * fillSymbol() const
Returns the fill symbol to be rendered in the background.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the shape size.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units used for the shape's size.
@ RotationOffset
Shape rotation is offset from text rotation.
@ RotationFixed
Shape rotation is a fixed angle.
QgsUnitTypes::RenderUnit radiiUnit() const
Returns the units used for the shape's radii.
QgsMarkerSymbol * markerSymbol() const
Returns the marker symbol to be rendered in the background.
const QgsPaintEffect * paintEffect() const
Returns the current paint effect for the background shape.
QgsMapUnitScale offsetMapUnitScale() const
Returns the map unit scale object for the shape offset.
QPointF offset() const
Returns the offset used for drawing the background shape.
Represents a block of text consisting of one or more QgsTextFragment objects.
int size() const
Returns the number of fragments in the block.
QString toPlainText() const
Converts the block to plain text.
Container for settings relating to a text buffer.
Qt::PenJoinStyle joinStyle() const
Returns the buffer join style.
double size() const
Returns the size of the buffer.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the buffer size.
bool enabled() const
Returns whether the buffer is enabled.
double opacity() const
Returns the buffer opacity.
bool fillBufferInterior() const
Returns whether the interior of the buffer will be filled in.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the buffer size.
const QgsPaintEffect * paintEffect() const
Returns the current paint effect for the buffer.
QColor color() const
Returns the color of the buffer.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the buffer.
QColor textColor() const
Returns the character's text color, or an invalid color if no color override is set and the default f...
void updateFontForFormat(QFont &font, double scaleFactor=1.0) const
Updates the specified font in place, applying character formatting options which are applicable on a ...
Represents a document consisting of one or more QgsTextBlock objects.
const QgsTextBlock & at(int index) const
Returns the block at the specified index.
QStringList toPlainText() const
Returns a list of plain text lines of text representing the document.
int size() const
Returns the number of blocks in the document.
static QgsTextDocument fromHtml(const QStringList &lines)
Constructor for QgsTextDocument consisting of a set of HTML formatted lines.
static QgsTextDocument fromPlainText(const QStringList &lines)
Constructor for QgsTextDocument consisting of a set of plain text lines.
void applyCapitalization(Qgis::Capitalization capitalization)
Applies a capitalization style to the document's text.
Container for all settings relating to text rendering.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the size.
double lineHeight() const
Returns the line height for text.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the size of rendered text.
void updateDataDefinedProperties(QgsRenderContext &context)
Updates the format by evaluating current values of data defined properties.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the format's property collection, used for data defined overrides.
QFont scaledFont(const QgsRenderContext &context, double scaleFactor=1.0, bool *isZeroSize=nullptr) const
Returns a font with the size scaled to match the format's size settings (including units and map unit...
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the text.
TextOrientation orientation() const
Returns the orientation of the text.
Qgis::Capitalization capitalization() const
Returns the text capitalization style.
QgsTextMaskSettings & mask()
Returns a reference to the masking settings.
QgsTextBackgroundSettings & background()
Returns a reference to the text background settings.
TextOrientation
Text orientation.
@ HorizontalOrientation
Vertically oriented text.
@ RotationBasedOrientation
Horizontally or vertically oriented text based on rotation (only available for map labeling)
@ VerticalOrientation
Horizontally oriented text.
bool allowHtmlFormatting() const
Returns true if text should be treated as a HTML document and HTML tags should be used for formatting...
double opacity() const
Returns the text's opacity.
double size() const
Returns the size for rendered text.
QgsTextShadowSettings & shadow()
Returns a reference to the text drop shadow settings.
QColor color() const
Returns the color that text will be rendered in.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
Stores a fragment of text along with formatting overrides to be used when rendering the fragment.
QString text() const
Returns the text content of the fragment.
double horizontalAdvance(const QFont &font, bool fontHasBeenUpdatedForFragment=false, double scaleFactor=1.0) const
Returns the horizontal advance associated with this fragment, when rendered using the specified base ...
const QgsTextCharacterFormat & characterFormat() const
Returns the character formatting for the fragment.
Container for settings relating to a selective masking around a text.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the buffer size.
double size() const
Returns the size of the buffer.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the mask.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the buffer size.
double opacity() const
Returns the mask's opacity.
bool enabled() const
Returns whether the mask is enabled.
Qt::PenJoinStyle joinStyle() const
Returns the buffer join style.
static double textWidth(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, QFontMetricsF *fontMetrics=nullptr)
Returns the width of a text based on a given format.
static Q_DECL_DEPRECATED void drawPart(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, TextPart part, bool drawAsOutlines=true)
Draws a single component of rendered text using the specified settings.
VAlignment
Vertical alignment.
@ AlignBottom
Align to bottom.
@ AlignVCenter
Center align.
TextPart
Components of text.
@ Buffer
Buffer component.
@ Background
Background shape.
static void drawText(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, VAlignment vAlignment=AlignTop, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags())
Draws text within a rectangle using the specified settings.
static bool textRequiresWrapping(const QgsRenderContext &context, const QString &text, double width, const QgsTextFormat &format)
Returns true if the specified text requires line wrapping in order to fit within the specified width ...
HAlignment
Horizontal alignment.
@ AlignCenter
Center align.
@ AlignJustify
Justify align.
static QFontMetricsF fontMetrics(QgsRenderContext &context, const QgsTextFormat &format, double scaleFactor=1.0)
Returns the font metrics for the given text format, when rendered in the specified render context.
static HAlignment convertQtHAlignment(Qt::Alignment alignment)
Converts a Qt horizontal alignment flag to a QgsTextRenderer::HAlignment value.
static int sizeToPixel(double size, const QgsRenderContext &c, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale())
Calculates pixel size (considering output size should be in pixel or map units, scale factors and opt...
static QStringList wrappedText(const QgsRenderContext &context, const QString &text, double width, const QgsTextFormat &format)
Wraps a text string to multiple lines, such that each individual line will fit within the specified w...
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, DrawMode mode=Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
static VAlignment convertQtVAlignment(Qt::Alignment alignment)
Converts a Qt vertical alignment flag to a QgsTextRenderer::VAlignment value.
DrawMode
Draw mode to calculate width and height.
@ Point
Text at point of origin draw mode.
@ Rect
Text within rectangle draw mode.
@ Label
Label-specific draw mode.
static constexpr double FONT_WORKAROUND_SCALE
Scale factor for upscaling font sizes and downscaling destination painter devices.
Container for settings relating to a text shadow.
int offsetAngle() const
Returns the angle for offsetting the position of the shadow from the text.
bool enabled() const
Returns whether the shadow is enabled.
int scale() const
Returns the scaling used for the drop shadow (in percentage of original size).
void setShadowPlacement(QgsTextShadowSettings::ShadowPlacement placement)
Sets the placement for the drop shadow.
double opacity() const
Returns the shadow's opacity.
QgsMapUnitScale blurRadiusMapUnitScale() const
Returns the map unit scale object for the shadow blur radius.
QColor color() const
Returns the color of the drop shadow.
@ ShadowBuffer
Draw shadow under buffer.
@ ShadowShape
Draw shadow under background shape.
@ ShadowLowest
Draw shadow below all text components.
@ ShadowText
Draw shadow under text.
QgsTextShadowSettings::ShadowPlacement shadowPlacement() const
Returns the placement for the drop shadow.
double offsetDistance() const
Returns the distance for offsetting the position of the shadow from the text.
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing the drop shadow.
QgsMapUnitScale offsetMapUnitScale() const
Returns the map unit scale object for the shadow offset distance.
QgsUnitTypes::RenderUnit blurRadiusUnit() const
Returns the units used for the shadow's blur radius.
bool blurAlphaOnly() const
Returns whether only the alpha channel for the shadow will be blurred.
bool offsetGlobal() const
Returns true if the global shadow offset will be used.
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units used for the shadow's offset.
double blurRadius() const
Returns the blur radius for the shadow.
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
RenderUnit
Rendering size units.
@ RenderUnknownUnit
Mixed or unknown units.
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
@ RenderMapUnits
Map units.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< QgsSymbolLayer * > QgsSymbolLayerList
Q_GUI_EXPORT int qt_defaultDpiX()
Q_GUI_EXPORT int qt_defaultDpiY()