32#include <QTextBoundaryFinder>
37static void _fixQPictureDPI( QPainter *p )
43 p->scale(
static_cast< double >(
qt_defaultDpiX() ) / p->device()->logicalDpiX(),
44 static_cast< double >(
qt_defaultDpiY() ) / p->device()->logicalDpiY() );
49 if ( alignment & Qt::AlignLeft )
50 return Qgis::TextHorizontalAlignment::Left;
51 else if ( alignment & Qt::AlignRight )
52 return Qgis::TextHorizontalAlignment::Right;
53 else if ( alignment & Qt::AlignHCenter )
54 return Qgis::TextHorizontalAlignment::Center;
55 else if ( alignment & Qt::AlignJustify )
56 return Qgis::TextHorizontalAlignment::Justify;
59 return Qgis::TextHorizontalAlignment::Left;
64 if ( alignment & Qt::AlignTop )
65 return Qgis::TextVerticalAlignment::Top;
66 else if ( alignment & Qt::AlignBottom )
67 return Qgis::TextVerticalAlignment::Bottom;
68 else if ( alignment & Qt::AlignVCenter )
69 return Qgis::TextVerticalAlignment::VerticalCenter;
71 else if ( alignment & Qt::AlignBaseline )
72 return Qgis::TextVerticalAlignment::Bottom;
74 return Qgis::TextVerticalAlignment::Top;
79 return static_cast< int >(
c.convertToPainterUnits( size, unit, mapUnitScale ) + 0.5 );
89 QStringList textLines;
90 for (
const QString &line : text )
94 textLines.append(
wrappedText( context, line, rect.width(), format ) );
98 textLines.append( line );
105 const double fontScale = calculateScaleFactorForFormat( context, format );
108 drawDocument( rect, tmpFormat, document, metrics, context, alignment, vAlignment, rotation, mode, flags );
113 const QgsTextFormat tmpFormat = updateShadowPosition( format );
133 tmpFormat = updateShadowPosition( tmpFormat );
137 const double fontScale = calculateScaleFactorForFormat( context, format );
178 const double fontScale = calculateScaleFactorForFormat( context, format );
181 drawPart( rect, rotation, alignment, Qgis::TextVerticalAlignment::Top, document, metrics, context, format, part, Qgis::TextLayoutMode::Rectangle );
192 component.dpiRatio = 1.0;
193 component.origin = rect.topLeft();
194 component.rotation = rotation;
195 component.size = rect.size();
196 component.hAlign = alignment;
209 double xc = rect.width() / 2.0;
210 double yc = rect.height() / 2.0;
212 double angle = -rotation;
213 double xd = xc * std::cos(
angle ) - yc * std::sin(
angle );
214 double yd = xc * std::sin(
angle ) + yc * std::cos(
angle );
216 component.center = QPointF( component.origin.x() + xd, component.origin.y() + yd );
220 component.center = rect.center();
223 switch ( vAlignment )
225 case Qgis::TextVerticalAlignment::Top:
227 case Qgis::TextVerticalAlignment::VerticalCenter:
230 case Qgis::TextVerticalAlignment::Bottom:
235 QgsTextRenderer::drawBackground( context, component, format, metrics, Qgis::TextLayoutMode::Rectangle );
249 drawTextInternal( part, context, format, component,
251 alignment, vAlignment, mode );
260 const double fontScale = calculateScaleFactorForFormat( context, format );
274 component.dpiRatio = 1.0;
275 component.origin = origin;
276 component.rotation = rotation;
277 component.hAlign = alignment;
286 QgsTextRenderer::drawBackground( context, component, format, metrics, mode );
299 drawTextInternal( part, context, format, component,
302 alignment, Qgis::TextVerticalAlignment::Top,
311 return QFontMetricsF( format.
scaledFont( context, scaleFactor ), context.
painter() ? context.
painter()->device() :
nullptr );
318 QPainter *p = context.
painter();
321 if ( format.
orientation() == Qgis::TextOrientation::RotationBased )
323 if ( component.rotation >= -315 && component.rotation < -90 )
325 orientation = Qgis::TextOrientation::Vertical;
327 else if ( component.rotation >= -90 && component.rotation < -45 )
329 orientation = Qgis::TextOrientation::Vertical;
333 orientation = Qgis::TextOrientation::Horizontal;
339 const double penSize = buffer.
sizeUnit() == Qgis::RenderUnit::Percentage
343 const double scaleFactor = calculateScaleFactorForFormat( context, format );
345 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
346 if ( mode == Qgis::TextLayoutMode::Labeling )
356 referenceScaleOverride.reset();
359 path.setFillRule( Qt::WindingFill );
361 double height = component.size.height();
362 switch ( orientation )
364 case Qgis::TextOrientation::Horizontal:
367 int fragmentIndex = 0;
370 QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, fragmentIndex );
372 if ( component.extraWordSpacing || component.extraLetterSpacing )
373 applyExtraSpacingForLineJustification( fragmentFont, component.extraWordSpacing, component.extraLetterSpacing );
376 path.addText( xOffset, yOffset, fragmentFont, fragment.
text() );
386 case Qgis::TextOrientation::Vertical:
387 case Qgis::TextOrientation::RotationBased:
389 double partYOffset = component.offset.y() * scaleFactor;
392 double partLastDescent = 0;
394 int fragmentIndex = 0;
397 const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, component.firstFragmentIndex + fragmentIndex );
398 const double letterSpacing = fragmentFont.letterSpacing() / scaleFactor;
400 const QFontMetricsF fragmentMetrics( fragmentFont );
402 const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode )
406 for (
const QString &part : parts )
408 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / scaleFactor - letterSpacing ) ) / 2;
409 partYOffset += fragmentMetrics.ascent() / scaleFactor;
410 path.addText( partXOffset, partYOffset + fragmentYOffset, fragmentFont, part );
411 partYOffset += letterSpacing;
413 partLastDescent = fragmentMetrics.descent() / scaleFactor;
417 height = partYOffset + partLastDescent;
418 advance = partYOffset - component.offset.y() * scaleFactor;
423 QColor bufferColor = buffer.
color();
424 bufferColor.setAlphaF( buffer.
opacity() );
425 QPen pen( bufferColor );
426 pen.setWidthF( penSize * scaleFactor );
428 QColor tmpColor( bufferColor );
432 tmpColor.setAlpha( 0 );
438 buffp.begin( &buffPict );
442 std::unique_ptr< QgsPaintEffect > tmpEffect( buffer.
paintEffect()->
clone() );
444 tmpEffect->begin( context );
445 context.
painter()->setPen( pen );
446 context.
painter()->setBrush( tmpColor );
447 if ( scaleFactor != 1.0 )
448 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
449 context.
painter()->drawPath( path );
450 if ( scaleFactor != 1.0 )
451 context.
painter()->scale( scaleFactor, scaleFactor );
452 tmpEffect->end( context );
458 if ( scaleFactor != 1.0 )
459 buffp.scale( 1 / scaleFactor, 1 / scaleFactor );
461 buffp.setBrush( tmpColor );
462 buffp.drawPath( path );
468 QgsTextRenderer::Component bufferComponent = component;
469 bufferComponent.origin = QPointF( 0.0, 0.0 );
470 bufferComponent.picture = buffPict;
471 bufferComponent.pictureBuffer = penSize / 2.0;
472 bufferComponent.size.setHeight( height );
474 if ( format.
orientation() == Qgis::TextOrientation::Vertical || format.
orientation() == Qgis::TextOrientation::RotationBased )
476 bufferComponent.offset.setY( - bufferComponent.size.height() );
478 drawShadow( context, bufferComponent, format );
486 p->setCompositionMode( buffer.
blendMode() );
490 p->scale( component.dpiRatio, component.dpiRatio );
491 _fixQPictureDPI( p );
492 p->drawPicture( 0, 0, buffPict );
494 return advance / scaleFactor;
508 double penSize = mask.
sizeUnit() == Qgis::RenderUnit::Percentage
514 path.setFillRule( Qt::WindingFill );
516 const double scaleFactor = calculateScaleFactorForFormat( context, format );
521 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
522 if ( mode == Qgis::TextLayoutMode::Labeling )
532 referenceScaleOverride.reset();
535 int fragmentIndex = 0;
538 const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, fragmentIndex );
540 const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode );
541 path.addText( xOffset, fragmentYOffset, fragmentFont, fragment.
text() );
547 QColor bufferColor( Qt::gray );
548 bufferColor.setAlphaF( mask.
opacity() );
552 brush.setColor( bufferColor );
553 pen.setColor( bufferColor );
554 pen.setWidthF( penSize * scaleFactor );
561 p->scale( component.dpiRatio, component.dpiRatio );
567 if ( scaleFactor != 1.0 )
568 context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
569 context.
painter()->setPen( pen );
570 context.
painter()->setBrush( brush );
571 context.
painter()->drawPath( path );
572 if ( scaleFactor != 1.0 )
573 context.
painter()->scale( scaleFactor, scaleFactor );
578 if ( scaleFactor != 1.0 )
579 p->scale( 1 / scaleFactor, 1 / scaleFactor );
581 p->setBrush( brush );
583 if ( scaleFactor != 1.0 )
584 p->scale( scaleFactor, scaleFactor );
600 if ( doc.
size() == 0 )
604 return textWidth( context, format, doc );
610 const double scaleFactor = calculateScaleFactorForFormat( context, format );
621 for (
const QString &line : textLines )
625 lines.append(
wrappedText( context, line, maxLineWidth, format ) );
629 lines.append( line );
645 const double scaleFactor = calculateScaleFactorForFormat( context, format );
647 bool isNullSize =
false;
648 const QFont baseFont = format.
scaledFont( context, scaleFactor, &isNullSize );
652 const QFontMetrics fm( baseFont );
653 const double height = ( character.isNull() ? fm.height() : fm.boundingRect( character ).height() ) / scaleFactor;
655 if ( !includeEffects )
658 double maxExtension = 0;
662 maxExtension += format.
buffer().
sizeUnit() == Qgis::RenderUnit::Percentage
668 maxExtension += ( format.
shadow().
offsetUnit() == Qgis::RenderUnit::Percentage
687 return height + maxExtension;
695 const QStringList multiLineSplit = text.split(
'\n' );
697 return currentTextWidth > width;
702 const QStringList lines = text.split(
'\n' );
703 QStringList outLines;
704 for (
const QString &line : lines )
709 const QStringList words = line.split(
' ' );
710 QStringList linesToProcess;
711 QString wordsInCurrentLine;
712 for (
const QString &word : words )
717 if ( !wordsInCurrentLine.isEmpty() )
718 linesToProcess << wordsInCurrentLine;
719 wordsInCurrentLine.clear();
720 linesToProcess << word;
724 if ( !wordsInCurrentLine.isEmpty() )
725 wordsInCurrentLine.append(
' ' );
726 wordsInCurrentLine.append( word );
729 if ( !wordsInCurrentLine.isEmpty() )
730 linesToProcess << wordsInCurrentLine;
732 for (
const QString &line : std::as_const( linesToProcess ) )
734 QString remainingText = line;
735 int lastPos = remainingText.lastIndexOf(
' ' );
736 while ( lastPos > -1 )
746 outLines << remainingText.left( lastPos );
747 remainingText = remainingText.mid( lastPos + 1 );
750 lastPos = remainingText.lastIndexOf(
' ', lastPos - 1 );
752 outLines << remainingText;
770 const double scaleFactor = calculateScaleFactorForFormat( context, format );
783 QPainter *prevP = context.
painter();
784 QPainter *p = context.
painter();
785 std::unique_ptr< QgsPaintEffect > tmpEffect;
789 tmpEffect->begin( context );
798 const double originAdjustRotationRadians = -component.rotation;
801 component.rotation = -( component.rotation * 180 / M_PI );
802 component.rotationOffset =
807 component.rotation = 0.0;
808 component.rotationOffset = background.
rotation();
811 const double scaleFactor = calculateScaleFactorForFormat( context, format );
813 if ( mode != Qgis::TextLayoutMode::Labeling )
817 double width = documentSize.width();
818 double height = documentSize.height();
822 case Qgis::TextLayoutMode::Rectangle:
825 switch ( component.hAlign )
827 case Qgis::TextHorizontalAlignment::Left:
828 case Qgis::TextHorizontalAlignment::Justify:
829 component.center = QPointF( component.origin.x() + width / 2.0,
830 component.origin.y() + height / 2.0 );
833 case Qgis::TextHorizontalAlignment::Center:
834 component.center = QPointF( component.origin.x() + component.size.width() / 2.0,
835 component.origin.y() + height / 2.0 );
838 case Qgis::TextHorizontalAlignment::Right:
839 component.center = QPointF( component.origin.x() + component.size.width() - width / 2.0,
840 component.origin.y() + height / 2.0 );
847 bool isNullSize =
false;
848 QFontMetricsF fm( format.
scaledFont( context, scaleFactor, &isNullSize ) );
849 double originAdjust = isNullSize ? 0 : ( fm.ascent() / scaleFactor / 2.0 - fm.leading() / scaleFactor / 2.0 );
850 switch ( component.hAlign )
852 case Qgis::TextHorizontalAlignment::Left:
853 case Qgis::TextHorizontalAlignment::Justify:
854 component.center = QPointF( component.origin.x() + width / 2.0,
855 component.origin.y() - height / 2.0 + originAdjust );
858 case Qgis::TextHorizontalAlignment::Center:
859 component.center = QPointF( component.origin.x(),
860 component.origin.y() - height / 2.0 + originAdjust );
863 case Qgis::TextHorizontalAlignment::Right:
864 component.center = QPointF( component.origin.x() - width / 2.0,
865 component.origin.y() - height / 2.0 + originAdjust );
872 const double dx = component.center.x() - component.origin.x();
873 const double dy = component.center.y() - component.origin.y();
874 component.center.setX( component.origin.x() + ( std::cos( originAdjustRotationRadians ) * dx - std::sin( originAdjustRotationRadians ) * dy ) );
875 component.center.setY( component.origin.y() + ( std::sin( originAdjustRotationRadians ) * dx + std::cos( originAdjustRotationRadians ) * dy ) );
880 case Qgis::TextLayoutMode::Labeling:
885 component.size = QSizeF( width, height );
890 switch ( background.
type() )
903 double sizeOut = 0.0;
911 sizeOut = std::max( component.size.width(), component.size.height() );
915 sizeOut += bufferSize * 2;
923 std::unique_ptr< QgsMarkerSymbol > renderedSymbol;
927 map[QStringLiteral(
"name" )] = background.
svgFile().trimmed();
928 map[QStringLiteral(
"size" )] = QString::number( sizeOut );
930 map[QStringLiteral(
"angle" )] = QString::number( 0.0 );
938 map[QStringLiteral(
"fill" )] = background.
fillColor().name();
939 map[QStringLiteral(
"outline" )] = background.
strokeColor().name();
940 map[QStringLiteral(
"outline-width" )] = QString::number( background.
strokeWidth() );
947 QVariantMap shdwmap( map );
948 shdwmap[QStringLiteral(
"fill" )] = shadow.
color().name();
949 shdwmap[QStringLiteral(
"outline" )] = shadow.
color().name();
950 shdwmap[QStringLiteral(
"size" )] = QString::number( sizeOut );
955 svgp.begin( &svgPict );
972 svgShdwM->
renderPoint( QPointF( sizeOut / 2, -sizeOut / 2 ), svgShdwContext );
975 component.picture = svgPict;
977 component.pictureBuffer = 0.0;
979 component.size = QSizeF( sizeOut, sizeOut );
980 component.offset = QPointF( 0.0, 0.0 );
986 p->translate( component.center.x(), component.center.y() );
987 p->rotate( component.rotation );
990 p->translate( QPointF( xoff, yoff ) );
991 p->rotate( component.rotationOffset );
992 p->translate( -sizeOut / 2, sizeOut / 2 );
994 drawShadow( context, component, format );
996 renderedSymbol.reset( );
1004 renderedSymbol->setSize( sizeOut );
1005 renderedSymbol->setSizeUnit( Qgis::RenderUnit::Pixels );
1008 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1016 p->setCompositionMode( background.
blendMode() );
1018 p->translate( component.center.x(), component.center.y() );
1019 p->rotate( component.rotation );
1022 p->translate( QPointF( xoff, yoff ) );
1023 p->rotate( component.rotationOffset );
1027 renderedSymbol->renderPoint( QPointF( 0, 0 ), &f, context );
1028 renderedSymbol->stopRender( context );
1029 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1039 double w = component.size.width();
1040 double h = component.size.height();
1061 h = std::sqrt( std::pow( w, 2 ) + std::pow( h, 2 ) );
1067 h = h * M_SQRT1_2 * 2;
1068 w = w * M_SQRT1_2 * 2;
1076 w += bufferWidth * 2;
1077 h += bufferHeight * 2;
1081 QRectF rect( -w / 2.0, - h / 2.0, w, h );
1083 if ( rect.isNull() )
1089 p->translate( QPointF( component.center.x(), component.center.y() ) );
1090 p->rotate( component.rotation );
1093 p->translate( QPointF( xoff, yoff ) );
1094 p->rotate( component.rotationOffset );
1100 QTransform t = QTransform::fromScale( 10, 10 );
1102 QTransform ti = t.inverted();
1107 if ( background.
radiiUnit() == Qgis::RenderUnit::Percentage )
1109 path.addRoundedRect( rect, background.
radii().width(), background.
radii().height(), Qt::RelativeSize );
1115 path.addRoundedRect( rect, xRadius, yRadius );
1121 path.addEllipse( rect );
1123 QPolygonF tempPolygon = path.toFillPolygon( t );
1124 QPolygonF polygon = ti.map( tempPolygon );
1126 QPainter *oldp = context.
painter();
1129 shapep.begin( &shapePict );
1132 std::unique_ptr< QgsFillSymbol > renderedSymbol;
1134 renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
1138 renderedSymbol->renderPolygon( polygon,
nullptr, &f, context );
1139 renderedSymbol->stopRender( context );
1146 component.picture = shapePict;
1149 component.size = rect.size();
1150 component.offset = QPointF( rect.width() / 2, -rect.height() / 2 );
1151 drawShadow( context, component, format );
1156 p->setCompositionMode( background.
blendMode() );
1160 p->scale( component.dpiRatio, component.dpiRatio );
1161 _fixQPictureDPI( p );
1162 p->drawPicture( 0, 0, shapePict );
1163 p->setCompositionMode( QPainter::CompositionMode_SourceOver );
1170 tmpEffect->end( context );
1183 QPainter *p = context.
painter();
1184 const double componentWidth = component.size.width();
1185 const double componentHeight = component.size.height();
1186 double xOffset = component.offset.x(), yOffset = component.offset.y();
1187 double pictbuffer = component.pictureBuffer;
1190 bool mapUnits = shadow.
blurRadiusUnit() == Qgis::RenderUnit::MapUnits;
1193 double radius = shadow.
blurRadiusUnit() == Qgis::RenderUnit::Percentage
1196 radius /= ( mapUnits ? context.
scaleFactor() / component.dpiRatio : 1 );
1197 radius =
static_cast< int >( radius + 0.5 );
1201 double blurBufferClippingScale = 3.75;
1202 int blurbuffer = ( radius > 17 ? 16 : radius ) * blurBufferClippingScale;
1204 QImage blurImg( componentWidth + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1205 componentHeight + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
1206 QImage::Format_ARGB32_Premultiplied );
1210 int minBlurImgSize = 1;
1214 int maxBlurImgSize = 40000;
1215 if ( blurImg.isNull()
1216 || ( blurImg.width() < minBlurImgSize || blurImg.height() < minBlurImgSize )
1217 || ( blurImg.width() > maxBlurImgSize || blurImg.height() > maxBlurImgSize ) )
1220 blurImg.fill( QColor( Qt::transparent ).rgba() );
1222 if ( !pictp.begin( &blurImg ) )
1224 pictp.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
1225 QPointF imgOffset( blurbuffer + pictbuffer + xOffset,
1226 blurbuffer + pictbuffer + componentHeight + yOffset );
1228 pictp.drawPicture( imgOffset,
1229 component.picture );
1232 pictp.setCompositionMode( QPainter::CompositionMode_SourceIn );
1233 pictp.fillRect( blurImg.rect(), shadow.
color() );
1237 if ( shadow.
blurRadius() > 0.0 && radius > 0 )
1245 picti.begin( &blurImg );
1246 picti.setBrush( Qt::Dense7Pattern );
1247 QPen imgPen( QColor( 0, 0, 255, 255 ) );
1248 imgPen.setWidth( 1 );
1249 picti.setPen( imgPen );
1250 picti.setOpacity( 0.1 );
1251 picti.drawRect( 0, 0, blurImg.width(), blurImg.height() );
1255 const double offsetDist = shadow.
offsetUnit() == Qgis::RenderUnit::Percentage
1258 double angleRad = shadow.
offsetAngle() * M_PI / 180;
1266 angleRad -= ( component.rotation * M_PI / 180 + component.rotationOffset * M_PI / 180 );
1269 QPointF transPt( -offsetDist * std::cos( angleRad + M_PI_2 ),
1270 -offsetDist * std::sin( angleRad + M_PI_2 ) );
1276 p->setRenderHint( QPainter::SmoothPixmapTransform );
1279 p->setCompositionMode( shadow.
blendMode() );
1281 p->setOpacity( shadow.
opacity() );
1283 double scale = shadow.
scale() / 100.0;
1285 p->scale( scale, scale );
1286 if ( component.useOrigin )
1288 p->translate( component.origin.x(), component.origin.y() );
1290 p->translate( transPt );
1291 p->translate( -imgOffset.x(),
1293 p->drawImage( 0, 0, blurImg );
1300 p->setBrush( Qt::NoBrush );
1301 QPen imgPen( QColor( 255, 0, 0, 10 ) );
1302 imgPen.setWidth( 2 );
1303 imgPen.setStyle( Qt::DashLine );
1304 p->setPen( imgPen );
1305 p->scale( scale, scale );
1306 if ( component.useOrigin() )
1308 p->translate( component.origin().x(), component.origin().y() );
1310 p->translate( transPt );
1311 p->translate( -imgOffset.x(),
1313 p->drawRect( 0, 0, blurImg.width(), blurImg.height() );
1318 p->setBrush( Qt::NoBrush );
1319 QPen componentRectPen( QColor( 0, 255, 0, 70 ) );
1320 componentRectPen.setWidth( 1 );
1321 if ( component.useOrigin() )
1323 p->translate( component.origin().x(), component.origin().y() );
1325 p->setPen( componentRectPen );
1326 p->drawRect( QRect( -xOffset, -componentHeight - yOffset, componentWidth, componentHeight ) );
1335 const Component &component,
1345 const double fontScale = calculateScaleFactorForFormat( context, format );
1347 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1348 if ( mode == Qgis::TextLayoutMode::Labeling )
1358 referenceScaleOverride.reset();
1360 double rotation = 0;
1361 const Qgis::TextOrientation orientation = calculateRotationAndOrientationForComponent( format, component, rotation );
1362 switch ( orientation )
1364 case Qgis::TextOrientation::Horizontal:
1366 drawTextInternalHorizontal( context, format, drawType, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
1370 case Qgis::TextOrientation::Vertical:
1371 case Qgis::TextOrientation::RotationBased:
1373 drawTextInternalVertical( context, format, drawType, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
1379Qgis::TextOrientation QgsTextRenderer::calculateRotationAndOrientationForComponent(
const QgsTextFormat &format,
const QgsTextRenderer::Component &component,
double &rotation )
1381 rotation = -component.rotation * 180 / M_PI;
1385 case Qgis::TextOrientation::RotationBased:
1388 if ( rotation >= -315 && rotation < -90 )
1391 return Qgis::TextOrientation::Vertical;
1393 else if ( rotation >= -90 && rotation < -45 )
1396 return Qgis::TextOrientation::Vertical;
1399 return Qgis::TextOrientation::Horizontal;
1402 case Qgis::TextOrientation::Horizontal:
1403 case Qgis::TextOrientation::Vertical:
1406 return Qgis::TextOrientation::Horizontal;
1409void QgsTextRenderer::calculateExtraSpacingForLineJustification(
const double spaceToDistribute,
const QgsTextBlock &block,
double &extraWordSpace,
double &extraLetterSpace )
1412 QTextBoundaryFinder
finder( QTextBoundaryFinder::Word, blockText );
1414 int wordBoundaries = 0;
1415 while (
finder.toNextBoundary() != -1 )
1417 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1421 if ( wordBoundaries > 0 )
1424 extraWordSpace = spaceToDistribute / wordBoundaries;
1429 QTextBoundaryFinder
finder( QTextBoundaryFinder::Grapheme, blockText );
1432 int graphemeBoundaries = 0;
1433 while (
finder.toNextBoundary() != -1 )
1435 if (
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
1436 graphemeBoundaries++;
1439 if ( graphemeBoundaries > 0 )
1441 extraLetterSpace = spaceToDistribute / graphemeBoundaries;
1446void QgsTextRenderer::applyExtraSpacingForLineJustification( QFont &font,
double extraWordSpace,
double extraLetterSpace )
1448 const double prevWordSpace = font.wordSpacing();
1449 font.setWordSpacing( prevWordSpace + extraWordSpace );
1450 const double prevLetterSpace = font.letterSpacing();
1451 font.setLetterSpacing( QFont::AbsoluteSpacing, prevLetterSpace + extraLetterSpace );
1458 const QStringList textLines = document.
toPlainText();
1460 const QSizeF documentSize = metrics.
documentSize( mode, Qgis::TextOrientation::Horizontal );
1462 double labelWidest = 0.0;
1465 case Qgis::TextLayoutMode::Labeling:
1467 labelWidest = documentSize.width();
1470 case Qgis::TextLayoutMode::Rectangle:
1473 labelWidest = component.size.width();
1477 double verticalAlignOffset = 0;
1479 bool adjustForAlignment = hAlignment != Qgis::TextHorizontalAlignment::Left && ( mode != Qgis::TextLayoutMode::Labeling || textLines.size() > 1 );
1481 if ( mode == Qgis::TextLayoutMode::Rectangle && vAlignment != Qgis::TextVerticalAlignment::Top )
1483 const double overallHeight = documentSize.height();
1484 switch ( vAlignment )
1486 case Qgis::TextVerticalAlignment::Top:
1489 case Qgis::TextVerticalAlignment::VerticalCenter:
1490 verticalAlignOffset = ( component.size.height() - overallHeight ) * 0.5;
1493 case Qgis::TextVerticalAlignment::Bottom:
1494 verticalAlignOffset = ( component.size.height() - overallHeight );
1502 const bool isFinalLineInParagraph = ( blockIndex == document.size() - 1 )
1503 || document.at( blockIndex + 1 ).toPlainText().trimmed().isEmpty();
1505 const double blockHeight = metrics.
blockHeight( blockIndex );
1509 context.
painter()->translate( component.origin );
1511 context.
painter()->rotate( rotation );
1516 maskPainter->save();
1517 maskPainter->translate( component.origin );
1519 maskPainter->rotate( rotation );
1523 double xMultiLineOffset = 0.0;
1524 double blockWidth = metrics.
blockWidth( blockIndex );
1525 double extraWordSpace = 0;
1526 double extraLetterSpace = 0;
1527 if ( adjustForAlignment )
1529 double labelWidthDiff = 0;
1530 switch ( hAlignment )
1532 case Qgis::TextHorizontalAlignment::Center:
1533 labelWidthDiff = ( labelWidest - blockWidth ) * 0.5;
1536 case Qgis::TextHorizontalAlignment::Right:
1537 labelWidthDiff = labelWidest - blockWidth;
1540 case Qgis::TextHorizontalAlignment::Justify:
1541 if ( !isFinalLineInParagraph && labelWidest > blockWidth )
1543 calculateExtraSpacingForLineJustification( labelWidest - blockWidth, block, extraWordSpace, extraLetterSpace );
1544 blockWidth = labelWidest;
1548 case Qgis::TextHorizontalAlignment::Left:
1554 case Qgis::TextLayoutMode::Labeling:
1555 case Qgis::TextLayoutMode::Rectangle:
1558 xMultiLineOffset = labelWidthDiff;
1563 switch ( hAlignment )
1565 case Qgis::TextHorizontalAlignment::Right:
1566 xMultiLineOffset = labelWidthDiff - labelWidest;
1569 case Qgis::TextHorizontalAlignment::Center:
1570 xMultiLineOffset = labelWidthDiff - labelWidest / 2.0;
1573 case Qgis::TextHorizontalAlignment::Left:
1574 case Qgis::TextHorizontalAlignment::Justify:
1582 const double baseLineOffset = metrics.
baselineOffset( blockIndex, mode );
1584 context.
painter()->translate( QPointF( xMultiLineOffset, baseLineOffset + verticalAlignOffset ) );
1586 maskPainter->translate( QPointF( xMultiLineOffset, baseLineOffset + verticalAlignOffset ) );
1588 Component subComponent;
1589 subComponent.block = block;
1590 subComponent.blockIndex = blockIndex;
1591 subComponent.
size = QSizeF( blockWidth, blockHeight );
1592 subComponent.offset = QPointF( 0.0, -metrics.
ascentOffset() );
1593 subComponent.rotation = -component.rotation * 180 / M_PI;
1594 subComponent.rotationOffset = 0.0;
1595 subComponent.extraWordSpacing = extraWordSpace * fontScale;
1596 subComponent.extraLetterSpacing = extraLetterSpace * fontScale;
1601 QgsTextRenderer::drawMask( context, subComponent, format, metrics, mode );
1606 QgsTextRenderer::drawBuffer( context, subComponent, format, metrics, mode );
1613 textp.begin( &textPict );
1614 textp.setPen( Qt::NoPen );
1616 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1617 if ( mode == Qgis::TextLayoutMode::Labeling )
1624 referenceScaleOverride.reset();
1628 textp.scale( 1 / fontScale, 1 / fontScale );
1631 int fragmentIndex = 0;
1636 path.setFillRule( Qt::WindingFill );
1638 QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
1640 if ( extraWordSpace || extraLetterSpace )
1641 applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
1645 path.addText( xOffset, yOffset, fragmentFont, fragment.
text() );
1649 textp.setBrush( textColor );
1650 textp.drawPath( path );
1660 subComponent.picture = textPict;
1661 subComponent.pictureBuffer = 0.0;
1662 subComponent.origin = QPointF( 0.0, 0.0 );
1664 QgsTextRenderer::drawShadow( context, subComponent, format );
1674 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
1678 case Qgis::TextRenderFormat::AlwaysOutlines:
1681 _fixQPictureDPI( context.
painter() );
1682 context.
painter()->drawPicture( 0, 0, textPict );
1686 case Qgis::TextRenderFormat::AlwaysText:
1689 int fragmentIndex = 0;
1692 QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
1694 if ( extraWordSpace || extraLetterSpace )
1695 applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
1702 context.
painter()->setPen( textColor );
1703 context.
painter()->setFont( fragmentFont );
1704 context.
painter()->setRenderHint( QPainter::TextAntialiasing );
1706 context.
painter()->scale( 1 / fontScale, 1 / fontScale );
1707 context.
painter()->drawText( QPointF( xOffset, yOffset ), fragment.
text() );
1708 context.
painter()->scale( fontScale, fontScale );
1717 maskPainter->restore();
1723void 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 )
1726 const QStringList textLines = document.
toPlainText();
1728 std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
1729 if ( mode == Qgis::TextLayoutMode::Labeling )
1739 referenceScaleOverride.reset();
1741 const QSizeF documentSize = metrics.
documentSize( mode, Qgis::TextOrientation::Vertical );
1742 const double actualTextWidth = documentSize.width();
1743 double textRectWidth = 0.0;
1747 case Qgis::TextLayoutMode::Labeling:
1749 textRectWidth = actualTextWidth;
1752 case Qgis::TextLayoutMode::Rectangle:
1755 textRectWidth = component.size.width();
1759 int maxLineLength = 0;
1760 for (
const QString &line : std::as_const( textLines ) )
1762 maxLineLength = std::max( maxLineLength,
static_cast<int>( line.length() ) );
1765 const double actualLabelHeight = documentSize.height();
1768 bool adjustForAlignment = hAlignment != Qgis::TextHorizontalAlignment::Left && ( mode != Qgis::TextLayoutMode::Labeling || textLines.size() > 1 );
1775 context.
painter()->translate( component.origin );
1777 context.
painter()->rotate( rotation );
1782 maskPainter->save();
1783 maskPainter->translate( component.origin );
1785 maskPainter->rotate( rotation );
1792 if ( adjustForAlignment )
1794 double hAlignmentOffset = 0;
1795 switch ( hAlignment )
1797 case Qgis::TextHorizontalAlignment::Center:
1798 hAlignmentOffset = ( textRectWidth - actualTextWidth ) * 0.5;
1801 case Qgis::TextHorizontalAlignment::Right:
1802 hAlignmentOffset = textRectWidth - actualTextWidth;
1805 case Qgis::TextHorizontalAlignment::Left:
1806 case Qgis::TextHorizontalAlignment::Justify:
1812 case Qgis::TextLayoutMode::Labeling:
1813 case Qgis::TextLayoutMode::Rectangle:
1816 xOffset += hAlignmentOffset;
1824 double yOffset = 0.0;
1827 case Qgis::TextLayoutMode::Labeling:
1828 if ( format.
orientation() == Qgis::TextOrientation::RotationBased )
1830 if ( rotation >= -405 && rotation < -180 )
1834 else if ( rotation >= 0 && rotation < 45 )
1836 xOffset -= actualTextWidth;
1842 yOffset = -actualLabelHeight;
1847 yOffset = -actualLabelHeight;
1850 case Qgis::TextLayoutMode::Rectangle:
1857 context.
painter()->translate( QPointF( xOffset, yOffset ) );
1859 double currentBlockYOffset = 0;
1860 int fragmentIndex = 0;
1868 const QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
1870 QFontMetricsF fragmentMetrics( fragmentFont );
1872 const double letterSpacing = fragmentFont.letterSpacing() / fontScale;
1873 const double labelHeight = fragmentMetrics.ascent() / fontScale + ( fragmentMetrics.ascent() / fontScale + letterSpacing ) * ( line.length() - 1 );
1875 Component subComponent;
1877 subComponent.blockIndex = blockIndex;
1878 subComponent.firstFragmentIndex = fragmentIndex;
1879 subComponent.size = QSizeF( blockMaximumCharacterWidth, labelHeight + fragmentMetrics.descent() / fontScale );
1880 subComponent.offset = QPointF( 0.0, currentBlockYOffset );
1881 subComponent.rotation = -component.rotation * 180 / M_PI;
1882 subComponent.rotationOffset = 0.0;
1889 QgsTextRenderer::drawMask( context, subComponent, format );
1895 currentBlockYOffset += QgsTextRenderer::drawBuffer( context, subComponent, format, metrics, mode );
1901 path.setFillRule( Qt::WindingFill );
1903 double partYOffset = 0.0;
1904 for (
const QString &part : parts )
1906 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
1907 partYOffset += fragmentMetrics.ascent() / fontScale;
1908 path.addText( partXOffset * fontScale, partYOffset * fontScale, fragmentFont, part );
1909 partYOffset += letterSpacing;
1915 textp.begin( &textPict );
1916 textp.setPen( Qt::NoPen );
1919 textp.setBrush( textColor );
1920 textp.scale( 1 / fontScale, 1 / fontScale );
1921 textp.drawPath( path );
1932 subComponent.picture = textPict;
1933 subComponent.pictureBuffer = 0.0;
1934 subComponent.origin = QPointF( 0.0, currentBlockYOffset );
1935 const double prevY = subComponent.offset.y();
1936 subComponent.offset = QPointF( 0, -subComponent.size.height() );
1937 subComponent.useOrigin =
true;
1938 QgsTextRenderer::drawShadow( context, subComponent, format );
1939 subComponent.useOrigin =
false;
1940 subComponent.offset = QPointF( 0, prevY );
1950 context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
1954 case Qgis::TextRenderFormat::AlwaysOutlines:
1957 context.
painter()->translate( 0, currentBlockYOffset );
1958 _fixQPictureDPI( context.
painter() );
1959 context.
painter()->drawPicture( 0, 0, textPict );
1960 currentBlockYOffset += partYOffset;
1964 case Qgis::TextRenderFormat::AlwaysText:
1966 context.
painter()->setFont( fragmentFont );
1967 context.
painter()->setPen( textColor );
1968 context.
painter()->setRenderHint( QPainter::TextAntialiasing );
1970 double partYOffset = 0.0;
1971 for (
const QString &part : parts )
1973 double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
1974 context.
painter()->scale( 1 / fontScale, 1 / fontScale );
1975 context.
painter()->drawText( QPointF( partXOffset * fontScale, ( currentBlockYOffset + partYOffset ) * fontScale ), part );
1976 context.
painter()->scale( fontScale, fontScale );
1977 partYOffset += fragmentMetrics.ascent() / fontScale + letterSpacing;
1979 currentBlockYOffset += partYOffset;
1987 maskPainter->restore();
2002 if ( pixelSize < 50 )
2006 else if ( pixelSize > 200 )
2007 return 200 / pixelSize;
TextLayoutMode
Text layout modes.
@ 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 ...
TextOrientation
Text orientations.
RenderUnit
Rendering size units.
@ ApplyScalingWorkaroundForTextRendering
Whether a scaling workaround designed to stablise the rendering of small font sizes (or for painters ...
TextVerticalAlignment
Text vertical alignment.
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.
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 ...
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.
QColor textColor() const
Returns the character's text color, or an invalid color if no color override is set and the default f...
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.
QStringList toPlainText() const
Returns a list of plain text lines of text representing the document.
int size() const
Returns the number of blocks in the document.
static QgsTextDocument fromHtml(const QStringList &lines)
Constructor for QgsTextDocument consisting of a set of HTML formatted lines.
static QgsTextDocument fromPlainText(const QStringList &lines)
Constructor for QgsTextDocument consisting of a set of plain text lines.
void applyCapitalization(Qgis::Capitalization capitalization)
Applies a capitalization style to the document's text.
Container for all settings relating to text rendering.
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the size.
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.
QString text() const
Returns the text content of the fragment.
const QgsTextCharacterFormat & characterFormat() const
Returns the character formatting for 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.
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 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 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)
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()