35#include <QTextBoundaryFinder>
40static void _fixQPictureDPI( QPainter *p )
46 p->scale(
static_cast< double >(
qt_defaultDpiX() ) / p->device()->logicalDpiX(),
47 static_cast< double >(
qt_defaultDpiY() ) / p->device()->logicalDpiY() );
52 if ( alignment & Qt::AlignLeft )
54 else if ( alignment & Qt::AlignRight )
56 else if ( alignment & Qt::AlignHCenter )
58 else if ( alignment & Qt::AlignJustify )
67 if ( alignment & Qt::AlignTop )
69 else if ( alignment & Qt::AlignBottom )
71 else if ( alignment & Qt::AlignVCenter )
74 else if ( alignment & Qt::AlignBaseline )
82 return static_cast< int >(
c.convertToPainterUnits( size, unit, mapUnitScale ) + 0.5 );
94 QStringList textLines;
95 for (
const QString &line : text )
99 textLines.append(
wrappedText( context, line, rect.width(), lFormat ) );
103 textLines.append( line );
110 const double fontScale = calculateScaleFactorForFormat( context, lFormat );
113 drawDocument( rect, lFormat, document, metrics, context, alignment, vAlignment, rotation, mode, flags );
118 const QgsTextFormat tmpFormat = updateShadowPosition( format );
138 lFormat = updateShadowPosition( lFormat );
143 const double fontScale = calculateScaleFactorForFormat( context, lFormat );
164 lFormat = updateShadowPosition( lFormat );
172 drawDocumentOnLine( line, lFormat, document, context, offsetAlongLine, offsetFromLine );
177 QPolygonF labelBaselineCurve = line;
186#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
187 if ( offsetFromLine < 0 )
190 std::unique_ptr < QgsLineString > reversed( offsetCurve->reversed() );
194 offsetCurve = std::move( reversed );
198 labelBaselineCurve = offsetCurve->asQPolygonF();
201 const double fontScale = calculateScaleFactorForFormat( context, format );
203 const QFont baseFont = format.
scaledFont( context, fontScale );
204 const double letterSpacing = baseFont.letterSpacing() / fontScale;
205 const double wordSpacing = baseFont.wordSpacing() / fontScale;
207 QStringList graphemes;
208 QVector< QgsTextCharacterFormat > graphemeFormats;
209 QVector< QgsTextDocument > graphemeDocuments;
210 QVector< QgsTextDocumentMetrics > graphemeMetrics;
212 for (
const QgsTextBlock &block : std::as_const( document ) )
217 for (
const QString &grapheme : fragmentGraphemes )
219 graphemes.append( grapheme );
220 graphemeFormats.append( fragment.characterFormat() );
225 graphemeDocuments.append( document );
231 QVector< double > characterWidths( graphemes.count() );
232 QVector< double > characterHeights( graphemes.count() );
233 QVector< double > characterDescents( graphemes.count() );
234 QFont previousNonSuperSubScriptFont;
236 for (
int i = 0; i < graphemes.count(); i++ )
241 double graphemeFirstCharHorizontalAdvanceWithLetterSpacing = 0;
242 double graphemeFirstCharHorizontalAdvance = 0;
243 double graphemeHorizontalAdvance = 0;
244 double characterDescent = 0;
245 double characterHeight = 0;
248 QFont graphemeFont = baseFont;
252 previousNonSuperSubScriptFont = graphemeFont;
259 previousNonSuperSubScriptFont = graphemeFont;
280 previousNonSuperSubScriptFont = graphemeFont;
283 const QFontMetricsF graphemeFontMetrics( graphemeFont );
284 graphemeFirstCharHorizontalAdvance = graphemeFontMetrics.horizontalAdvance( QString( graphemes[i].at( 0 ) ) ) / fontScale;
285 graphemeFirstCharHorizontalAdvanceWithLetterSpacing = graphemeFontMetrics.horizontalAdvance( graphemes[i].at( 0 ) ) / fontScale + letterSpacing;
286 graphemeHorizontalAdvance = graphemeFontMetrics.horizontalAdvance( QString( graphemes[i] ) ) / fontScale;
287 characterDescent = graphemeFontMetrics.descent() / fontScale;
288 characterHeight = graphemeFontMetrics.height() / fontScale;
290 qreal wordSpaceFix = qreal( 0.0 );
291 if ( graphemes[i] == QLatin1String(
" " ) )
295 wordSpaceFix = ( nxt < graphemes.count() && graphemes[nxt] != QLatin1String(
" " ) ) ? wordSpacing : qreal( 0.0 );
300 if ( graphemes[i].length() == 1 &&
301 !
qgsDoubleNear( graphemeFirstCharHorizontalAdvance, graphemeFirstCharHorizontalAdvanceWithLetterSpacing ) )
304 wordSpaceFix -= wordSpacing;
307 const double charWidth = graphemeHorizontalAdvance + wordSpaceFix;
308 characterWidths[i] = charWidth;
309 characterHeights[i] = characterHeight;
310 characterDescents[i] = characterDescent;
313 QgsPrecalculatedTextMetrics metrics( graphemes, std::move( characterWidths ), std::move( characterHeights ), std::move( characterDescents ) );
317 metrics, labelBaselineCurve, offsetAlongLine,
324 if ( placement->graphemePlacement.empty() )
327 std::vector< QgsTextRenderer::Component > components;
328 components.reserve( placement->graphemePlacement.size() );
331 QgsTextRenderer::Component component;
332 component.origin = QPointF( grapheme.x, grapheme.y );
333 component.rotation = -grapheme.angle;
339 component.origin.rx() += verticalOffset * std::cos( grapheme.angle + M_PI_2 );
340 component.origin.ry() += verticalOffset * std::sin( grapheme.angle + M_PI_2 );
343 components.emplace_back( component );
351 const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
360 const QgsTextDocument &document = graphemeDocuments.
at( grapheme.graphemeIndex );
362 const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
378 const QgsTextDocument &document = graphemeDocuments.
at( grapheme.graphemeIndex );
380 const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
419 const double fontScale = calculateScaleFactorForFormat( context, format );
433 component.dpiRatio = 1.0;
434 component.origin = rect.topLeft();
435 component.rotation = rotation;
436 component.size = rect.size();
437 component.hAlign = alignment;
450 double xc = rect.width() / 2.0;
451 double yc = rect.height() / 2.0;
453 double angle = -rotation;
454 double xd = xc * std::cos( angle ) - yc * std::sin( angle );
455 double yd = xc * std::sin( angle ) + yc * std::cos( angle );
457 component.center = QPointF( component.origin.x() + xd, component.origin.y() + yd );
461 component.center = rect.center();
464 switch ( vAlignment )
490 drawTextInternal( part, context, format, component,
492 alignment, vAlignment, mode );
501 const double fontScale = calculateScaleFactorForFormat( context, format );
515 component.dpiRatio = 1.0;
516 component.origin = origin;
517 component.rotation = rotation;
518 component.hAlign = alignment;
527 QgsTextRenderer::drawBackground( context, component, format, metrics, mode );
540 drawTextInternal( part, context, format, component,
552 return QFontMetricsF( format.
scaledFont( context, scaleFactor ), context.
painter() ? context.
painter()->device() : nullptr );
559 QPainter *p = context.
painter();
564 if ( component.rotation >= -315 && component.rotation < -90 )
568 else if ( component.rotation >= -90 && component.rotation < -45 )
584 const double scaleFactor = calculateScaleFactorForFormat( context, format );
586 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
597 referenceScaleOverride.reset();
600 path.setFillRule( Qt::WindingFill );
602 double height = component.size.height();
603 switch ( orientation )
608 int fragmentIndex = 0;
611 QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, fragmentIndex );
613 if ( !fragment.isWhitespace() )
615 if ( component.extraWordSpacing || component.extraLetterSpacing )
616 applyExtraSpacingForLineJustification( fragmentFont, component.extraWordSpacing, component.extraLetterSpacing );
619 path.addText( xOffset, yOffset, fragmentFont, fragment.text() );
633 double partYOffset = component.offset.y() * scaleFactor;
636 double partLastDescent = 0;
638 int fragmentIndex = 0;
641 const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, component.firstFragmentIndex + fragmentIndex );
642 const double letterSpacing = fragmentFont.letterSpacing() / scaleFactor;
644 const QFontMetricsF fragmentMetrics( fragmentFont );
646 const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode );
649 for (
const QString &part : parts )
651 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / scaleFactor - letterSpacing ) ) / 2;
652 partYOffset += fragmentMetrics.ascent() / scaleFactor;
653 path.addText( partXOffset, partYOffset + fragmentYOffset, fragmentFont, part );
654 partYOffset += letterSpacing;
656 partLastDescent = fragmentMetrics.descent() / scaleFactor;
660 height = partYOffset + partLastDescent;
661 advance = partYOffset - component.offset.y() * scaleFactor;
666 QColor bufferColor = buffer.
color();
667 bufferColor.setAlphaF( buffer.
opacity() );
668 QPen pen( bufferColor );
669 pen.setWidthF( penSize * scaleFactor );
671 QColor tmpColor( bufferColor );
675 tmpColor.setAlpha( 0 );
681 buffp.begin( &buffPict );
685 std::unique_ptr< QgsPaintEffect > tmpEffect( buffer.
paintEffect()->
clone() );
687 tmpEffect->begin( context );
688 context.
painter()->setPen( pen );
689 context.
painter()->setBrush( tmpColor );
690 if ( scaleFactor != 1.0 )
691 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
692 context.
painter()->drawPath( path );
693 if ( scaleFactor != 1.0 )
694 context.
painter()->scale( scaleFactor, scaleFactor );
695 tmpEffect->end( context );
701 if ( scaleFactor != 1.0 )
702 buffp.scale( 1 / scaleFactor, 1 / scaleFactor );
704 buffp.setBrush( tmpColor );
705 buffp.drawPath( path );
711 QgsTextRenderer::Component bufferComponent = component;
712 bufferComponent.origin = QPointF( 0.0, 0.0 );
713 bufferComponent.picture = buffPict;
714 bufferComponent.pictureBuffer = penSize / 2.0;
715 bufferComponent.size.setHeight( height );
719 bufferComponent.offset.setY( - bufferComponent.size.height() );
721 drawShadow( context, bufferComponent, format );
729 p->setCompositionMode( buffer.
blendMode() );
733 p->scale( component.dpiRatio, component.dpiRatio );
734 _fixQPictureDPI( p );
735 p->drawPicture( 0, 0, buffPict );
737 return advance / scaleFactor;
757 path.setFillRule( Qt::WindingFill );
759 const double scaleFactor = calculateScaleFactorForFormat( context, format );
764 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
775 referenceScaleOverride.reset();
778 int fragmentIndex = 0;
781 if ( !fragment.isWhitespace() )
783 const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, fragmentIndex );
785 const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode );
786 path.addText( xOffset, fragmentYOffset, fragmentFont, fragment.text() );
793 QColor bufferColor( Qt::gray );
794 bufferColor.setAlphaF( mask.
opacity() );
798 brush.setColor( bufferColor );
799 pen.setColor( bufferColor );
800 pen.setWidthF( penSize * scaleFactor );
807 p->scale( component.dpiRatio, component.dpiRatio );
813 if ( scaleFactor != 1.0 )
814 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
815 context.
painter()->setPen( pen );
816 context.
painter()->setBrush( brush );
817 context.
painter()->drawPath( path );
818 if ( scaleFactor != 1.0 )
819 context.
painter()->scale( scaleFactor, scaleFactor );
824 if ( scaleFactor != 1.0 )
825 p->scale( 1 / scaleFactor, 1 / scaleFactor );
827 p->setBrush( brush );
829 if ( scaleFactor != 1.0 )
830 p->scale( scaleFactor, scaleFactor );
846 if ( doc.
size() == 0 )
850 return textWidth( context, format, doc );
856 const double scaleFactor = calculateScaleFactorForFormat( context, format );
867 for (
const QString &line : textLines )
871 lines.append(
wrappedText( context, line, maxLineWidth, format ) );
875 lines.append( line );
891 const double scaleFactor = calculateScaleFactorForFormat( context, format );
893 bool isNullSize =
false;
894 const QFont baseFont = format.
scaledFont( context, scaleFactor, &isNullSize );
898 const QFontMetrics fm( baseFont );
899 const double height = ( character.isNull() ? fm.height() : fm.boundingRect( character ).height() ) / scaleFactor;
901 if ( !includeEffects )
904 double maxExtension = 0;
933 return height + maxExtension;
941 const QStringList multiLineSplit = text.split(
'\n' );
943 return currentTextWidth > width;
948 const QStringList lines = text.split(
'\n' );
949 QStringList outLines;
950 for (
const QString &line : lines )
955 const QStringList words = line.split(
' ' );
956 QStringList linesToProcess;
957 QString wordsInCurrentLine;
958 for (
const QString &word : words )
963 if ( !wordsInCurrentLine.isEmpty() )
964 linesToProcess << wordsInCurrentLine;
965 wordsInCurrentLine.clear();
966 linesToProcess << word;
970 if ( !wordsInCurrentLine.isEmpty() )
971 wordsInCurrentLine.append(
' ' );
972 wordsInCurrentLine.append( word );
975 if ( !wordsInCurrentLine.isEmpty() )
976 linesToProcess << wordsInCurrentLine;
978 for (
const QString &line : std::as_const( linesToProcess ) )
980 QString remainingText = line;
981 int lastPos = remainingText.lastIndexOf(
' ' );
982 while ( lastPos > -1 )
992 outLines << remainingText.left( lastPos );
993 remainingText = remainingText.mid( lastPos + 1 );
996 lastPos = remainingText.lastIndexOf(
' ', lastPos - 1 );
998 outLines << remainingText;
1016 const double scaleFactor = calculateScaleFactorForFormat( context, format );
1029 QPainter *prevP = context.
painter();
1030 QPainter *p = context.
painter();
1031 std::unique_ptr< QgsPaintEffect > tmpEffect;
1035 tmpEffect->begin( context );
1044 const double originAdjustRotationRadians = -component.rotation;
1047 component.rotation = -( component.rotation * 180 / M_PI );
1048 component.rotationOffset =
1053 component.rotation = 0.0;
1054 component.rotationOffset = background.
rotation();
1057 const double scaleFactor = calculateScaleFactorForFormat( context, format );
1063 double width = documentSize.width();
1064 double height = documentSize.height();
1071 switch ( component.hAlign )
1075 component.center = QPointF( component.origin.x() + width / 2.0,
1076 component.origin.y() + height / 2.0 );
1080 component.center = QPointF( component.origin.x() + component.size.width() / 2.0,
1081 component.origin.y() + height / 2.0 );
1085 component.center = QPointF( component.origin.x() + component.size.width() - width / 2.0,
1086 component.origin.y() + height / 2.0 );
1093 bool isNullSize =
false;
1094 QFontMetricsF fm( format.
scaledFont( context, scaleFactor, &isNullSize ) );
1095 double originAdjust = isNullSize ? 0 : ( fm.ascent() / scaleFactor / 2.0 - fm.leading() / scaleFactor / 2.0 );
1096 switch ( component.hAlign )
1100 component.center = QPointF( component.origin.x() + width / 2.0,
1101 component.origin.y() - height / 2.0 + originAdjust );
1105 component.center = QPointF( component.origin.x(),
1106 component.origin.y() - height / 2.0 + originAdjust );
1110 component.center = QPointF( component.origin.x() - width / 2.0,
1111 component.origin.y() - height / 2.0 + originAdjust );
1118 const double dx = component.center.x() - component.origin.x();
1119 const double dy = component.center.y() - component.origin.y();
1120 component.center.setX( component.origin.x() + ( std::cos( originAdjustRotationRadians ) * dx - std::sin( originAdjustRotationRadians ) * dy ) );
1121 component.center.setY( component.origin.y() + ( std::sin( originAdjustRotationRadians ) * dx + std::cos( originAdjustRotationRadians ) * dy ) );
1131 component.size = QSizeF( width, height );
1136 switch ( background.
type() )
1149 double sizeOut = 0.0;
1160 sizeOut = std::max( component.size.width(), component.size.height() );
1164 sizeOut += bufferSize * 2;
1170 if ( sizeOut < 1.0 )
1173 std::unique_ptr< QgsMarkerSymbol > renderedSymbol;
1177 map[QStringLiteral(
"name" )] = background.
svgFile().trimmed();
1178 map[QStringLiteral(
"size" )] = QString::number( sizeOut );
1180 map[QStringLiteral(
"angle" )] = QString::number( 0.0 );
1188 map[QStringLiteral(
"fill" )] = background.
fillColor().name();
1189 map[QStringLiteral(
"outline" )] = background.
strokeColor().name();
1190 map[QStringLiteral(
"outline-width" )] = QString::number( background.
strokeWidth() );
1197 QVariantMap shdwmap( map );
1198 shdwmap[QStringLiteral(
"fill" )] = shadow.
color().name();
1199 shdwmap[QStringLiteral(
"outline" )] = shadow.
color().name();
1200 shdwmap[QStringLiteral(
"size" )] = QString::number( sizeOut );
1205 svgp.begin( &svgPict );
1222 svgShdwM->
renderPoint( QPointF( sizeOut / 2, -sizeOut / 2 ), svgShdwContext );
1225 component.picture = svgPict;
1227 component.pictureBuffer = 0.0;
1229 component.size = QSizeF( sizeOut, sizeOut );
1230 component.offset = QPointF( 0.0, 0.0 );
1236 p->translate( component.center.x(), component.center.y() );
1237 p->rotate( component.rotation );
1240 p->translate( QPointF( xoff, yoff ) );
1241 p->rotate( component.rotationOffset );
1242 p->translate( -sizeOut / 2, sizeOut / 2 );
1244 drawShadow( context, component, format );
1246 renderedSymbol.reset( );
1254 renderedSymbol->setSize( sizeOut );
1258 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1266 p->setCompositionMode( background.
blendMode() );
1268 p->translate( component.center.x(), component.center.y() );
1269 p->rotate( component.rotation );
1272 p->translate( QPointF( xoff, yoff ) );
1273 p->rotate( component.rotationOffset );
1277 renderedSymbol->renderPoint( QPointF( 0, 0 ), &f, context );
1278 renderedSymbol->stopRender( context );
1279 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1289 double w = component.size.width();
1290 double h = component.size.height();
1311 h = std::sqrt( std::pow( w, 2 ) + std::pow( h, 2 ) );
1317 h = h * M_SQRT1_2 * 2;
1318 w = w * M_SQRT1_2 * 2;
1326 w += bufferWidth * 2;
1327 h += bufferHeight * 2;
1331 QRectF rect( -w / 2.0, - h / 2.0, w, h );
1333 if ( rect.isNull() )
1339 p->translate( QPointF( component.center.x(), component.center.y() ) );
1340 p->rotate( component.rotation );
1343 p->translate( QPointF( xoff, yoff ) );
1344 p->rotate( component.rotationOffset );
1350 QTransform t = QTransform::fromScale( 10, 10 );
1352 QTransform ti = t.inverted();
1359 path.addRoundedRect( rect, background.
radii().width(), background.
radii().height(), Qt::RelativeSize );
1365 path.addRoundedRect( rect, xRadius, yRadius );
1371 path.addEllipse( rect );
1373 QPolygonF tempPolygon = path.toFillPolygon( t );
1374 QPolygonF polygon = ti.map( tempPolygon );
1376 QPainter *oldp = context.
painter();
1379 shapep.begin( &shapePict );
1382 std::unique_ptr< QgsFillSymbol > renderedSymbol;
1384 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1388 renderedSymbol->renderPolygon( polygon,
nullptr, &f, context );
1389 renderedSymbol->stopRender( context );
1396 component.picture = shapePict;
1399 component.size = rect.size();
1400 component.offset = QPointF( rect.width() / 2, -rect.height() / 2 );
1401 drawShadow( context, component, format );
1406 p->setCompositionMode( background.
blendMode() );
1410 p->scale( component.dpiRatio, component.dpiRatio );
1411 _fixQPictureDPI( p );
1412 p->drawPicture( 0, 0, shapePict );
1413 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1420 tmpEffect->end( context );
1433 QPainter *p = context.
painter();
1434 const double componentWidth = component.size.width();
1435 const double componentHeight = component.size.height();
1436 double xOffset = component.offset.x(), yOffset = component.offset.y();
1437 double pictbuffer = component.pictureBuffer;
1446 radius /= ( mapUnits ? context.
scaleFactor() / component.dpiRatio : 1 );
1447 radius =
static_cast< int >( radius + 0.5 );
1451 double blurBufferClippingScale = 3.75;
1452 int blurbuffer = ( radius > 17 ? 16 : radius ) * blurBufferClippingScale;
1454 QImage blurImg( componentWidth + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1455 componentHeight + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1456 QImage::Format_ARGB32_Premultiplied );
1460 int minBlurImgSize = 1;
1464 int maxBlurImgSize = 40000;
1465 if ( blurImg.isNull()
1466 || ( blurImg.width() < minBlurImgSize || blurImg.height() < minBlurImgSize )
1467 || ( blurImg.width() > maxBlurImgSize || blurImg.height() > maxBlurImgSize ) )
1470 blurImg.fill( QColor( Qt::transparent ).rgba() );
1472 if ( !pictp.begin( &blurImg ) )
1474 pictp.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
1475 QPointF imgOffset( blurbuffer + pictbuffer + xOffset,
1476 blurbuffer + pictbuffer + componentHeight + yOffset );
1478 pictp.drawPicture( imgOffset,
1479 component.picture );
1482 pictp.setCompositionMode( QPainter::CompositionMode_SourceIn );
1483 pictp.fillRect( blurImg.rect(), shadow.
color() );
1487 if ( shadow.
blurRadius() > 0.0 && radius > 0 )
1495 picti.begin( &blurImg );
1496 picti.setBrush( Qt::Dense7Pattern );
1497 QPen imgPen( QColor( 0, 0, 255, 255 ) );
1498 imgPen.setWidth( 1 );
1499 picti.setPen( imgPen );
1500 picti.setOpacity( 0.1 );
1501 picti.drawRect( 0, 0, blurImg.width(), blurImg.height() );
1508 double angleRad = shadow.
offsetAngle() * M_PI / 180;
1516 angleRad -= ( component.rotation * M_PI / 180 + component.rotationOffset * M_PI / 180 );
1519 QPointF transPt( -offsetDist * std::cos( angleRad + M_PI_2 ),
1520 -offsetDist * std::sin( angleRad + M_PI_2 ) );
1526 p->setRenderHint( QPainter::SmoothPixmapTransform );
1529 p->setCompositionMode( shadow.
blendMode() );
1531 p->setOpacity( shadow.
opacity() );
1533 double scale = shadow.
scale() / 100.0;
1535 p->scale( scale, scale );
1536 if ( component.useOrigin )
1538 p->translate( component.origin.x(), component.origin.y() );
1540 p->translate( transPt );
1541 p->translate( -imgOffset.x(),
1543 p->drawImage( 0, 0, blurImg );
1550 p->setBrush( Qt::NoBrush );
1551 QPen imgPen( QColor( 255, 0, 0, 10 ) );
1552 imgPen.setWidth( 2 );
1553 imgPen.setStyle( Qt::DashLine );
1554 p->setPen( imgPen );
1555 p->scale( scale, scale );
1556 if ( component.useOrigin() )
1558 p->translate( component.origin().x(), component.origin().y() );
1560 p->translate( transPt );
1561 p->translate( -imgOffset.x(),
1563 p->drawRect( 0, 0, blurImg.width(), blurImg.height() );
1568 p->setBrush( Qt::NoBrush );
1569 QPen componentRectPen( QColor( 0, 255, 0, 70 ) );
1570 componentRectPen.setWidth( 1 );
1571 if ( component.useOrigin() )
1573 p->translate( component.origin().x(), component.origin().y() );
1575 p->setPen( componentRectPen );
1576 p->drawRect( QRect( -xOffset, -componentHeight - yOffset, componentWidth, componentHeight ) );
1585 const Component &component,
1595 const double fontScale = calculateScaleFactorForFormat( context, format );
1597 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1608 referenceScaleOverride.reset();
1610 double rotation = 0;
1611 const Qgis::TextOrientation orientation = calculateRotationAndOrientationForComponent( format, component, rotation );
1612 switch ( orientation )
1616 drawTextInternalHorizontal( context, format, drawType, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
1623 drawTextInternalVertical( context, format, drawType, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
1629Qgis::TextOrientation QgsTextRenderer::calculateRotationAndOrientationForComponent(
const QgsTextFormat &format,
const QgsTextRenderer::Component &component,
double &rotation )
1631 rotation = -component.rotation * 180 / M_PI;
1638 if ( rotation >= -315 && rotation < -90 )
1643 else if ( rotation >= -90 && rotation < -45 )
1659void QgsTextRenderer::calculateExtraSpacingForLineJustification(
const double spaceToDistribute,
const QgsTextBlock &block,
double &extraWordSpace,
double &extraLetterSpace )
1662 QTextBoundaryFinder
finder( QTextBoundaryFinder::Word, blockText );
1664 int wordBoundaries = 0;
1665 while (
finder.toNextBoundary() != -1 )
1667 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1671 if ( wordBoundaries > 0 )
1674 extraWordSpace = spaceToDistribute / wordBoundaries;
1679 QTextBoundaryFinder
finder( QTextBoundaryFinder::Grapheme, blockText );
1682 int graphemeBoundaries = 0;
1683 while (
finder.toNextBoundary() != -1 )
1685 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1686 graphemeBoundaries++;
1689 if ( graphemeBoundaries > 0 )
1691 extraLetterSpace = spaceToDistribute / graphemeBoundaries;
1696void QgsTextRenderer::applyExtraSpacingForLineJustification( QFont &font,
double extraWordSpace,
double extraLetterSpace )
1698 const double prevWordSpace = font.wordSpacing();
1699 font.setWordSpacing( prevWordSpace + extraWordSpace );
1700 const double prevLetterSpace = font.letterSpacing();
1701 font.setLetterSpacing( QFont::AbsoluteSpacing, prevLetterSpace + extraLetterSpace );
1708 const QStringList textLines = document.
toPlainText();
1712 double labelWidest = 0.0;
1717 labelWidest = documentSize.width();
1723 labelWidest = component.size.width();
1727 double verticalAlignOffset = 0;
1733 const double overallHeight = documentSize.height();
1734 switch ( vAlignment )
1740 verticalAlignOffset = ( component.size.height() - overallHeight ) * 0.5;
1744 verticalAlignOffset = ( component.size.height() - overallHeight );
1752 const bool isFinalLineInParagraph = ( blockIndex == document.
size() - 1 )
1753 || document.
at( blockIndex + 1 ).
toPlainText().trimmed().isEmpty();
1755 const double blockHeight = metrics.
blockHeight( blockIndex );
1759 context.
painter()->translate( component.origin );
1761 context.
painter()->rotate( rotation );
1766 maskPainter->save();
1767 maskPainter->translate( component.origin );
1769 maskPainter->rotate( rotation );
1773 double xMultiLineOffset = 0.0;
1774 double blockWidth = metrics.
blockWidth( blockIndex );
1775 double extraWordSpace = 0;
1776 double extraLetterSpace = 0;
1777 if ( adjustForAlignment )
1779 double labelWidthDiff = 0;
1780 switch ( hAlignment )
1783 labelWidthDiff = ( labelWidest - blockWidth ) * 0.5;
1787 labelWidthDiff = labelWidest - blockWidth;
1791 if ( !isFinalLineInParagraph && labelWidest > blockWidth )
1793 calculateExtraSpacingForLineJustification( labelWidest - blockWidth, block, extraWordSpace, extraLetterSpace );
1794 blockWidth = labelWidest;
1808 xMultiLineOffset = labelWidthDiff;
1813 switch ( hAlignment )
1816 xMultiLineOffset = labelWidthDiff - labelWidest;
1820 xMultiLineOffset = labelWidthDiff - labelWidest / 2.0;
1832 const double baseLineOffset = metrics.
baselineOffset( blockIndex, mode );
1834 context.
painter()->translate( QPointF( xMultiLineOffset, baseLineOffset + verticalAlignOffset ) );
1836 maskPainter->translate( QPointF( xMultiLineOffset, baseLineOffset + verticalAlignOffset ) );
1838 Component subComponent;
1839 subComponent.block = block;
1840 subComponent.blockIndex = blockIndex;
1841 subComponent.
size = QSizeF( blockWidth, blockHeight );
1842 subComponent.offset = QPointF( 0.0, -metrics.
ascentOffset() );
1843 subComponent.rotation = -component.rotation * 180 / M_PI;
1844 subComponent.rotationOffset = 0.0;
1845 subComponent.extraWordSpacing = extraWordSpace * fontScale;
1846 subComponent.extraLetterSpacing = extraLetterSpace * fontScale;
1851 QgsTextRenderer::drawMask( context, subComponent, format, metrics, mode );
1856 QgsTextRenderer::drawBuffer( context, subComponent, format, metrics, mode );
1863 textp.begin( &textPict );
1864 textp.setPen( Qt::NoPen );
1866 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1874 referenceScaleOverride.reset();
1878 textp.scale( 1 / fontScale, 1 / fontScale );
1881 int fragmentIndex = 0;
1885 if ( !fragment.isWhitespace() )
1888 path.setFillRule( Qt::WindingFill );
1890 QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
1892 if ( extraWordSpace || extraLetterSpace )
1893 applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
1897 path.addText( xOffset, yOffset, fragmentFont, fragment.text() );
1899 QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
1900 textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.opacity() );
1901 textp.setBrush( textColor );
1902 textp.drawPath( path );
1913 subComponent.picture = textPict;
1914 subComponent.pictureBuffer = 0.0;
1915 subComponent.origin = QPointF( 0.0, 0.0 );
1917 QgsTextRenderer::drawShadow( context, subComponent, format );
1927 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
1934 _fixQPictureDPI( context.
painter() );
1935 context.
painter()->drawPicture( 0, 0, textPict );
1942 int fragmentIndex = 0;
1945 if ( !fragment.isWhitespace() )
1947 QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
1949 if ( extraWordSpace || extraLetterSpace )
1950 applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
1954 QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
1955 textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.opacity() );
1957 context.
painter()->setPen( textColor );
1958 context.
painter()->setFont( fragmentFont );
1959 context.
painter()->setRenderHint( QPainter::TextAntialiasing );
1961 context.
painter()->scale( 1 / fontScale, 1 / fontScale );
1962 context.
painter()->drawText( QPointF( xOffset, yOffset ), fragment.text() );
1963 context.
painter()->scale( fontScale, fontScale );
1973 maskPainter->restore();
1979void QgsTextRenderer::drawTextInternalVertical(
QgsRenderContext &context,
const QgsTextFormat &format,
Qgis::TextComponent drawType,
Qgis::TextLayoutMode mode,
const QgsTextRenderer::Component &component,
const QgsTextDocument &document,
const QgsTextDocumentMetrics &metrics,
double fontScale,
Qgis::TextHorizontalAlignment hAlignment,
Qgis::TextVerticalAlignment,
double rotation )
1982 const QStringList textLines = document.
toPlainText();
1984 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1995 referenceScaleOverride.reset();
1998 const double actualTextWidth = documentSize.width();
1999 double textRectWidth = 0.0;
2005 textRectWidth = actualTextWidth;
2011 textRectWidth = component.size.width();
2015 int maxLineLength = 0;
2016 for (
const QString &line : std::as_const( textLines ) )
2018 maxLineLength = std::max( maxLineLength,
static_cast<int>( line.length() ) );
2021 const double actualLabelHeight = documentSize.height();
2031 context.
painter()->translate( component.origin );
2033 context.
painter()->rotate( rotation );
2038 maskPainter->save();
2039 maskPainter->translate( component.origin );
2041 maskPainter->rotate( rotation );
2048 if ( adjustForAlignment )
2050 double hAlignmentOffset = 0;
2051 switch ( hAlignment )
2054 hAlignmentOffset = ( textRectWidth - actualTextWidth ) * 0.5;
2058 hAlignmentOffset = textRectWidth - actualTextWidth;
2072 xOffset += hAlignmentOffset;
2080 double yOffset = 0.0;
2086 if ( rotation >= -405 && rotation < -180 )
2090 else if ( rotation >= 0 && rotation < 45 )
2092 xOffset -= actualTextWidth;
2098 yOffset = -actualLabelHeight;
2103 yOffset = -actualLabelHeight;
2113 context.
painter()->translate( QPointF( xOffset, yOffset ) );
2115 double currentBlockYOffset = 0;
2116 int fragmentIndex = 0;
2124 const QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
2126 QFontMetricsF fragmentMetrics( fragmentFont );
2128 const double letterSpacing = fragmentFont.letterSpacing() / fontScale;
2129 const double labelHeight = fragmentMetrics.ascent() / fontScale + ( fragmentMetrics.ascent() / fontScale + letterSpacing ) * ( line.length() - 1 );
2131 Component subComponent;
2133 subComponent.blockIndex = blockIndex;
2134 subComponent.firstFragmentIndex = fragmentIndex;
2135 subComponent.size = QSizeF( blockMaximumCharacterWidth, labelHeight + fragmentMetrics.descent() / fontScale );
2136 subComponent.offset = QPointF( 0.0, currentBlockYOffset );
2137 subComponent.rotation = -component.rotation * 180 / M_PI;
2138 subComponent.rotationOffset = 0.0;
2145 QgsTextRenderer::drawMask( context, subComponent, format );
2151 currentBlockYOffset += QgsTextRenderer::drawBuffer( context, subComponent, format, metrics, mode );
2157 path.setFillRule( Qt::WindingFill );
2159 double partYOffset = 0.0;
2160 for (
const QString &part : parts )
2162 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
2163 partYOffset += fragmentMetrics.ascent() / fontScale;
2164 path.addText( partXOffset * fontScale, partYOffset * fontScale, fragmentFont, part );
2165 partYOffset += letterSpacing;
2171 textp.begin( &textPict );
2172 textp.setPen( Qt::NoPen );
2173 QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
2174 textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.
opacity() );
2175 textp.setBrush( textColor );
2176 textp.scale( 1 / fontScale, 1 / fontScale );
2177 textp.drawPath( path );
2188 subComponent.picture = textPict;
2189 subComponent.pictureBuffer = 0.0;
2190 subComponent.origin = QPointF( 0.0, currentBlockYOffset );
2191 const double prevY = subComponent.offset.y();
2192 subComponent.offset = QPointF( 0, -subComponent.size.height() );
2193 subComponent.useOrigin =
true;
2194 QgsTextRenderer::drawShadow( context, subComponent, format );
2195 subComponent.useOrigin =
false;
2196 subComponent.offset = QPointF( 0, prevY );
2206 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
2213 context.
painter()->translate( 0, currentBlockYOffset );
2214 _fixQPictureDPI( context.
painter() );
2215 context.
painter()->drawPicture( 0, 0, textPict );
2216 currentBlockYOffset += partYOffset;
2222 context.
painter()->setFont( fragmentFont );
2223 context.
painter()->setPen( textColor );
2224 context.
painter()->setRenderHint( QPainter::TextAntialiasing );
2226 double partYOffset = 0.0;
2227 for (
const QString &part : parts )
2229 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
2230 context.
painter()->scale( 1 / fontScale, 1 / fontScale );
2231 context.
painter()->drawText( QPointF( partXOffset * fontScale, ( currentBlockYOffset + partYOffset ) * fontScale ), part );
2232 context.
painter()->scale( fontScale, fontScale );
2233 partYOffset += fragmentMetrics.ascent() / fontScale + letterSpacing;
2235 currentBlockYOffset += partYOffset;
2243 maskPainter->restore();
2258 if ( pixelSize < 50 )
2262 else if ( pixelSize > 200 )
2263 return 200 / pixelSize;
TextLayoutMode
Text layout modes.
@ Labeling
Labeling-specific layout mode.
@ Point
Text at point of origin layout mode.
@ RectangleAscentBased
Similar to Rectangle mode, but uses ascents only when calculating font and line heights....
@ RectangleCapHeightBased
Similar to Rectangle mode, but uses cap height only when calculating font heights for the first line ...
@ Rectangle
Text within rectangle layout mode.
QFlags< TextRendererFlag > TextRendererFlags
TextOrientation
Text orientations.
@ Vertical
Vertically oriented text.
@ RotationBased
Horizontally or vertically oriented text based on rotation (only available for map labeling)
@ Horizontal
Horizontally oriented text.
@ Round
Use rounded joins.
@ Normal
Adjacent characters are positioned in the standard way for text in the writing system in use.
@ SubScript
Characters are placed below the base line for normal text.
@ SuperScript
Characters are placed above the base line for normal text.
@ AlwaysOutlines
Always render text using path objects (AKA outlines/curves). This setting guarantees the best quality...
@ AlwaysText
Always render text as text objects. While this mode preserves text objects as text for post-processin...
RenderUnit
Rendering size units.
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size)
@ Unknown
Mixed or unknown units.
@ ApplyScalingWorkaroundForTextRendering
Whether a scaling workaround designed to stablise the rendering of small font sizes (or for painters ...
TextVerticalAlignment
Text vertical alignment.
@ VerticalCenter
Center align.
TextHorizontalAlignment
Text horizontal alignment.
@ WrapLines
Automatically wrap long lines of text.
TextComponent
Text components.
@ Buffer
Buffer component.
@ Background
Background shape.
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.
Does vector analysis using the geos library and handles import, export, exception handling*.
Line string geometry type, with support for z-dimension and m-values.
static QgsLineString * fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
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.
bool enabled() const
Returns whether the effect is enabled.
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
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 ...
Contains precalculated properties regarding text metrics for text to be renderered at a later stage.
void setGraphemeFormats(const QVector< QgsTextCharacterFormat > &formats)
Sets the character formats associated with the text graphemes().
bool hasActiveProperties() const final
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.
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.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
QgsExpressionContext & expressionContext()
Gets the expression context.
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.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QPainter * maskPainter(int id=0)
Returns a mask QPainter for the render operation.
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.
Qgis::RenderUnit radiiUnit() const
Returns the units used for the shape's radii.
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.
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...
Qgis::RenderUnit strokeWidthUnit() const
Returns the units used for the shape's stroke width.
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.
Qgis::RenderUnit offsetUnit() const
Returns the units used for the shape's offset.
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.
Qgis::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.
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.
Qgis::RenderUnit sizeUnit() const
Returns the units for the buffer size.
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.
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.
Stores information relating to individual character formatting.
void updateFontForFormat(QFont &font, const QgsRenderContext &context, double scaleFactor=1.0) const
Updates the specified font in place, applying character formatting options which are applicable on a ...
Qgis::TextCharacterVerticalAlignment verticalAlignment() const
Returns the format vertical alignment.
bool hasVerticalAlignmentSet() const
Returns true if the format has an explicit vertical alignment set.
double fontPointSize() const
Returns the font point size, or -1 if the font size is not set and should be inherited.
Contains pre-calculated metrics of a QgsTextDocument.
double verticalOrientationXOffset(int blockIndex) const
Returns the vertical orientation x offset for the specified block.
double fragmentVerticalOffset(int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode) const
Returns the vertical offset from a text block's baseline which should be applied to the fragment at t...
double blockMaximumDescent(int blockIndex) const
Returns the maximum descent encountered in the specified block.
QSizeF documentSize(Qgis::TextLayoutMode mode, Qgis::TextOrientation orientation) const
Returns the overall size of the document.
QFont fragmentFont(int blockIndex, int fragmentIndex) const
Returns the calculated font for the fragment at the specified block and fragment indices.
double blockMaximumCharacterWidth(int blockIndex) const
Returns the maximum character width for the specified block.
double baselineOffset(int blockIndex, Qgis::TextLayoutMode mode) const
Returns the offset from the top of the document to the text baseline for the given block index.
static QgsTextDocumentMetrics calculateMetrics(const QgsTextDocument &document, const QgsTextFormat &format, const QgsRenderContext &context, double scaleFactor=1.0)
Returns precalculated text metrics for a text document, when rendered using the given base format and...
double blockHeight(int blockIndex) const
Returns the height of the block at the specified index.
double fragmentHorizontalAdvance(int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode) const
Returns the horizontal advance of the fragment at the specified block and fragment index.
bool isNullFontSize() const
Returns true if the metrics could not be calculated because the text format has a null font size.
double blockWidth(int blockIndex) const
Returns the width of the block at the specified index.
double ascentOffset() const
Returns the ascent offset of the first block in the document.
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 append(const QgsTextBlock &block)
Appends a block to the document.
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.
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.
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.
Qgis::RenderUnit sizeUnit() const
Returns the units for the size of rendered 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.
Qgis::TextOrientation orientation() const
Returns the orientation of the text.
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.
Container for settings relating to a selective masking around a text.
Qgis::RenderUnit sizeUnit() const
Returns the units for the buffer size.
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.
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.
Contains placement information for a single grapheme in a curved text layout.
@ RespectPainterOrientation
Curved text will be placed respecting the painter orientation, and the actual line direction will be ...
@ TruncateStringWhenLineIsTooShort
When a string is too long for the line, truncate characters instead of aborting the placement.
@ UseBaselinePlacement
Generate placement based on the character baselines instead of centers.
static std::unique_ptr< CurvePlacementProperties > generateCurvedTextPlacement(const QgsPrecalculatedTextMetrics &metrics, const QPolygonF &line, double offsetAlongLine, LabelLineDirection direction=RespectPainterOrientation, double maxConcaveAngle=-1, double maxConvexAngle=-1, CurvedTextFlags flags=CurvedTextFlags())
Calculates curved text placement properties.
static void drawDocumentOnLine(const QPolygonF &line, const QgsTextFormat &format, const QgsTextDocument &document, QgsRenderContext &context, double offsetAlongLine=0, double offsetFromLine=0)
Draws a text document along a line using the specified settings.
static Qgis::TextVerticalAlignment convertQtVAlignment(Qt::Alignment alignment)
Converts a Qt vertical alignment flag to a Qgis::TextVerticalAlignment value.
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 void drawDocument(const QRectF &rect, const QgsTextFormat &format, const QgsTextDocument &document, const QgsTextDocumentMetrics &metrics, QgsRenderContext &context, Qgis::TextHorizontalAlignment horizontalAlignment=Qgis::TextHorizontalAlignment::Left, Qgis::TextVerticalAlignment verticalAlignment=Qgis::TextVerticalAlignment::Top, double rotation=0, Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags())
Draws a text document within a rectangle using the specified settings.
static int sizeToPixel(double size, const QgsRenderContext &c, Qgis::RenderUnit unit, const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale())
Calculates pixel size (considering output size should be in pixel or map units, scale factors and opt...
static Q_DECL_DEPRECATED void drawPart(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, Qgis::TextComponent part, bool drawAsOutlines=true)
Draws a single component of rendered text using the specified settings.
static void drawText(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, Qgis::TextVerticalAlignment vAlignment=Qgis::TextVerticalAlignment::Top, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle)
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 ...
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 void drawTextOnLine(const QPolygonF &line, const QString &text, QgsRenderContext &context, const QgsTextFormat &format, double offsetAlongLine=0, double offsetFromLine=0)
Draws text along a line using the specified settings.
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, Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
static constexpr double SUPERSCRIPT_SUBSCRIPT_FONT_SIZE_SCALING_FACTOR
Scale factor to use for super or subscript text which doesn't have an explicit font size set.
static constexpr double FONT_WORKAROUND_SCALE
Scale factor for upscaling font sizes and downscaling destination painter devices.
static Qgis::TextHorizontalAlignment convertQtHAlignment(Qt::Alignment alignment)
Converts a Qt horizontal alignment flag to a Qgis::TextHorizontalAlignment value.
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).
Qgis::RenderUnit offsetUnit() const
Returns the units used for the shadow's offset.
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.
Qgis::RenderUnit blurRadiusUnit() const
Returns the units used for the shadow's blur radius.
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.
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.
double blurRadius() const
Returns the blur radius for the shadow.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
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)
Contains geos related utilities and functions.
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()