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 );
92 QStringList textLines;
93 for (
const QString &line : text )
97 textLines.append(
wrappedText( context, line, rect.width(), format ) );
101 textLines.append( line );
108 const double fontScale = calculateScaleFactorForFormat( context, format );
111 drawDocument( rect, tmpFormat, document, metrics, context, alignment, vAlignment, rotation, mode, flags );
116 const QgsTextFormat tmpFormat = updateShadowPosition( format );
136 tmpFormat = updateShadowPosition( tmpFormat );
140 const double fontScale = calculateScaleFactorForFormat( context, format );
161 tmpFormat = updateShadowPosition( tmpFormat );
167 drawDocumentOnLine( line, tmpFormat, document, context, offsetAlongLine, offsetFromLine );
172 QPolygonF labelBaselineCurve = line;
181#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
182 if ( offsetFromLine < 0 )
185 std::unique_ptr < QgsLineString > reversed( offsetCurve->reversed() );
189 offsetCurve = std::move( reversed );
193 labelBaselineCurve = offsetCurve->asQPolygonF();
196 const double fontScale = calculateScaleFactorForFormat( context, format );
198 const QFont baseFont = format.
scaledFont( context, fontScale );
199 const double letterSpacing = baseFont.letterSpacing() / fontScale;
200 const double wordSpacing = baseFont.wordSpacing() / fontScale;
202 QStringList graphemes;
203 QVector< QgsTextCharacterFormat > graphemeFormats;
204 QVector< QgsTextDocument > graphemeDocuments;
205 QVector< QgsTextDocumentMetrics > graphemeMetrics;
207 for (
const QgsTextBlock &block : std::as_const( document ) )
212 for (
const QString &grapheme : fragmentGraphemes )
214 graphemes.append( grapheme );
215 graphemeFormats.append( fragment.characterFormat() );
220 graphemeDocuments.append( document );
226 QVector< double > characterWidths( graphemes.count() );
227 QVector< double > characterHeights( graphemes.count() );
228 QVector< double > characterDescents( graphemes.count() );
229 QFont previousNonSuperSubScriptFont;
231 for (
int i = 0; i < graphemes.count(); i++ )
236 double graphemeFirstCharHorizontalAdvanceWithLetterSpacing = 0;
237 double graphemeFirstCharHorizontalAdvance = 0;
238 double graphemeHorizontalAdvance = 0;
239 double characterDescent = 0;
240 double characterHeight = 0;
243 QFont graphemeFont = baseFont;
247 previousNonSuperSubScriptFont = graphemeFont;
254 previousNonSuperSubScriptFont = graphemeFont;
275 previousNonSuperSubScriptFont = graphemeFont;
278 const QFontMetricsF graphemeFontMetrics( graphemeFont );
279 graphemeFirstCharHorizontalAdvance = graphemeFontMetrics.horizontalAdvance( QString( graphemes[i].at( 0 ) ) ) / fontScale;
280 graphemeFirstCharHorizontalAdvanceWithLetterSpacing = graphemeFontMetrics.horizontalAdvance( graphemes[i].at( 0 ) ) / fontScale + letterSpacing;
281 graphemeHorizontalAdvance = graphemeFontMetrics.horizontalAdvance( QString( graphemes[i] ) ) / fontScale;
282 characterDescent = graphemeFontMetrics.descent() / fontScale;
283 characterHeight = graphemeFontMetrics.height() / fontScale;
285 qreal wordSpaceFix = qreal( 0.0 );
286 if ( graphemes[i] == QLatin1String(
" " ) )
290 wordSpaceFix = ( nxt < graphemes.count() && graphemes[nxt] != QLatin1String(
" " ) ) ? wordSpacing : qreal( 0.0 );
295 if ( graphemes[i].length() == 1 &&
296 !
qgsDoubleNear( graphemeFirstCharHorizontalAdvance, graphemeFirstCharHorizontalAdvanceWithLetterSpacing ) )
299 wordSpaceFix -= wordSpacing;
302 const double charWidth = graphemeHorizontalAdvance + wordSpaceFix;
303 characterWidths[i] = charWidth;
304 characterHeights[i] = characterHeight;
305 characterDescents[i] = characterDescent;
308 QgsPrecalculatedTextMetrics metrics( graphemes, std::move( characterWidths ), std::move( characterHeights ), std::move( characterDescents ) );
312 metrics, labelBaselineCurve, offsetAlongLine,
319 if ( placement->graphemePlacement.empty() )
322 std::vector< QgsTextRenderer::Component > components;
323 components.reserve( placement->graphemePlacement.size() );
326 QgsTextRenderer::Component component;
327 component.origin = QPointF( grapheme.x, grapheme.y );
328 component.rotation = -grapheme.angle;
334 component.origin.rx() += verticalOffset * std::cos( grapheme.angle + M_PI_2 );
335 component.origin.ry() += verticalOffset * std::sin( grapheme.angle + M_PI_2 );
338 components.emplace_back( component );
346 const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
355 const QgsTextDocument &document = graphemeDocuments.
at( grapheme.graphemeIndex );
357 const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
373 const QgsTextDocument &document = graphemeDocuments.
at( grapheme.graphemeIndex );
375 const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
414 const double fontScale = calculateScaleFactorForFormat( context, format );
428 component.dpiRatio = 1.0;
429 component.origin = rect.topLeft();
430 component.rotation = rotation;
431 component.size = rect.size();
432 component.hAlign = alignment;
445 double xc = rect.width() / 2.0;
446 double yc = rect.height() / 2.0;
448 double angle = -rotation;
449 double xd = xc * std::cos( angle ) - yc * std::sin( angle );
450 double yd = xc * std::sin( angle ) + yc * std::cos( angle );
452 component.center = QPointF( component.origin.x() + xd, component.origin.y() + yd );
456 component.center = rect.center();
459 switch ( vAlignment )
485 drawTextInternal( part, context, format, component,
487 alignment, vAlignment, mode );
496 const double fontScale = calculateScaleFactorForFormat( context, format );
510 component.dpiRatio = 1.0;
511 component.origin = origin;
512 component.rotation = rotation;
513 component.hAlign = alignment;
522 QgsTextRenderer::drawBackground( context, component, format, metrics, mode );
535 drawTextInternal( part, context, format, component,
547 return QFontMetricsF( format.
scaledFont( context, scaleFactor ), context.
painter() ? context.
painter()->device() : nullptr );
554 QPainter *p = context.
painter();
559 if ( component.rotation >= -315 && component.rotation < -90 )
563 else if ( component.rotation >= -90 && component.rotation < -45 )
579 const double scaleFactor = calculateScaleFactorForFormat( context, format );
581 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
592 referenceScaleOverride.reset();
595 path.setFillRule( Qt::WindingFill );
597 double height = component.size.height();
598 switch ( orientation )
603 int fragmentIndex = 0;
606 QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, fragmentIndex );
608 if ( component.extraWordSpacing || component.extraLetterSpacing )
609 applyExtraSpacingForLineJustification( fragmentFont, component.extraWordSpacing, component.extraLetterSpacing );
612 path.addText( xOffset, yOffset, fragmentFont, fragment.text() );
625 double partYOffset = component.offset.y() * scaleFactor;
628 double partLastDescent = 0;
630 int fragmentIndex = 0;
633 const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, component.firstFragmentIndex + fragmentIndex );
634 const double letterSpacing = fragmentFont.letterSpacing() / scaleFactor;
636 const QFontMetricsF fragmentMetrics( fragmentFont );
638 const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode );
641 for (
const QString &part : parts )
643 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / scaleFactor - letterSpacing ) ) / 2;
644 partYOffset += fragmentMetrics.ascent() / scaleFactor;
645 path.addText( partXOffset, partYOffset + fragmentYOffset, fragmentFont, part );
646 partYOffset += letterSpacing;
648 partLastDescent = fragmentMetrics.descent() / scaleFactor;
652 height = partYOffset + partLastDescent;
653 advance = partYOffset - component.offset.y() * scaleFactor;
658 QColor bufferColor = buffer.
color();
659 bufferColor.setAlphaF( buffer.
opacity() );
660 QPen pen( bufferColor );
661 pen.setWidthF( penSize * scaleFactor );
663 QColor tmpColor( bufferColor );
667 tmpColor.setAlpha( 0 );
673 buffp.begin( &buffPict );
677 std::unique_ptr< QgsPaintEffect > tmpEffect( buffer.
paintEffect()->
clone() );
679 tmpEffect->begin( context );
680 context.
painter()->setPen( pen );
681 context.
painter()->setBrush( tmpColor );
682 if ( scaleFactor != 1.0 )
683 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
684 context.
painter()->drawPath( path );
685 if ( scaleFactor != 1.0 )
686 context.
painter()->scale( scaleFactor, scaleFactor );
687 tmpEffect->end( context );
693 if ( scaleFactor != 1.0 )
694 buffp.scale( 1 / scaleFactor, 1 / scaleFactor );
696 buffp.setBrush( tmpColor );
697 buffp.drawPath( path );
703 QgsTextRenderer::Component bufferComponent = component;
704 bufferComponent.origin = QPointF( 0.0, 0.0 );
705 bufferComponent.picture = buffPict;
706 bufferComponent.pictureBuffer = penSize / 2.0;
707 bufferComponent.size.setHeight( height );
711 bufferComponent.offset.setY( - bufferComponent.size.height() );
713 drawShadow( context, bufferComponent, format );
721 p->setCompositionMode( buffer.
blendMode() );
725 p->scale( component.dpiRatio, component.dpiRatio );
726 _fixQPictureDPI( p );
727 p->drawPicture( 0, 0, buffPict );
729 return advance / scaleFactor;
749 path.setFillRule( Qt::WindingFill );
751 const double scaleFactor = calculateScaleFactorForFormat( context, format );
756 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
767 referenceScaleOverride.reset();
770 int fragmentIndex = 0;
773 const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, fragmentIndex );
775 const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode );
776 path.addText( xOffset, fragmentYOffset, fragmentFont, fragment.text() );
782 QColor bufferColor( Qt::gray );
783 bufferColor.setAlphaF( mask.
opacity() );
787 brush.setColor( bufferColor );
788 pen.setColor( bufferColor );
789 pen.setWidthF( penSize * scaleFactor );
796 p->scale( component.dpiRatio, component.dpiRatio );
802 if ( scaleFactor != 1.0 )
803 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
804 context.
painter()->setPen( pen );
805 context.
painter()->setBrush( brush );
806 context.
painter()->drawPath( path );
807 if ( scaleFactor != 1.0 )
808 context.
painter()->scale( scaleFactor, scaleFactor );
813 if ( scaleFactor != 1.0 )
814 p->scale( 1 / scaleFactor, 1 / scaleFactor );
816 p->setBrush( brush );
818 if ( scaleFactor != 1.0 )
819 p->scale( scaleFactor, scaleFactor );
835 if ( doc.
size() == 0 )
839 return textWidth( context, format, doc );
845 const double scaleFactor = calculateScaleFactorForFormat( context, format );
856 for (
const QString &line : textLines )
860 lines.append(
wrappedText( context, line, maxLineWidth, format ) );
864 lines.append( line );
880 const double scaleFactor = calculateScaleFactorForFormat( context, format );
882 bool isNullSize =
false;
883 const QFont baseFont = format.
scaledFont( context, scaleFactor, &isNullSize );
887 const QFontMetrics fm( baseFont );
888 const double height = ( character.isNull() ? fm.height() : fm.boundingRect( character ).height() ) / scaleFactor;
890 if ( !includeEffects )
893 double maxExtension = 0;
922 return height + maxExtension;
930 const QStringList multiLineSplit = text.split(
'\n' );
932 return currentTextWidth > width;
937 const QStringList lines = text.split(
'\n' );
938 QStringList outLines;
939 for (
const QString &line : lines )
944 const QStringList words = line.split(
' ' );
945 QStringList linesToProcess;
946 QString wordsInCurrentLine;
947 for (
const QString &word : words )
952 if ( !wordsInCurrentLine.isEmpty() )
953 linesToProcess << wordsInCurrentLine;
954 wordsInCurrentLine.clear();
955 linesToProcess << word;
959 if ( !wordsInCurrentLine.isEmpty() )
960 wordsInCurrentLine.append(
' ' );
961 wordsInCurrentLine.append( word );
964 if ( !wordsInCurrentLine.isEmpty() )
965 linesToProcess << wordsInCurrentLine;
967 for (
const QString &line : std::as_const( linesToProcess ) )
969 QString remainingText = line;
970 int lastPos = remainingText.lastIndexOf(
' ' );
971 while ( lastPos > -1 )
981 outLines << remainingText.left( lastPos );
982 remainingText = remainingText.mid( lastPos + 1 );
985 lastPos = remainingText.lastIndexOf(
' ', lastPos - 1 );
987 outLines << remainingText;
1005 const double scaleFactor = calculateScaleFactorForFormat( context, format );
1018 QPainter *prevP = context.
painter();
1019 QPainter *p = context.
painter();
1020 std::unique_ptr< QgsPaintEffect > tmpEffect;
1024 tmpEffect->begin( context );
1033 const double originAdjustRotationRadians = -component.rotation;
1036 component.rotation = -( component.rotation * 180 / M_PI );
1037 component.rotationOffset =
1042 component.rotation = 0.0;
1043 component.rotationOffset = background.
rotation();
1046 const double scaleFactor = calculateScaleFactorForFormat( context, format );
1052 double width = documentSize.width();
1053 double height = documentSize.height();
1060 switch ( component.hAlign )
1064 component.center = QPointF( component.origin.x() + width / 2.0,
1065 component.origin.y() + height / 2.0 );
1069 component.center = QPointF( component.origin.x() + component.size.width() / 2.0,
1070 component.origin.y() + height / 2.0 );
1074 component.center = QPointF( component.origin.x() + component.size.width() - width / 2.0,
1075 component.origin.y() + height / 2.0 );
1082 bool isNullSize =
false;
1083 QFontMetricsF fm( format.
scaledFont( context, scaleFactor, &isNullSize ) );
1084 double originAdjust = isNullSize ? 0 : ( fm.ascent() / scaleFactor / 2.0 - fm.leading() / scaleFactor / 2.0 );
1085 switch ( component.hAlign )
1089 component.center = QPointF( component.origin.x() + width / 2.0,
1090 component.origin.y() - height / 2.0 + originAdjust );
1094 component.center = QPointF( component.origin.x(),
1095 component.origin.y() - height / 2.0 + originAdjust );
1099 component.center = QPointF( component.origin.x() - width / 2.0,
1100 component.origin.y() - height / 2.0 + originAdjust );
1107 const double dx = component.center.x() - component.origin.x();
1108 const double dy = component.center.y() - component.origin.y();
1109 component.center.setX( component.origin.x() + ( std::cos( originAdjustRotationRadians ) * dx - std::sin( originAdjustRotationRadians ) * dy ) );
1110 component.center.setY( component.origin.y() + ( std::sin( originAdjustRotationRadians ) * dx + std::cos( originAdjustRotationRadians ) * dy ) );
1120 component.size = QSizeF( width, height );
1125 switch ( background.
type() )
1138 double sizeOut = 0.0;
1149 sizeOut = std::max( component.size.width(), component.size.height() );
1153 sizeOut += bufferSize * 2;
1159 if ( sizeOut < 1.0 )
1162 std::unique_ptr< QgsMarkerSymbol > renderedSymbol;
1166 map[QStringLiteral(
"name" )] = background.
svgFile().trimmed();
1167 map[QStringLiteral(
"size" )] = QString::number( sizeOut );
1169 map[QStringLiteral(
"angle" )] = QString::number( 0.0 );
1177 map[QStringLiteral(
"fill" )] = background.
fillColor().name();
1178 map[QStringLiteral(
"outline" )] = background.
strokeColor().name();
1179 map[QStringLiteral(
"outline-width" )] = QString::number( background.
strokeWidth() );
1186 QVariantMap shdwmap( map );
1187 shdwmap[QStringLiteral(
"fill" )] = shadow.
color().name();
1188 shdwmap[QStringLiteral(
"outline" )] = shadow.
color().name();
1189 shdwmap[QStringLiteral(
"size" )] = QString::number( sizeOut );
1194 svgp.begin( &svgPict );
1211 svgShdwM->
renderPoint( QPointF( sizeOut / 2, -sizeOut / 2 ), svgShdwContext );
1214 component.picture = svgPict;
1216 component.pictureBuffer = 0.0;
1218 component.size = QSizeF( sizeOut, sizeOut );
1219 component.offset = QPointF( 0.0, 0.0 );
1225 p->translate( component.center.x(), component.center.y() );
1226 p->rotate( component.rotation );
1229 p->translate( QPointF( xoff, yoff ) );
1230 p->rotate( component.rotationOffset );
1231 p->translate( -sizeOut / 2, sizeOut / 2 );
1233 drawShadow( context, component, format );
1235 renderedSymbol.reset( );
1243 renderedSymbol->setSize( sizeOut );
1247 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1255 p->setCompositionMode( background.
blendMode() );
1257 p->translate( component.center.x(), component.center.y() );
1258 p->rotate( component.rotation );
1261 p->translate( QPointF( xoff, yoff ) );
1262 p->rotate( component.rotationOffset );
1266 renderedSymbol->renderPoint( QPointF( 0, 0 ), &f, context );
1267 renderedSymbol->stopRender( context );
1268 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1278 double w = component.size.width();
1279 double h = component.size.height();
1300 h = std::sqrt( std::pow( w, 2 ) + std::pow( h, 2 ) );
1306 h = h * M_SQRT1_2 * 2;
1307 w = w * M_SQRT1_2 * 2;
1315 w += bufferWidth * 2;
1316 h += bufferHeight * 2;
1320 QRectF rect( -w / 2.0, - h / 2.0, w, h );
1322 if ( rect.isNull() )
1328 p->translate( QPointF( component.center.x(), component.center.y() ) );
1329 p->rotate( component.rotation );
1332 p->translate( QPointF( xoff, yoff ) );
1333 p->rotate( component.rotationOffset );
1339 QTransform t = QTransform::fromScale( 10, 10 );
1341 QTransform ti = t.inverted();
1348 path.addRoundedRect( rect, background.
radii().width(), background.
radii().height(), Qt::RelativeSize );
1354 path.addRoundedRect( rect, xRadius, yRadius );
1360 path.addEllipse( rect );
1362 QPolygonF tempPolygon = path.toFillPolygon( t );
1363 QPolygonF polygon = ti.map( tempPolygon );
1365 QPainter *oldp = context.
painter();
1368 shapep.begin( &shapePict );
1371 std::unique_ptr< QgsFillSymbol > renderedSymbol;
1373 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1377 renderedSymbol->renderPolygon( polygon,
nullptr, &f, context );
1378 renderedSymbol->stopRender( context );
1385 component.picture = shapePict;
1388 component.size = rect.size();
1389 component.offset = QPointF( rect.width() / 2, -rect.height() / 2 );
1390 drawShadow( context, component, format );
1395 p->setCompositionMode( background.
blendMode() );
1399 p->scale( component.dpiRatio, component.dpiRatio );
1400 _fixQPictureDPI( p );
1401 p->drawPicture( 0, 0, shapePict );
1402 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1409 tmpEffect->end( context );
1422 QPainter *p = context.
painter();
1423 const double componentWidth = component.size.width();
1424 const double componentHeight = component.size.height();
1425 double xOffset = component.offset.x(), yOffset = component.offset.y();
1426 double pictbuffer = component.pictureBuffer;
1435 radius /= ( mapUnits ? context.
scaleFactor() / component.dpiRatio : 1 );
1436 radius =
static_cast< int >( radius + 0.5 );
1440 double blurBufferClippingScale = 3.75;
1441 int blurbuffer = ( radius > 17 ? 16 : radius ) * blurBufferClippingScale;
1443 QImage blurImg( componentWidth + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1444 componentHeight + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1445 QImage::Format_ARGB32_Premultiplied );
1449 int minBlurImgSize = 1;
1453 int maxBlurImgSize = 40000;
1454 if ( blurImg.isNull()
1455 || ( blurImg.width() < minBlurImgSize || blurImg.height() < minBlurImgSize )
1456 || ( blurImg.width() > maxBlurImgSize || blurImg.height() > maxBlurImgSize ) )
1459 blurImg.fill( QColor( Qt::transparent ).rgba() );
1461 if ( !pictp.begin( &blurImg ) )
1463 pictp.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
1464 QPointF imgOffset( blurbuffer + pictbuffer + xOffset,
1465 blurbuffer + pictbuffer + componentHeight + yOffset );
1467 pictp.drawPicture( imgOffset,
1468 component.picture );
1471 pictp.setCompositionMode( QPainter::CompositionMode_SourceIn );
1472 pictp.fillRect( blurImg.rect(), shadow.
color() );
1476 if ( shadow.
blurRadius() > 0.0 && radius > 0 )
1484 picti.begin( &blurImg );
1485 picti.setBrush( Qt::Dense7Pattern );
1486 QPen imgPen( QColor( 0, 0, 255, 255 ) );
1487 imgPen.setWidth( 1 );
1488 picti.setPen( imgPen );
1489 picti.setOpacity( 0.1 );
1490 picti.drawRect( 0, 0, blurImg.width(), blurImg.height() );
1497 double angleRad = shadow.
offsetAngle() * M_PI / 180;
1505 angleRad -= ( component.rotation * M_PI / 180 + component.rotationOffset * M_PI / 180 );
1508 QPointF transPt( -offsetDist * std::cos( angleRad + M_PI_2 ),
1509 -offsetDist * std::sin( angleRad + M_PI_2 ) );
1515 p->setRenderHint( QPainter::SmoothPixmapTransform );
1518 p->setCompositionMode( shadow.
blendMode() );
1520 p->setOpacity( shadow.
opacity() );
1522 double scale = shadow.
scale() / 100.0;
1524 p->scale( scale, scale );
1525 if ( component.useOrigin )
1527 p->translate( component.origin.x(), component.origin.y() );
1529 p->translate( transPt );
1530 p->translate( -imgOffset.x(),
1532 p->drawImage( 0, 0, blurImg );
1539 p->setBrush( Qt::NoBrush );
1540 QPen imgPen( QColor( 255, 0, 0, 10 ) );
1541 imgPen.setWidth( 2 );
1542 imgPen.setStyle( Qt::DashLine );
1543 p->setPen( imgPen );
1544 p->scale( scale, scale );
1545 if ( component.useOrigin() )
1547 p->translate( component.origin().x(), component.origin().y() );
1549 p->translate( transPt );
1550 p->translate( -imgOffset.x(),
1552 p->drawRect( 0, 0, blurImg.width(), blurImg.height() );
1557 p->setBrush( Qt::NoBrush );
1558 QPen componentRectPen( QColor( 0, 255, 0, 70 ) );
1559 componentRectPen.setWidth( 1 );
1560 if ( component.useOrigin() )
1562 p->translate( component.origin().x(), component.origin().y() );
1564 p->setPen( componentRectPen );
1565 p->drawRect( QRect( -xOffset, -componentHeight - yOffset, componentWidth, componentHeight ) );
1574 const Component &component,
1584 const double fontScale = calculateScaleFactorForFormat( context, format );
1586 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1597 referenceScaleOverride.reset();
1599 double rotation = 0;
1600 const Qgis::TextOrientation orientation = calculateRotationAndOrientationForComponent( format, component, rotation );
1601 switch ( orientation )
1605 drawTextInternalHorizontal( context, format, drawType, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
1612 drawTextInternalVertical( context, format, drawType, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
1618Qgis::TextOrientation QgsTextRenderer::calculateRotationAndOrientationForComponent(
const QgsTextFormat &format,
const QgsTextRenderer::Component &component,
double &rotation )
1620 rotation = -component.rotation * 180 / M_PI;
1627 if ( rotation >= -315 && rotation < -90 )
1632 else if ( rotation >= -90 && rotation < -45 )
1648void QgsTextRenderer::calculateExtraSpacingForLineJustification(
const double spaceToDistribute,
const QgsTextBlock &block,
double &extraWordSpace,
double &extraLetterSpace )
1651 QTextBoundaryFinder
finder( QTextBoundaryFinder::Word, blockText );
1653 int wordBoundaries = 0;
1654 while (
finder.toNextBoundary() != -1 )
1656 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1660 if ( wordBoundaries > 0 )
1663 extraWordSpace = spaceToDistribute / wordBoundaries;
1668 QTextBoundaryFinder
finder( QTextBoundaryFinder::Grapheme, blockText );
1671 int graphemeBoundaries = 0;
1672 while (
finder.toNextBoundary() != -1 )
1674 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1675 graphemeBoundaries++;
1678 if ( graphemeBoundaries > 0 )
1680 extraLetterSpace = spaceToDistribute / graphemeBoundaries;
1685void QgsTextRenderer::applyExtraSpacingForLineJustification( QFont &font,
double extraWordSpace,
double extraLetterSpace )
1687 const double prevWordSpace = font.wordSpacing();
1688 font.setWordSpacing( prevWordSpace + extraWordSpace );
1689 const double prevLetterSpace = font.letterSpacing();
1690 font.setLetterSpacing( QFont::AbsoluteSpacing, prevLetterSpace + extraLetterSpace );
1697 const QStringList textLines = document.
toPlainText();
1701 double labelWidest = 0.0;
1706 labelWidest = documentSize.width();
1712 labelWidest = component.size.width();
1716 double verticalAlignOffset = 0;
1722 const double overallHeight = documentSize.height();
1723 switch ( vAlignment )
1729 verticalAlignOffset = ( component.size.height() - overallHeight ) * 0.5;
1733 verticalAlignOffset = ( component.size.height() - overallHeight );
1741 const bool isFinalLineInParagraph = ( blockIndex == document.
size() - 1 )
1742 || document.
at( blockIndex + 1 ).
toPlainText().trimmed().isEmpty();
1744 const double blockHeight = metrics.
blockHeight( blockIndex );
1748 context.
painter()->translate( component.origin );
1750 context.
painter()->rotate( rotation );
1755 maskPainter->save();
1756 maskPainter->translate( component.origin );
1758 maskPainter->rotate( rotation );
1762 double xMultiLineOffset = 0.0;
1763 double blockWidth = metrics.
blockWidth( blockIndex );
1764 double extraWordSpace = 0;
1765 double extraLetterSpace = 0;
1766 if ( adjustForAlignment )
1768 double labelWidthDiff = 0;
1769 switch ( hAlignment )
1772 labelWidthDiff = ( labelWidest - blockWidth ) * 0.5;
1776 labelWidthDiff = labelWidest - blockWidth;
1780 if ( !isFinalLineInParagraph && labelWidest > blockWidth )
1782 calculateExtraSpacingForLineJustification( labelWidest - blockWidth, block, extraWordSpace, extraLetterSpace );
1783 blockWidth = labelWidest;
1797 xMultiLineOffset = labelWidthDiff;
1802 switch ( hAlignment )
1805 xMultiLineOffset = labelWidthDiff - labelWidest;
1809 xMultiLineOffset = labelWidthDiff - labelWidest / 2.0;
1821 const double baseLineOffset = metrics.
baselineOffset( blockIndex, mode );
1823 context.
painter()->translate( QPointF( xMultiLineOffset, baseLineOffset + verticalAlignOffset ) );
1825 maskPainter->translate( QPointF( xMultiLineOffset, baseLineOffset + verticalAlignOffset ) );
1827 Component subComponent;
1828 subComponent.block = block;
1829 subComponent.blockIndex = blockIndex;
1830 subComponent.
size = QSizeF( blockWidth, blockHeight );
1831 subComponent.offset = QPointF( 0.0, -metrics.
ascentOffset() );
1832 subComponent.rotation = -component.rotation * 180 / M_PI;
1833 subComponent.rotationOffset = 0.0;
1834 subComponent.extraWordSpacing = extraWordSpace * fontScale;
1835 subComponent.extraLetterSpacing = extraLetterSpace * fontScale;
1840 QgsTextRenderer::drawMask( context, subComponent, format, metrics, mode );
1845 QgsTextRenderer::drawBuffer( context, subComponent, format, metrics, mode );
1852 textp.begin( &textPict );
1853 textp.setPen( Qt::NoPen );
1855 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1863 referenceScaleOverride.reset();
1867 textp.scale( 1 / fontScale, 1 / fontScale );
1870 int fragmentIndex = 0;
1875 path.setFillRule( Qt::WindingFill );
1877 QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
1879 if ( extraWordSpace || extraLetterSpace )
1880 applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
1884 path.addText( xOffset, yOffset, fragmentFont, fragment.text() );
1886 QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
1887 textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.opacity() );
1888 textp.setBrush( textColor );
1889 textp.drawPath( path );
1899 subComponent.picture = textPict;
1900 subComponent.pictureBuffer = 0.0;
1901 subComponent.origin = QPointF( 0.0, 0.0 );
1903 QgsTextRenderer::drawShadow( context, subComponent, format );
1913 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
1920 _fixQPictureDPI( context.
painter() );
1921 context.
painter()->drawPicture( 0, 0, textPict );
1928 int fragmentIndex = 0;
1931 QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
1933 if ( extraWordSpace || extraLetterSpace )
1934 applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
1938 QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
1939 textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.opacity() );
1941 context.
painter()->setPen( textColor );
1942 context.
painter()->setFont( fragmentFont );
1943 context.
painter()->setRenderHint( QPainter::TextAntialiasing );
1945 context.
painter()->scale( 1 / fontScale, 1 / fontScale );
1946 context.
painter()->drawText( QPointF( xOffset, yOffset ), fragment.text() );
1947 context.
painter()->scale( fontScale, fontScale );
1956 maskPainter->restore();
1962void 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 )
1965 const QStringList textLines = document.
toPlainText();
1967 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1978 referenceScaleOverride.reset();
1981 const double actualTextWidth = documentSize.width();
1982 double textRectWidth = 0.0;
1988 textRectWidth = actualTextWidth;
1994 textRectWidth = component.size.width();
1998 int maxLineLength = 0;
1999 for (
const QString &line : std::as_const( textLines ) )
2001 maxLineLength = std::max( maxLineLength,
static_cast<int>( line.length() ) );
2004 const double actualLabelHeight = documentSize.height();
2014 context.
painter()->translate( component.origin );
2016 context.
painter()->rotate( rotation );
2021 maskPainter->save();
2022 maskPainter->translate( component.origin );
2024 maskPainter->rotate( rotation );
2031 if ( adjustForAlignment )
2033 double hAlignmentOffset = 0;
2034 switch ( hAlignment )
2037 hAlignmentOffset = ( textRectWidth - actualTextWidth ) * 0.5;
2041 hAlignmentOffset = textRectWidth - actualTextWidth;
2055 xOffset += hAlignmentOffset;
2063 double yOffset = 0.0;
2069 if ( rotation >= -405 && rotation < -180 )
2073 else if ( rotation >= 0 && rotation < 45 )
2075 xOffset -= actualTextWidth;
2081 yOffset = -actualLabelHeight;
2086 yOffset = -actualLabelHeight;
2096 context.
painter()->translate( QPointF( xOffset, yOffset ) );
2098 double currentBlockYOffset = 0;
2099 int fragmentIndex = 0;
2107 const QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
2109 QFontMetricsF fragmentMetrics( fragmentFont );
2111 const double letterSpacing = fragmentFont.letterSpacing() / fontScale;
2112 const double labelHeight = fragmentMetrics.ascent() / fontScale + ( fragmentMetrics.ascent() / fontScale + letterSpacing ) * ( line.length() - 1 );
2114 Component subComponent;
2116 subComponent.blockIndex = blockIndex;
2117 subComponent.firstFragmentIndex = fragmentIndex;
2118 subComponent.size = QSizeF( blockMaximumCharacterWidth, labelHeight + fragmentMetrics.descent() / fontScale );
2119 subComponent.offset = QPointF( 0.0, currentBlockYOffset );
2120 subComponent.rotation = -component.rotation * 180 / M_PI;
2121 subComponent.rotationOffset = 0.0;
2128 QgsTextRenderer::drawMask( context, subComponent, format );
2134 currentBlockYOffset += QgsTextRenderer::drawBuffer( context, subComponent, format, metrics, mode );
2140 path.setFillRule( Qt::WindingFill );
2142 double partYOffset = 0.0;
2143 for (
const QString &part : parts )
2145 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
2146 partYOffset += fragmentMetrics.ascent() / fontScale;
2147 path.addText( partXOffset * fontScale, partYOffset * fontScale, fragmentFont, part );
2148 partYOffset += letterSpacing;
2154 textp.begin( &textPict );
2155 textp.setPen( Qt::NoPen );
2156 QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
2157 textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.
opacity() );
2158 textp.setBrush( textColor );
2159 textp.scale( 1 / fontScale, 1 / fontScale );
2160 textp.drawPath( path );
2171 subComponent.picture = textPict;
2172 subComponent.pictureBuffer = 0.0;
2173 subComponent.origin = QPointF( 0.0, currentBlockYOffset );
2174 const double prevY = subComponent.offset.y();
2175 subComponent.offset = QPointF( 0, -subComponent.size.height() );
2176 subComponent.useOrigin =
true;
2177 QgsTextRenderer::drawShadow( context, subComponent, format );
2178 subComponent.useOrigin =
false;
2179 subComponent.offset = QPointF( 0, prevY );
2189 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
2196 context.
painter()->translate( 0, currentBlockYOffset );
2197 _fixQPictureDPI( context.
painter() );
2198 context.
painter()->drawPicture( 0, 0, textPict );
2199 currentBlockYOffset += partYOffset;
2205 context.
painter()->setFont( fragmentFont );
2206 context.
painter()->setPen( textColor );
2207 context.
painter()->setRenderHint( QPainter::TextAntialiasing );
2209 double partYOffset = 0.0;
2210 for (
const QString &part : parts )
2212 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
2213 context.
painter()->scale( 1 / fontScale, 1 / fontScale );
2214 context.
painter()->drawText( QPointF( partXOffset * fontScale, ( currentBlockYOffset + partYOffset ) * fontScale ), part );
2215 context.
painter()->scale( fontScale, fontScale );
2216 partYOffset += fragmentMetrics.ascent() / fontScale + letterSpacing;
2218 currentBlockYOffset += partYOffset;
2226 maskPainter->restore();
2241 if ( pixelSize < 50 )
2245 else if ( pixelSize > 200 )
2246 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.
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 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.
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())
Flags controlling behavior of curved text generation.
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()