37#include <QTextBoundaryFinder>
42 if ( alignment & Qt::AlignLeft )
44 else if ( alignment & Qt::AlignRight )
46 else if ( alignment & Qt::AlignHCenter )
48 else if ( alignment & Qt::AlignJustify )
57 if ( alignment & Qt::AlignTop )
59 else if ( alignment & Qt::AlignBottom )
61 else if ( alignment & Qt::AlignVCenter )
64 else if ( alignment & Qt::AlignBaseline )
72 return static_cast< int >(
c.convertToPainterUnits( size, unit, mapUnitScale ) + 0.5 );
92 drawDocument( rect, lFormat, metrics.
document(), metrics, context, alignment, vAlignment, rotation, mode, flags );
97 const QgsTextFormat tmpFormat = updateShadowPosition( format );
117 lFormat = updateShadowPosition( lFormat );
147 lFormat = updateShadowPosition( lFormat );
154 drawDocumentOnLine( line, lFormat, document, context, offsetAlongLine, offsetFromLine );
159 QPolygonF labelBaselineCurve = line;
168#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11
169 if ( offsetFromLine < 0 )
172 std::unique_ptr < QgsLineString > reversed( offsetCurve->reversed() );
176 offsetCurve = std::move( reversed );
180 labelBaselineCurve = offsetCurve->asQPolygonF();
185 const QFont baseFont = format.
scaledFont( context, fontScale );
186 const double letterSpacing = baseFont.letterSpacing() / fontScale;
187 const double wordSpacing = baseFont.wordSpacing() / fontScale;
189 QStringList graphemes;
190 QVector< QgsTextCharacterFormat > graphemeFormats;
191 QVector< QgsTextDocumentMetrics > graphemeMetrics;
193 for (
const QgsTextBlock &block : std::as_const( document ) )
198 for (
const QString &grapheme : fragmentGraphemes )
200 graphemes.append( grapheme );
201 graphemeFormats.append( fragment.characterFormat() );
211 QVector< double > characterWidths( graphemes.count() );
212 QVector< double > characterHeights( graphemes.count() );
213 QVector< double > characterDescents( graphemes.count() );
214 QFont previousNonSuperSubScriptFont;
216 for (
int i = 0; i < graphemes.count(); i++ )
221 double graphemeFirstCharHorizontalAdvanceWithLetterSpacing = 0;
222 double graphemeFirstCharHorizontalAdvance = 0;
223 double graphemeHorizontalAdvance = 0;
224 double characterDescent = 0;
225 double characterHeight = 0;
228 QFont graphemeFont = baseFont;
232 previousNonSuperSubScriptFont = graphemeFont;
239 previousNonSuperSubScriptFont = graphemeFont;
260 previousNonSuperSubScriptFont = graphemeFont;
263 const QFontMetricsF graphemeFontMetrics( graphemeFont );
264 graphemeFirstCharHorizontalAdvance = graphemeFontMetrics.horizontalAdvance( QString( graphemes[i].at( 0 ) ) ) / fontScale;
265 graphemeFirstCharHorizontalAdvanceWithLetterSpacing = graphemeFontMetrics.horizontalAdvance( graphemes[i].at( 0 ) ) / fontScale + letterSpacing;
266 graphemeHorizontalAdvance = graphemeFontMetrics.horizontalAdvance( QString( graphemes[i] ) ) / fontScale;
267 characterDescent = graphemeFontMetrics.descent() / fontScale;
268 characterHeight = graphemeFontMetrics.height() / fontScale;
270 qreal wordSpaceFix = qreal( 0.0 );
271 if ( graphemes[i] == QLatin1String(
" " ) )
275 wordSpaceFix = ( nxt < graphemes.count() && graphemes[nxt] != QLatin1String(
" " ) ) ? wordSpacing : qreal( 0.0 );
280 if ( graphemes[i].length() == 1 &&
281 !
qgsDoubleNear( graphemeFirstCharHorizontalAdvance, graphemeFirstCharHorizontalAdvanceWithLetterSpacing ) )
284 wordSpaceFix -= wordSpacing;
287 const double charWidth = graphemeHorizontalAdvance + wordSpaceFix;
288 characterWidths[i] = charWidth;
289 characterHeights[i] = characterHeight;
290 characterDescents[i] = characterDescent;
293 QgsPrecalculatedTextMetrics metrics( graphemes, std::move( characterWidths ), std::move( characterHeights ), std::move( characterDescents ) );
297 metrics, labelBaselineCurve, offsetAlongLine,
304 if ( placement->graphemePlacement.empty() )
311 QHash< int, QgsTextRenderer::Component > components;
312 components.reserve( placement->graphemePlacement.size() );
315 QgsTextRenderer::Component component;
316 component.origin = QPointF( grapheme.x, grapheme.y );
317 component.rotation = -grapheme.angle;
323 component.origin.rx() += verticalOffset * std::cos( grapheme.angle + M_PI_2 );
324 component.origin.ry() += verticalOffset * std::sin( grapheme.angle + M_PI_2 );
327 components.insert( grapheme.graphemeIndex, component );
335 const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
345 const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
362 const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
415 component.dpiRatio = 1.0;
416 component.origin = rect.topLeft();
417 component.rotation = rotation;
418 component.size = rect.size();
419 component.hAlign = alignment;
432 double xc = rect.width() / 2.0;
433 double yc = rect.height() / 2.0;
435 double angle = -rotation;
436 double xd = xc * std::cos( angle ) - yc * std::sin( angle );
437 double yd = xc * std::sin( angle ) + yc * std::cos( angle );
439 component.center = QPointF( component.origin.x() + xd, component.origin.y() + yd );
443 component.center = rect.center();
446 switch ( vAlignment )
472 drawTextInternal( part, context, format, component,
474 alignment, vAlignment, mode );
497 component.dpiRatio = 1.0;
498 component.origin = origin;
499 component.rotation = rotation;
500 component.hAlign = alignment;
509 QgsTextRenderer::drawBackground( context, component, format, metrics, mode );
522 drawTextInternal( part, context, format, component,
534 return QFontMetricsF( format.
scaledFont( context, scaleFactor ), context.
painter() ? context.
painter()->device() : nullptr );
541 QPainter *p = context.
painter();
546 if ( component.rotation >= -315 && component.rotation < -90 )
550 else if ( component.rotation >= -90 && component.rotation < -45 )
568 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
579 referenceScaleOverride.reset();
582 path.setFillRule( Qt::WindingFill );
584 double height = component.size.height();
585 switch ( orientation )
590 int fragmentIndex = 0;
593 QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, fragmentIndex );
595 if ( !fragment.isWhitespace() && !fragment.isImage() )
597 if ( component.extraWordSpacing || component.extraLetterSpacing )
598 applyExtraSpacingForLineJustification( fragmentFont, component.extraWordSpacing, component.extraLetterSpacing );
601 path.addText( xOffset, yOffset, fragmentFont, fragment.text() );
615 double partYOffset = component.offset.y() * scaleFactor;
618 double partLastDescent = 0;
620 int fragmentIndex = 0;
623 const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, component.firstFragmentIndex + fragmentIndex );
624 const double letterSpacing = fragmentFont.letterSpacing() / scaleFactor;
626 const QFontMetricsF fragmentMetrics( fragmentFont );
628 const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode );
631 for (
const QString &part : parts )
633 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / scaleFactor - letterSpacing ) ) / 2;
634 partYOffset += fragmentMetrics.ascent() / scaleFactor;
635 path.addText( partXOffset, partYOffset + fragmentYOffset, fragmentFont, part );
636 partYOffset += letterSpacing;
638 partLastDescent = fragmentMetrics.descent() / scaleFactor;
642 height = partYOffset + partLastDescent;
643 advance = partYOffset - component.offset.y() * scaleFactor;
648 QColor bufferColor = buffer.
color();
649 bufferColor.setAlphaF( buffer.
opacity() );
650 QPen pen( bufferColor );
651 pen.setWidthF( penSize * scaleFactor );
653 QColor tmpColor( bufferColor );
657 tmpColor.setAlpha( 0 );
663 buffp.begin( &buffPict );
667 std::unique_ptr< QgsPaintEffect > tmpEffect( buffer.
paintEffect()->
clone() );
669 tmpEffect->begin( context );
670 context.
painter()->setPen( pen );
671 context.
painter()->setBrush( tmpColor );
672 if ( scaleFactor != 1.0 )
673 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
674 context.
painter()->drawPath( path );
675 if ( scaleFactor != 1.0 )
676 context.
painter()->scale( scaleFactor, scaleFactor );
677 tmpEffect->end( context );
683 if ( scaleFactor != 1.0 )
684 buffp.scale( 1 / scaleFactor, 1 / scaleFactor );
686 buffp.setBrush( tmpColor );
687 buffp.drawPath( path );
693 QgsTextRenderer::Component bufferComponent = component;
694 bufferComponent.origin = QPointF( 0.0, 0.0 );
695 bufferComponent.picture = buffPict;
696 bufferComponent.pictureBuffer = penSize / 2.0;
697 bufferComponent.size.setHeight( height );
701 bufferComponent.offset.setY( - bufferComponent.size.height() );
703 drawShadow( context, bufferComponent, format );
711 p->setCompositionMode( buffer.
blendMode() );
715 p->scale( component.dpiRatio, component.dpiRatio );
717 p->drawPicture( 0, 0, buffPict );
719 return advance / scaleFactor;
739 path.setFillRule( Qt::WindingFill );
746 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
757 referenceScaleOverride.reset();
760 int fragmentIndex = 0;
763 if ( !fragment.isWhitespace() && !fragment.isImage() )
765 const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, fragmentIndex );
767 const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode );
768 path.addText( xOffset, fragmentYOffset, fragmentFont, fragment.text() );
775 QColor bufferColor( Qt::gray );
776 bufferColor.setAlphaF( mask.
opacity() );
780 brush.setColor( bufferColor );
781 pen.setColor( bufferColor );
782 pen.setWidthF( penSize * scaleFactor );
789 p->scale( component.dpiRatio, component.dpiRatio );
795 if ( scaleFactor != 1.0 )
796 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
797 context.
painter()->setPen( pen );
798 context.
painter()->setBrush( brush );
799 context.
painter()->drawPath( path );
800 if ( scaleFactor != 1.0 )
801 context.
painter()->scale( scaleFactor, scaleFactor );
806 if ( scaleFactor != 1.0 )
807 p->scale( 1 / scaleFactor, 1 / scaleFactor );
809 p->setBrush( brush );
811 if ( scaleFactor != 1.0 )
812 p->scale( scaleFactor, scaleFactor );
820 if ( doc.
size() == 0 )
823 return textWidth( context, format, doc );
840 for (
const QString &line : textLines )
844 lines.append(
wrappedText( context, line, maxLineWidth, format ) );
848 lines.append( line );
853 return textHeight( context, format, doc, mode );
860 bool isNullSize =
false;
861 const QFont baseFont = format.
scaledFont( context, scaleFactor, &isNullSize );
865 const QFontMetrics fm( baseFont );
866 const double height = ( character.isNull() ? fm.height() : fm.boundingRect( character ).height() ) / scaleFactor;
868 if ( !includeEffects )
871 double maxExtension = 0;
900 return height + maxExtension;
908 const QStringList multiLineSplit = text.split(
'\n' );
910 return currentTextWidth > width;
915 const QStringList lines = text.split(
'\n' );
916 QStringList outLines;
917 for (
const QString &line : lines )
922 const QStringList words = line.split(
' ' );
923 QStringList linesToProcess;
924 QString wordsInCurrentLine;
925 for (
const QString &word : words )
930 if ( !wordsInCurrentLine.isEmpty() )
931 linesToProcess << wordsInCurrentLine;
932 wordsInCurrentLine.clear();
933 linesToProcess << word;
937 if ( !wordsInCurrentLine.isEmpty() )
938 wordsInCurrentLine.append(
' ' );
939 wordsInCurrentLine.append( word );
942 if ( !wordsInCurrentLine.isEmpty() )
943 linesToProcess << wordsInCurrentLine;
945 for (
const QString &line : std::as_const( linesToProcess ) )
947 QString remainingText = line;
948 int lastPos = remainingText.lastIndexOf(
' ' );
949 while ( lastPos > -1 )
959 outLines << remainingText.left( lastPos );
960 remainingText = remainingText.mid( lastPos + 1 );
963 lastPos = remainingText.lastIndexOf(
' ', lastPos - 1 );
965 outLines << remainingText;
996 QPainter *prevP = context.
painter();
997 QPainter *p = context.
painter();
998 std::unique_ptr< QgsPaintEffect > tmpEffect;
1002 tmpEffect->begin( context );
1011 const double originAdjustRotationRadians = -component.rotation;
1014 component.rotation = -( component.rotation * 180 / M_PI );
1015 component.rotationOffset =
1020 component.rotation = 0.0;
1021 component.rotationOffset = background.
rotation();
1030 double width = documentSize.width();
1031 double height = documentSize.height();
1038 switch ( component.hAlign )
1042 component.center = QPointF( component.origin.x() + width / 2.0,
1043 component.origin.y() + height / 2.0 );
1047 component.center = QPointF( component.origin.x() + component.size.width() / 2.0,
1048 component.origin.y() + height / 2.0 );
1052 component.center = QPointF( component.origin.x() + component.size.width() - width / 2.0,
1053 component.origin.y() + height / 2.0 );
1060 bool isNullSize =
false;
1061 QFontMetricsF fm( format.
scaledFont( context, scaleFactor, &isNullSize ) );
1062 double originAdjust = isNullSize ? 0 : ( fm.ascent() / scaleFactor / 2.0 - fm.leading() / scaleFactor / 2.0 );
1063 switch ( component.hAlign )
1067 component.center = QPointF( component.origin.x() + width / 2.0,
1068 component.origin.y() - height / 2.0 + originAdjust );
1072 component.center = QPointF( component.origin.x(),
1073 component.origin.y() - height / 2.0 + originAdjust );
1077 component.center = QPointF( component.origin.x() - width / 2.0,
1078 component.origin.y() - height / 2.0 + originAdjust );
1085 const double dx = component.center.x() - component.origin.x();
1086 const double dy = component.center.y() - component.origin.y();
1087 component.center.setX( component.origin.x() + ( std::cos( originAdjustRotationRadians ) * dx - std::sin( originAdjustRotationRadians ) * dy ) );
1088 component.center.setY( component.origin.y() + ( std::sin( originAdjustRotationRadians ) * dx + std::cos( originAdjustRotationRadians ) * dy ) );
1098 component.size = QSizeF( width, height );
1103 switch ( background.
type() )
1116 double sizeOut = 0.0;
1127 sizeOut = std::max( component.size.width(), component.size.height() );
1131 sizeOut += bufferSize * 2;
1137 if ( sizeOut < 1.0 )
1140 std::unique_ptr< QgsMarkerSymbol > renderedSymbol;
1144 map[QStringLiteral(
"name" )] = background.
svgFile().trimmed();
1145 map[QStringLiteral(
"size" )] = QString::number( sizeOut );
1147 map[QStringLiteral(
"angle" )] = QString::number( 0.0 );
1155 map[QStringLiteral(
"fill" )] = background.
fillColor().name();
1156 map[QStringLiteral(
"outline" )] = background.
strokeColor().name();
1157 map[QStringLiteral(
"outline-width" )] = QString::number( background.
strokeWidth() );
1164 QVariantMap shdwmap( map );
1165 shdwmap[QStringLiteral(
"fill" )] = shadow.
color().name();
1166 shdwmap[QStringLiteral(
"outline" )] = shadow.
color().name();
1167 shdwmap[QStringLiteral(
"size" )] = QString::number( sizeOut );
1172 svgp.begin( &svgPict );
1189 svgShdwM->
renderPoint( QPointF( sizeOut / 2, -sizeOut / 2 ), svgShdwContext );
1192 component.picture = svgPict;
1194 component.pictureBuffer = 0.0;
1196 component.size = QSizeF( sizeOut, sizeOut );
1197 component.offset = QPointF( 0.0, 0.0 );
1203 p->translate( component.center.x(), component.center.y() );
1204 p->rotate( component.rotation );
1207 p->translate( QPointF( xoff, yoff ) );
1208 p->rotate( component.rotationOffset );
1209 p->translate( -sizeOut / 2, sizeOut / 2 );
1211 drawShadow( context, component, format );
1213 renderedSymbol.reset( );
1221 renderedSymbol->setSize( sizeOut );
1225 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1233 p->setCompositionMode( background.
blendMode() );
1235 p->translate( component.center.x(), component.center.y() );
1236 p->rotate( component.rotation );
1239 p->translate( QPointF( xoff, yoff ) );
1240 p->rotate( component.rotationOffset );
1244 renderedSymbol->renderPoint( QPointF( 0, 0 ), &f, context );
1245 renderedSymbol->stopRender( context );
1246 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1256 double w = component.size.width();
1257 double h = component.size.height();
1278 h = std::sqrt( std::pow( w, 2 ) + std::pow( h, 2 ) );
1284 h = h * M_SQRT1_2 * 2;
1285 w = w * M_SQRT1_2 * 2;
1293 w += bufferWidth * 2;
1294 h += bufferHeight * 2;
1298 QRectF rect( -w / 2.0, - h / 2.0, w, h );
1300 if ( rect.isNull() )
1306 p->translate( QPointF( component.center.x(), component.center.y() ) );
1307 p->rotate( component.rotation );
1310 p->translate( QPointF( xoff, yoff ) );
1311 p->rotate( component.rotationOffset );
1317 QTransform t = QTransform::fromScale( 10, 10 );
1319 QTransform ti = t.inverted();
1326 path.addRoundedRect( rect, background.
radii().width(), background.
radii().height(), Qt::RelativeSize );
1332 path.addRoundedRect( rect, xRadius, yRadius );
1338 path.addEllipse( rect );
1340 QPolygonF tempPolygon = path.toFillPolygon( t );
1341 QPolygonF polygon = ti.map( tempPolygon );
1343 QPainter *oldp = context.
painter();
1346 shapep.begin( &shapePict );
1349 std::unique_ptr< QgsFillSymbol > renderedSymbol;
1351 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1355 renderedSymbol->renderPolygon( polygon,
nullptr, &f, context );
1356 renderedSymbol->stopRender( context );
1363 component.picture = shapePict;
1366 component.size = rect.size();
1367 component.offset = QPointF( rect.width() / 2, -rect.height() / 2 );
1368 drawShadow( context, component, format );
1373 p->setCompositionMode( background.
blendMode() );
1377 p->scale( component.dpiRatio, component.dpiRatio );
1379 p->drawPicture( 0, 0, shapePict );
1380 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1387 tmpEffect->end( context );
1400 QPainter *p = context.
painter();
1401 const double componentWidth = component.size.width();
1402 const double componentHeight = component.size.height();
1403 double xOffset = component.offset.x(), yOffset = component.offset.y();
1404 double pictbuffer = component.pictureBuffer;
1413 radius /= ( mapUnits ? context.
scaleFactor() / component.dpiRatio : 1 );
1414 radius =
static_cast< int >( radius + 0.5 );
1418 double blurBufferClippingScale = 3.75;
1419 int blurbuffer = ( radius > 17 ? 16 : radius ) * blurBufferClippingScale;
1421 QImage blurImg( componentWidth + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1422 componentHeight + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1423 QImage::Format_ARGB32_Premultiplied );
1427 int minBlurImgSize = 1;
1431 int maxBlurImgSize = 40000;
1432 if ( blurImg.isNull()
1433 || ( blurImg.width() < minBlurImgSize || blurImg.height() < minBlurImgSize )
1434 || ( blurImg.width() > maxBlurImgSize || blurImg.height() > maxBlurImgSize ) )
1437 blurImg.fill( QColor( Qt::transparent ).rgba() );
1439 if ( !pictp.begin( &blurImg ) )
1441 pictp.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
1442 QPointF imgOffset( blurbuffer + pictbuffer + xOffset,
1443 blurbuffer + pictbuffer + componentHeight + yOffset );
1445 pictp.drawPicture( imgOffset,
1446 component.picture );
1449 pictp.setCompositionMode( QPainter::CompositionMode_SourceIn );
1450 pictp.fillRect( blurImg.rect(), shadow.
color() );
1454 if ( shadow.
blurRadius() > 0.0 && radius > 0 )
1462 picti.begin( &blurImg );
1463 picti.setBrush( Qt::Dense7Pattern );
1464 QPen imgPen( QColor( 0, 0, 255, 255 ) );
1465 imgPen.setWidth( 1 );
1466 picti.setPen( imgPen );
1467 picti.setOpacity( 0.1 );
1468 picti.drawRect( 0, 0, blurImg.width(), blurImg.height() );
1475 double angleRad = shadow.
offsetAngle() * M_PI / 180;
1483 angleRad -= ( component.rotation * M_PI / 180 + component.rotationOffset * M_PI / 180 );
1486 QPointF transPt( -offsetDist * std::cos( angleRad + M_PI_2 ),
1487 -offsetDist * std::sin( angleRad + M_PI_2 ) );
1493 p->setRenderHint( QPainter::SmoothPixmapTransform );
1496 p->setCompositionMode( shadow.
blendMode() );
1498 p->setOpacity( shadow.
opacity() );
1500 double scale = shadow.
scale() / 100.0;
1502 p->scale( scale, scale );
1503 if ( component.useOrigin )
1505 p->translate( component.origin.x(), component.origin.y() );
1507 p->translate( transPt );
1508 p->translate( -imgOffset.x(),
1510 p->drawImage( 0, 0, blurImg );
1517 p->setBrush( Qt::NoBrush );
1518 QPen imgPen( QColor( 255, 0, 0, 10 ) );
1519 imgPen.setWidth( 2 );
1520 imgPen.setStyle( Qt::DashLine );
1521 p->setPen( imgPen );
1522 p->scale( scale, scale );
1523 if ( component.useOrigin() )
1525 p->translate( component.origin().x(), component.origin().y() );
1527 p->translate( transPt );
1528 p->translate( -imgOffset.x(),
1530 p->drawRect( 0, 0, blurImg.width(), blurImg.height() );
1535 p->setBrush( Qt::NoBrush );
1536 QPen componentRectPen( QColor( 0, 255, 0, 70 ) );
1537 componentRectPen.setWidth( 1 );
1538 if ( component.useOrigin() )
1540 p->translate( component.origin().x(), component.origin().y() );
1542 p->setPen( componentRectPen );
1543 p->drawRect( QRect( -xOffset, -componentHeight - yOffset, componentWidth, componentHeight ) );
1552 const Component &component,
1564 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1575 referenceScaleOverride.reset();
1577 double rotation = 0;
1578 const Qgis::TextOrientation orientation = calculateRotationAndOrientationForComponent( format, component, rotation );
1579 switch ( orientation )
1583 drawTextInternalHorizontal( context, format, drawType, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
1590 drawTextInternalVertical( context, format, drawType, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
1596Qgis::TextOrientation QgsTextRenderer::calculateRotationAndOrientationForComponent(
const QgsTextFormat &format,
const QgsTextRenderer::Component &component,
double &rotation )
1598 rotation = -component.rotation * 180 / M_PI;
1605 if ( rotation >= -315 && rotation < -90 )
1610 else if ( rotation >= -90 && rotation < -45 )
1626void QgsTextRenderer::calculateExtraSpacingForLineJustification(
const double spaceToDistribute,
const QgsTextBlock &block,
double &extraWordSpace,
double &extraLetterSpace )
1629 QTextBoundaryFinder
finder( QTextBoundaryFinder::Word, blockText );
1631 int wordBoundaries = 0;
1632 while (
finder.toNextBoundary() != -1 )
1634 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1638 if ( wordBoundaries > 0 )
1641 extraWordSpace = spaceToDistribute / wordBoundaries;
1646 QTextBoundaryFinder
finder( QTextBoundaryFinder::Grapheme, blockText );
1649 int graphemeBoundaries = 0;
1650 while (
finder.toNextBoundary() != -1 )
1652 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1653 graphemeBoundaries++;
1656 if ( graphemeBoundaries > 0 )
1658 extraLetterSpace = spaceToDistribute / graphemeBoundaries;
1663void QgsTextRenderer::applyExtraSpacingForLineJustification( QFont &font,
double extraWordSpace,
double extraLetterSpace )
1665 const double prevWordSpace = font.wordSpacing();
1666 font.setWordSpacing( prevWordSpace + extraWordSpace );
1667 const double prevLetterSpace = font.letterSpacing();
1668 font.setLetterSpacing( QFont::AbsoluteSpacing, prevLetterSpace + extraLetterSpace );
1672void QgsTextRenderer::renderBlockHorizontal(
const QgsTextBlock &block,
int blockIndex,
1675 QPainter *painter,
bool usePaths,
1676 double fontScale,
double extraWordSpace,
double extraLetterSpace,
1682 int fragmentIndex = 0;
1686 if ( !fragment.isWhitespace() && !fragment.isImage() )
1688 QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
1691 applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
1695 QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
1696 textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.opacity() );
1700 painter->setBrush( textColor );
1702 path.setFillRule( Qt::WindingFill );
1703 path.addText( xOffset, yOffset, fragmentFont, fragment.text() );
1704 painter->drawPath( path );
1708 painter->setPen( textColor );
1709 painter->setFont( fragmentFont );
1710 painter->drawText( QPointF( xOffset, yOffset ), fragment.text() );
1713 else if ( fragment.isImage() )
1715 bool fitsInCache =
false;
1717 const double imageHeight = metrics.
fragmentFixedHeight( blockIndex, fragmentIndex, mode ) * fontScale;
1720 QSize(
static_cast< int >( std::round( imageWidth ) ),
1721 static_cast< int >( std::round( imageHeight ) ) ),
1725 const double yOffset = imageBaseline - image.height();
1726 if ( !image.isNull() )
1727 painter->drawImage( QPointF( xOffset, yOffset ), image );
1758 if ( format.
font().underline()
1759 || format.
font().overline()
1760 || format.
font().strikeOut()
1761 || std::any_of( document.begin(), document.end(), [](
const QgsTextBlock & block )
1763 return std::any_of( block.begin(), block.end(), []( const QgsTextFragment & fragment )
1765 return fragment.characterFormat().underline() == QgsTextCharacterFormat::BooleanValue::SetTrue
1766 || fragment.characterFormat().overline() == QgsTextCharacterFormat::BooleanValue::SetTrue
1767 || fragment.characterFormat().strikeOut() == QgsTextCharacterFormat::BooleanValue::SetTrue;
1781 const QStringList textLines = document.
toPlainText();
1785 double labelWidest = 0.0;
1790 labelWidest = documentSize.width();
1796 labelWidest = component.size.width();
1800 double verticalAlignOffset = 0;
1804 const double overallHeight = documentSize.height();
1805 switch ( vAlignment )
1812 verticalAlignOffset = ( component.size.height() - overallHeight ) * 0.5 + metrics.
blockVerticalMargin( - 1 );
1816 verticalAlignOffset = ( component.size.height() - overallHeight ) + metrics.
blockVerticalMargin( - 1 );
1826 const bool usePaths = usePathsToRender( context, format, document );
1836 || textLines.size() > 1 );
1838 const bool isFinalLineInParagraph = ( blockIndex == document.
size() - 1 )
1839 || document.
at( blockIndex + 1 ).
toPlainText().trimmed().isEmpty();
1841 const double blockHeight = metrics.
blockHeight( blockIndex );
1845 context.
painter()->translate( component.origin );
1847 context.
painter()->rotate( rotation );
1852 maskPainter->save();
1853 maskPainter->translate( component.origin );
1855 maskPainter->rotate( rotation );
1859 double xMultiLineOffset = 0.0;
1860 double blockWidth = metrics.
blockWidth( blockIndex );
1861 double extraWordSpace = 0;
1862 double extraLetterSpace = 0;
1863 if ( adjustForAlignment )
1865 double labelWidthDiff = 0;
1866 switch ( blockAlignment )
1873 labelWidthDiff = labelWidest - blockWidth - metrics.
blockRightMargin( blockIndex );
1877 if ( !isFinalLineInParagraph && labelWidest > blockWidth )
1879 calculateExtraSpacingForLineJustification( labelWidest - blockWidth, block, extraWordSpace, extraLetterSpace );
1880 blockWidth = labelWidest;
1896 xMultiLineOffset = labelWidthDiff;
1901 switch ( blockAlignment )
1904 xMultiLineOffset = labelWidthDiff - labelWidest;
1908 xMultiLineOffset = labelWidthDiff - labelWidest / 2.0;
1925 const double baseLineOffset = metrics.
baselineOffset( blockIndex, mode );
1927 context.
painter()->translate( QPointF( xMultiLineOffset, baseLineOffset + verticalAlignOffset ) );
1929 maskPainter->translate( QPointF( xMultiLineOffset, baseLineOffset + verticalAlignOffset ) );
1931 Component subComponent;
1932 subComponent.block = block;
1933 subComponent.blockIndex = blockIndex;
1934 subComponent.
size = QSizeF( blockWidth, blockHeight );
1935 subComponent.offset = QPointF( 0.0, -metrics.
ascentOffset() );
1936 subComponent.rotation = -component.rotation * 180 / M_PI;
1937 subComponent.rotationOffset = 0.0;
1938 subComponent.extraWordSpacing = extraWordSpace * fontScale;
1939 subComponent.extraLetterSpacing = extraLetterSpace * fontScale;
1944 QgsTextRenderer::drawMask( context, subComponent, format, metrics, mode );
1949 QgsTextRenderer::drawBuffer( context, subComponent, format, metrics, mode );
1957 const bool requiresPicture = drawShadowOnText;
1959 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1967 referenceScaleOverride.reset();
1969 std::unique_ptr< QPicture > textPicture;
1970 if ( requiresPicture )
1973 textPicture = std::make_unique< QPicture >();
1974 QPainter picturePainter( textPicture.get() );
1975 picturePainter.setPen( Qt::NoPen );
1976 picturePainter.setBrush( Qt::NoBrush );
1977 picturePainter.scale( 1 / fontScale, 1 / fontScale );
1978 renderBlockHorizontal( block, blockIndex, metrics, context, format, &picturePainter, usePaths,
1979 fontScale, extraWordSpace, extraLetterSpace, mode );
1980 picturePainter.end();
1983 if ( drawShadowOnText )
1985 subComponent.picture = *textPicture;
1986 subComponent.pictureBuffer = 0.0;
1987 subComponent.origin = QPointF( 0.0, 0.0 );
1989 QgsTextRenderer::drawShadow( context, subComponent, format );
1999 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
2004 context.
painter()->drawPicture( 0, 0, *textPicture );
2008 context.
painter()->scale( 1 / fontScale, 1 / fontScale );
2009 context.
painter()->setPen( Qt::NoPen );
2010 context.
painter()->setBrush( Qt::NoBrush );
2011 renderBlockHorizontal( block, blockIndex, metrics, context, format, context.
painter(), usePaths,
2012 fontScale, extraWordSpace, extraLetterSpace, mode );
2016 maskPainter->restore();
2022void 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 )
2025 const QStringList textLines = document.
toPlainText();
2027 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
2038 referenceScaleOverride.reset();
2041 const double actualTextWidth = documentSize.width();
2042 double textRectWidth = 0.0;
2048 textRectWidth = actualTextWidth;
2054 textRectWidth = component.size.width();
2058 int maxLineLength = 0;
2059 for (
const QString &line : std::as_const( textLines ) )
2061 maxLineLength = std::max( maxLineLength,
static_cast<int>( line.length() ) );
2064 const double actualLabelHeight = documentSize.height();
2074 context.
painter()->translate( component.origin );
2076 context.
painter()->rotate( rotation );
2081 maskPainter->save();
2082 maskPainter->translate( component.origin );
2084 maskPainter->rotate( rotation );
2091 if ( adjustForAlignment )
2093 double hAlignmentOffset = 0;
2094 switch ( hAlignment )
2097 hAlignmentOffset = ( textRectWidth - actualTextWidth ) * 0.5;
2101 hAlignmentOffset = textRectWidth - actualTextWidth;
2115 xOffset += hAlignmentOffset;
2123 double yOffset = 0.0;
2129 if ( rotation >= -405 && rotation < -180 )
2133 else if ( rotation >= 0 && rotation < 45 )
2135 xOffset -= actualTextWidth;
2141 yOffset = -actualLabelHeight;
2146 yOffset = -actualLabelHeight;
2156 context.
painter()->translate( QPointF( xOffset, yOffset ) );
2158 double currentBlockYOffset = 0;
2159 int fragmentIndex = 0;
2167 const QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
2169 QFontMetricsF fragmentMetrics( fragmentFont );
2171 const double letterSpacing = fragmentFont.letterSpacing() / fontScale;
2172 const double labelHeight = fragmentMetrics.ascent() / fontScale + ( fragmentMetrics.ascent() / fontScale + letterSpacing ) * ( line.length() - 1 );
2174 Component subComponent;
2176 subComponent.blockIndex = blockIndex;
2177 subComponent.firstFragmentIndex = fragmentIndex;
2178 subComponent.size = QSizeF( blockMaximumCharacterWidth, labelHeight + fragmentMetrics.descent() / fontScale );
2179 subComponent.offset = QPointF( 0.0, currentBlockYOffset );
2180 subComponent.rotation = -component.rotation * 180 / M_PI;
2181 subComponent.rotationOffset = 0.0;
2188 QgsTextRenderer::drawMask( context, subComponent, format );
2194 currentBlockYOffset += QgsTextRenderer::drawBuffer( context, subComponent, format, metrics, mode );
2200 path.setFillRule( Qt::WindingFill );
2202 double partYOffset = 0.0;
2203 for (
const QString &part : parts )
2205 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
2206 partYOffset += fragmentMetrics.ascent() / fontScale;
2207 path.addText( partXOffset * fontScale, partYOffset * fontScale, fragmentFont, part );
2208 partYOffset += letterSpacing;
2214 textp.begin( &textPict );
2215 textp.setPen( Qt::NoPen );
2216 QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
2217 textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.
opacity() );
2218 textp.setBrush( textColor );
2219 textp.scale( 1 / fontScale, 1 / fontScale );
2220 textp.drawPath( path );
2231 subComponent.picture = textPict;
2232 subComponent.pictureBuffer = 0.0;
2233 subComponent.origin = QPointF( 0.0, currentBlockYOffset );
2234 const double prevY = subComponent.offset.y();
2235 subComponent.offset = QPointF( 0, -subComponent.size.height() );
2236 subComponent.useOrigin =
true;
2237 QgsTextRenderer::drawShadow( context, subComponent, format );
2238 subComponent.useOrigin =
false;
2239 subComponent.offset = QPointF( 0, prevY );
2249 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
2253 context.
painter()->translate( 0, currentBlockYOffset );
2255 context.
painter()->drawPicture( 0, 0, textPict );
2256 currentBlockYOffset += partYOffset;
2262 maskPainter->restore();
2280 if ( pixelSize < 50 )
2281 return 200 / pixelSize;
2284 else if ( pixelSize > 200 )
2285 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.
@ PreferText
Render text as text objects, unless doing so results in rendering artifacts or poor quality rendering...
@ 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 ...
@ RenderBlocking
Render and load remote sources in the same thread to ensure rendering remote sources (svg and images)...
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.
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
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*.
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache, bool blocking=false, double targetDpi=96, int frameNumber=-1, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
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 void applyScaleFixForQPictureDpi(QPainter *painter)
Applies a workaround to a painter to avoid an issue with incorrect scaling when drawing QPictures.
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.
Qgis::TextHorizontalAlignment horizontalAlignment() const
Returns the format horizontal alignment.
bool hasHorizontalAlignmentSet() const
Returns true if the format has an explicit horizontal alignment set.
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.
const QgsTextBlockFormat & blockFormat() const
Returns the block formatting for the fragment.
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.
double blockRightMargin(int blockIndex) const
Returns the margin for the right side of the specified block index.
static QgsTextDocumentMetrics calculateMetrics(const QgsTextDocument &document, const QgsTextFormat &format, const QgsRenderContext &context, double scaleFactor=1.0, const QgsTextDocumentRenderContext &documentContext=QgsTextDocumentRenderContext())
Returns precalculated text metrics for a text document, when rendered using the given base format and...
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.
double fragmentFixedHeight(int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode) const
Returns the fixed height of the fragment at the specified block and fragment index,...
double blockLeftMargin(int blockIndex) const
Returns the margin for the left side of the specified block index.
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.
const QgsTextDocument & document() const
Returns the document associated with the calculated metrics.
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.
double blockVerticalMargin(int blockIndex) const
Returns the vertical margin for the specified block index.
Encapsulates the context in which a text document is to be rendered.
void setFlags(Qgis::TextRendererFlags flags)
Sets associated text renderer flags.
void setMaximumWidth(double width)
Sets the maximum width (in painter units) for rendered text.
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.
void append(const QgsTextBlock &block)
Appends a block to the document.
static QgsTextDocument fromTextAndFormat(const QStringList &lines, const QgsTextFormat &format)
Constructor for QgsTextDocument consisting of a set of lines, respecting settings from a text format.
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.
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.
QFont font() const
Returns the font used for rendering text.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
Stores a fragment of document 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 double calculateScaleFactorForFormat(const QgsRenderContext &context, const QgsTextFormat &format)
Returns the scale factor used for upscaling font sizes and downscaling destination painter devices.
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 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
#define BUILTIN_UNREACHABLE
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< QgsSymbolLayer * > QgsSymbolLayerList