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 );
 
  115  drawParts( rect, rotation, horizontalAlignment, verticalAlignment, document, metrics, context, tmpFormat, components, mode );
 
 
  123  lFormat = updateShadowPosition( lFormat );
 
 
  135  const QgsTextFormat lFormat = updateShadowPosition( _format );
 
  154  drawParts( point, rotation, alignment, document, metrics, context, lFormat, components, mode );
 
 
  162  lFormat = updateShadowPosition( lFormat );
 
  169  drawDocumentOnLine( line, lFormat, document, context, offsetAlongLine, offsetFromLine );
 
 
  174  QPolygonF labelBaselineCurve = line;
 
  183#if GEOS_VERSION_MAJOR==3 && GEOS_VERSION_MINOR<11 
  184    if ( offsetFromLine < 0 )
 
  187      std::unique_ptr < QgsLineString > reversed( offsetCurve->reversed() );
 
  191      offsetCurve = std::move( reversed );
 
  195    labelBaselineCurve = offsetCurve->asQPolygonF();
 
  200  const QFont baseFont = format.
scaledFont( context, fontScale );
 
  201  const double letterSpacing = baseFont.letterSpacing() / fontScale;
 
  202  const double wordSpacing = baseFont.wordSpacing() / fontScale;
 
  204  QStringList graphemes;
 
  205  QVector< QgsTextCharacterFormat > graphemeFormats;
 
  206  QVector< QgsTextDocumentMetrics > graphemeMetrics;
 
  208  for ( 
const QgsTextBlock &block : std::as_const( document ) )
 
  213      for ( 
const QString &grapheme : fragmentGraphemes )
 
  215        graphemes.append( grapheme );
 
  216        graphemeFormats.append( fragment.characterFormat() );
 
  226  QVector< double > characterWidths( graphemes.count() );
 
  227  QVector< double > characterHeights( graphemes.count() );
 
  228  QVector< double > characterDescents( graphemes.count() );
 
  229  QFont previousNonSuperSubScriptFont;
 
  231  for ( 
int i = 0; i < graphemes.count(); i++ )
 
  236    double graphemeFirstCharHorizontalAdvanceWithLetterSpacing = 0;
 
  237    double graphemeFirstCharHorizontalAdvance = 0;
 
  238    double graphemeHorizontalAdvance = 0;
 
  239    double characterDescent = 0;
 
  240    double characterHeight = 0;
 
  243    QFont graphemeFont = baseFont;
 
  247      previousNonSuperSubScriptFont = graphemeFont;
 
  254          previousNonSuperSubScriptFont = graphemeFont;
 
  275      previousNonSuperSubScriptFont = graphemeFont;
 
  278    const QFontMetricsF graphemeFontMetrics( graphemeFont );
 
  279    graphemeFirstCharHorizontalAdvance = graphemeFontMetrics.horizontalAdvance( QString( graphemes[i].at( 0 ) ) ) / fontScale;
 
  280    graphemeFirstCharHorizontalAdvanceWithLetterSpacing = graphemeFontMetrics.horizontalAdvance( graphemes[i].at( 0 ) )  / fontScale + letterSpacing;
 
  281    graphemeHorizontalAdvance = graphemeFontMetrics.horizontalAdvance( QString( graphemes[i] ) )  / fontScale;
 
  282    characterDescent = graphemeFontMetrics.descent() / fontScale;
 
  283    characterHeight = graphemeFontMetrics.height() / fontScale;
 
  285    qreal wordSpaceFix = qreal( 0.0 );
 
  286    if ( graphemes[i] == QLatin1String( 
" " ) )
 
  290      wordSpaceFix = ( nxt < graphemes.count() && graphemes[nxt] != QLatin1String( 
" " ) ) ? wordSpacing : qreal( 0.0 );
 
  295    if ( graphemes[i].length() == 1 &&
 
  296         !
qgsDoubleNear( graphemeFirstCharHorizontalAdvance, graphemeFirstCharHorizontalAdvanceWithLetterSpacing ) )
 
  299      wordSpaceFix -= wordSpacing;
 
  302    const double charWidth = graphemeHorizontalAdvance + wordSpaceFix;
 
  303    characterWidths[i] = charWidth;
 
  304    characterHeights[i] = characterHeight;
 
  305    characterDescents[i] = characterDescent;
 
  308  QgsPrecalculatedTextMetrics metrics( graphemes, std::move( characterWidths ), std::move( characterHeights ), std::move( characterDescents ) );
 
  312        metrics, labelBaselineCurve, offsetAlongLine,
 
  319  if ( placement->graphemePlacement.empty() )
 
  326  QHash< int, QgsTextRenderer::Component > components;
 
  327  components.reserve( placement->graphemePlacement.size() );
 
  330    QgsTextRenderer::Component component;
 
  331    component.origin = QPointF( grapheme.x, grapheme.y );
 
  332    component.rotation = -grapheme.angle;
 
  338      component.origin.rx() += verticalOffset * std::cos( grapheme.angle + M_PI_2 );
 
  339      component.origin.ry() += verticalOffset * std::sin( grapheme.angle + M_PI_2 );
 
  342    components.insert( grapheme.graphemeIndex, component );
 
  350      const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
 
  360      const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
 
  377    const QgsTextRenderer::Component &component = components[grapheme.graphemeIndex ];
 
 
  430  component.dpiRatio = 1.0;
 
  431  component.origin = rect.topLeft();
 
  432  component.rotation = rotation;
 
  433  component.size = rect.size();
 
  434  component.hAlign = alignment;
 
  442      double xc = rect.width() / 2.0;
 
  443      double yc = rect.height() / 2.0;
 
  445      double angle = -rotation;
 
  446      double xd = xc * std::cos( angle ) - yc * std::sin( angle );
 
  447      double yd = xc * std::sin( angle ) + yc * std::cos( angle );
 
  449      component.center = QPointF( component.origin.x() + xd, component.origin.y() + yd );
 
  453      component.center = rect.center();
 
  456    switch ( vAlignment )
 
  478    drawTextInternal( parts, context, format, component,
 
  480                      alignment, vAlignment, mode );
 
  501  component.dpiRatio = 1.0;
 
  502  component.origin = origin;
 
  503  component.rotation = rotation;
 
  504  component.hAlign = alignment;
 
  508    QgsTextRenderer::drawBackground( context, component, format, metrics, mode );
 
  518    drawTextInternal( parts, context, format, component,
 
  528  return QFontMetricsF( format.
scaledFont( context, scaleFactor ), context.
painter() ? context.
painter()->device() : nullptr );
 
 
  535  QPainter *p = context.
painter();
 
  540    if ( component.rotation >= -315 && component.rotation < -90 )
 
  544    else if ( component.rotation >= -90 && component.rotation < -45 )
 
  562  std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
 
  573  referenceScaleOverride.reset();
 
  576  path.setFillRule( Qt::WindingFill );
 
  578  double height = component.size.height();
 
  579  switch ( orientation )
 
  590      double partYOffset = component.offset.y() * scaleFactor;
 
  593      double partLastDescent = 0;
 
  595      int fragmentIndex = 0;
 
  598        const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, component.firstFragmentIndex + fragmentIndex );
 
  599        const double letterSpacing = fragmentFont.letterSpacing() / scaleFactor;
 
  601        const QFontMetricsF fragmentMetrics( fragmentFont );
 
  603        const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode );
 
  606        for ( 
const QString &part : parts )
 
  608          double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / scaleFactor - letterSpacing ) ) / 2;
 
  609          partYOffset += fragmentMetrics.ascent() / scaleFactor;
 
  610          path.addText( partXOffset, partYOffset + fragmentYOffset, fragmentFont, part );
 
  611          partYOffset += letterSpacing;
 
  613        partLastDescent = fragmentMetrics.descent() / scaleFactor;
 
  617      height = partYOffset + partLastDescent;
 
  618      advance = partYOffset - component.offset.y() * scaleFactor;
 
  623  QColor bufferColor = buffer.
color();
 
  624  bufferColor.setAlphaF( buffer.
opacity() );
 
  625  QPen pen( bufferColor );
 
  626  pen.setWidthF( penSize * scaleFactor );
 
  628  QColor tmpColor( bufferColor );
 
  632    tmpColor.setAlpha( 0 );
 
  638  buffp.begin( &buffPict );
 
  642    std::unique_ptr< QgsPaintEffect > tmpEffect( buffer.
paintEffect()->
clone() );
 
  644    tmpEffect->begin( context );
 
  645    context.
painter()->setPen( pen );
 
  646    context.
painter()->setBrush( tmpColor );
 
  647    if ( scaleFactor != 1.0 )
 
  648      context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
 
  649    context.
painter()->drawPath( path );
 
  650    if ( scaleFactor != 1.0 )
 
  651      context.
painter()->scale( scaleFactor, scaleFactor );
 
  652    tmpEffect->end( context );
 
  658    if ( scaleFactor != 1.0 )
 
  659      buffp.scale( 1 / scaleFactor, 1 / scaleFactor );
 
  661    buffp.setBrush( tmpColor );
 
  662    buffp.drawPath( path );
 
  668    QgsTextRenderer::Component bufferComponent = component;
 
  669    bufferComponent.origin = QPointF( 0.0, 0.0 );
 
  670    bufferComponent.picture = buffPict;
 
  671    bufferComponent.pictureBuffer = penSize / 2.0;
 
  672    bufferComponent.size.setHeight( height );
 
  676      bufferComponent.offset.setY( - bufferComponent.size.height() );
 
  678    drawShadow( context, bufferComponent, format );
 
  686    p->setCompositionMode( buffer.
blendMode() );
 
  690  p->scale( component.dpiRatio, component.dpiRatio );
 
  692  p->drawPicture( 0, 0, buffPict );
 
  694  return advance / scaleFactor;
 
  714  path.setFillRule( Qt::WindingFill );
 
  721  std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
 
  732  referenceScaleOverride.reset();
 
  735  int fragmentIndex = 0;
 
  738    if ( !fragment.isWhitespace() && !fragment.isImage() )
 
  740      const QFont fragmentFont = metrics.
fragmentFont( component.blockIndex, fragmentIndex );
 
  742      const double fragmentYOffset = metrics.
fragmentVerticalOffset( component.blockIndex, fragmentIndex, mode );
 
  743      path.addText( xOffset, fragmentYOffset, fragmentFont, fragment.text() );
 
  750  QColor bufferColor( Qt::gray );
 
  751  bufferColor.setAlphaF( mask.
opacity() );
 
  755  brush.setColor( bufferColor );
 
  756  pen.setColor( bufferColor );
 
  757  pen.setWidthF( penSize * scaleFactor );
 
  764  p->scale( component.dpiRatio, component.dpiRatio );
 
  770      if ( scaleFactor != 1.0 )
 
  771        context.
painter()->scale( 1 / scaleFactor, 1 / scaleFactor );
 
  772      context.
painter()->setPen( pen );
 
  773      context.
painter()->setBrush( brush );
 
  774      context.
painter()->drawPath( path );
 
  775      if ( scaleFactor != 1.0 )
 
  776        context.
painter()->scale( scaleFactor, scaleFactor );
 
  781    if ( scaleFactor != 1.0 )
 
  782      p->scale( 1 / scaleFactor, 1 / scaleFactor );
 
  784    p->setBrush( brush );
 
  786    if ( scaleFactor != 1.0 )
 
  787      p->scale( scaleFactor, scaleFactor );
 
  795  if ( doc.
size() == 0 )
 
  798  return textWidth( context, format, doc );
 
 
  815  for ( 
const QString &line : textLines )
 
  819      lines.append( 
wrappedText( context, line, maxLineWidth, format ) );
 
  823      lines.append( line );
 
  828  return textHeight( context, format, doc, mode );
 
 
  835  bool isNullSize = 
false;
 
  836  const QFont baseFont = format.
scaledFont( context, scaleFactor, &isNullSize );
 
  840  const QFontMetrics fm( baseFont );
 
  841  const double height = ( character.isNull() ? fm.height() : fm.boundingRect( character ).height() ) / scaleFactor;
 
  843  if ( !includeEffects )
 
  846  double maxExtension = 0;
 
  875  return height + maxExtension;
 
 
  883  const QStringList multiLineSplit = text.split( 
'\n' );
 
  885  return currentTextWidth > width;
 
 
  890  const QStringList lines = text.split( 
'\n' );
 
  891  QStringList outLines;
 
  892  for ( 
const QString &line : lines )
 
  897      const QStringList words = line.split( 
' ' );
 
  898      QStringList linesToProcess;
 
  899      QString wordsInCurrentLine;
 
  900      for ( 
const QString &word : words )
 
  905          if ( !wordsInCurrentLine.isEmpty() )
 
  906            linesToProcess << wordsInCurrentLine;
 
  907          wordsInCurrentLine.clear();
 
  908          linesToProcess << word;
 
  912          if ( !wordsInCurrentLine.isEmpty() )
 
  913            wordsInCurrentLine.append( 
' ' );
 
  914          wordsInCurrentLine.append( word );
 
  917      if ( !wordsInCurrentLine.isEmpty() )
 
  918        linesToProcess << wordsInCurrentLine;
 
  920      for ( 
const QString &line : std::as_const( linesToProcess ) )
 
  922        QString remainingText = line;
 
  923        int lastPos = remainingText.lastIndexOf( 
' ' );
 
  924        while ( lastPos > -1 )
 
  934            outLines << remainingText.left( lastPos );
 
  935            remainingText = remainingText.mid( lastPos + 1 );
 
  938          lastPos = remainingText.lastIndexOf( 
' ', lastPos - 1 );
 
  940        outLines << remainingText;
 
 
  969  Component component = 
c;
 
  972  QPainter *prevP = context.
painter();
 
  973  QPainter *p = context.
painter();
 
  974  std::unique_ptr< QgsPaintEffect > tmpEffect;
 
  978    tmpEffect->begin( context );
 
  987  const double originAdjustRotationRadians = -component.rotation;
 
  990    component.rotation = -( component.rotation * 180 / M_PI ); 
 
  991    component.rotationOffset =
 
  996    component.rotation = 0.0; 
 
  997    component.rotationOffset = background.
rotation();
 
 1006    double width = documentSize.width();
 
 1007    double height = documentSize.height();
 
 1014        switch ( component.hAlign )
 
 1018            component.center = QPointF( component.origin.x() + width / 2.0,
 
 1019                                        component.origin.y() + height / 2.0 );
 
 1023            component.center = QPointF( component.origin.x() + component.size.width() / 2.0,
 
 1024                                        component.origin.y() + height / 2.0 );
 
 1028            component.center = QPointF( component.origin.x() + component.size.width() - width / 2.0,
 
 1029                                        component.origin.y() + height / 2.0 );
 
 1036        bool isNullSize = 
false;
 
 1037        QFontMetricsF fm( format.
scaledFont( context, scaleFactor, &isNullSize ) );
 
 1038        double originAdjust = isNullSize ? 0 : ( fm.ascent() / scaleFactor / 2.0 - fm.leading() / scaleFactor / 2.0 );
 
 1039        switch ( component.hAlign )
 
 1043            component.center = QPointF( component.origin.x() + width / 2.0,
 
 1044                                        component.origin.y() - height / 2.0 + originAdjust );
 
 1048            component.center = QPointF( component.origin.x(),
 
 1049                                        component.origin.y() - height / 2.0 + originAdjust );
 
 1053            component.center = QPointF( component.origin.x() - width / 2.0,
 
 1054                                        component.origin.y() - height / 2.0 + originAdjust );
 
 1061          const double dx = component.center.x() - component.origin.x();
 
 1062          const double dy = component.center.y() - component.origin.y();
 
 1063          component.center.setX( component.origin.x() + ( std::cos( originAdjustRotationRadians ) * dx - std::sin( originAdjustRotationRadians ) * dy ) );
 
 1064          component.center.setY( component.origin.y() + ( std::sin( originAdjustRotationRadians ) * dx + std::cos( originAdjustRotationRadians ) * dy ) );
 
 1074      component.size = QSizeF( width, height );
 
 1079  switch ( background.
type() )
 
 1092      double sizeOut = 0.0;
 
 1103          sizeOut = std::max( component.size.width(), component.size.height() );
 
 1107          sizeOut += bufferSize * 2;
 
 1113      if ( sizeOut < 1.0 )
 
 1116      std::unique_ptr< QgsMarkerSymbol > renderedSymbol;
 
 1120        map[QStringLiteral( 
"name" )] = background.
svgFile().trimmed();
 
 1121        map[QStringLiteral( 
"size" )] = QString::number( sizeOut );
 
 1123        map[QStringLiteral( 
"angle" )] = QString::number( 0.0 ); 
 
 1131        map[QStringLiteral( 
"fill" )] = background.
fillColor().name();
 
 1132        map[QStringLiteral( 
"outline" )] = background.
strokeColor().name();
 
 1133        map[QStringLiteral( 
"outline-width" )] = QString::number( background.
strokeWidth() );
 
 1140          QVariantMap shdwmap( map );
 
 1141          shdwmap[QStringLiteral( 
"fill" )] = shadow.
color().name();
 
 1142          shdwmap[QStringLiteral( 
"outline" )] = shadow.
color().name();
 
 1143          shdwmap[QStringLiteral( 
"size" )] = QString::number( sizeOut );
 
 1148          svgp.begin( &svgPict );
 
 1165          svgShdwM->
renderPoint( QPointF( sizeOut / 2, -sizeOut / 2 ), svgShdwContext );
 
 1168          component.picture = svgPict;
 
 1170          component.pictureBuffer = 0.0;
 
 1172          component.size = QSizeF( sizeOut, sizeOut );
 
 1173          component.offset = QPointF( 0.0, 0.0 );
 
 1179          p->translate( component.center.x(), component.center.y() );
 
 1180          p->rotate( component.rotation );
 
 1183          p->translate( QPointF( xoff, yoff ) );
 
 1184          p->rotate( component.rotationOffset );
 
 1185          p->translate( -sizeOut / 2, sizeOut / 2 );
 
 1187          drawShadow( context, component, format );
 
 1189        renderedSymbol.reset( );
 
 1197        renderedSymbol->setSize( sizeOut );
 
 1201      renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
 
 1209        p->setCompositionMode( background.
blendMode() );
 
 1211      p->translate( component.center.x(), component.center.y() );
 
 1212      p->rotate( component.rotation );
 
 1215      p->translate( QPointF( xoff, yoff ) );
 
 1216      p->rotate( component.rotationOffset );
 
 1220      renderedSymbol->renderPoint( QPointF( 0, 0 ), &f, context );
 
 1221      renderedSymbol->stopRender( context );
 
 1222      p->setCompositionMode( QPainter::CompositionMode_SourceOver ); 
 
 1232      double w = component.size.width();
 
 1233      double h = component.size.height();
 
 1254          h = std::sqrt( std::pow( w, 2 ) + std::pow( h, 2 ) );
 
 1260          h = h * M_SQRT1_2 * 2;
 
 1261          w = w * M_SQRT1_2 * 2;
 
 1269        w += bufferWidth * 2;
 
 1270        h += bufferHeight * 2;
 
 1274      QRectF rect( -w / 2.0, - h / 2.0, w, h );
 
 1276      if ( rect.isNull() )
 
 1282      p->translate( QPointF( component.center.x(), component.center.y() ) );
 
 1283      p->rotate( component.rotation );
 
 1286      p->translate( QPointF( xoff, yoff ) );
 
 1287      p->rotate( component.rotationOffset );
 
 1293      QTransform t = QTransform::fromScale( 10, 10 );
 
 1295      QTransform ti = t.inverted();
 
 1302          path.addRoundedRect( rect, background.
radii().width(), background.
radii().height(), Qt::RelativeSize );
 
 1308          path.addRoundedRect( rect, xRadius, yRadius );
 
 1314        path.addEllipse( rect );
 
 1316      QPolygonF tempPolygon = path.toFillPolygon( t );
 
 1317      QPolygonF polygon = ti.map( tempPolygon );
 
 1319      QPainter *oldp = context.
painter();
 
 1322      shapep.begin( &shapePict );
 
 1325      std::unique_ptr< QgsFillSymbol > renderedSymbol;
 
 1327      renderedSymbol->setOpacity( renderedSymbol->opacity() * background.
opacity() );
 
 1331      renderedSymbol->renderPolygon( polygon, 
nullptr, &f, context );
 
 1332      renderedSymbol->stopRender( context );
 
 1339        component.picture = shapePict;
 
 1342        component.size = rect.size();
 
 1343        component.offset = QPointF( rect.width() / 2, -rect.height() / 2 );
 
 1344        drawShadow( context, component, format );
 
 1349        p->setCompositionMode( background.
blendMode() );
 
 1353      p->scale( component.dpiRatio, component.dpiRatio );
 
 1355      p->drawPicture( 0, 0, shapePict );
 
 1356      p->setCompositionMode( QPainter::CompositionMode_SourceOver ); 
 
 1363    tmpEffect->end( context );
 
 1372  QPainter *p = context.
painter();
 
 1373  const double componentWidth = component.size.width();
 
 1374  const double componentHeight = component.size.height();
 
 1375  const double xOffset = component.offset.x();
 
 1376  const double yOffset = component.offset.y();
 
 1377  double pictbuffer = component.pictureBuffer;
 
 1386  radius /= ( mapUnits ? context.
scaleFactor() / component.dpiRatio : 1 );
 
 1387  radius = 
static_cast< int >( radius + 0.5 ); 
 
 1391  double blurBufferClippingScale = 3.75;
 
 1392  int blurbuffer = ( radius > 17 ? 16 : radius ) * blurBufferClippingScale;
 
 1394  QImage blurImg( componentWidth + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
 
 1395                  componentHeight + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
 
 1396                  QImage::Format_ARGB32_Premultiplied );
 
 1400  int minBlurImgSize = 1;
 
 1404  int maxBlurImgSize = 40000;
 
 1405  if ( blurImg.isNull()
 
 1406       || ( blurImg.width() < minBlurImgSize || blurImg.height() < minBlurImgSize )
 
 1407       || ( blurImg.width() > maxBlurImgSize || blurImg.height() > maxBlurImgSize ) )
 
 1410  blurImg.fill( QColor( Qt::transparent ).rgba() );
 
 1412  if ( !pictp.begin( &blurImg ) )
 
 1414  pictp.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
 
 1415  QPointF imgOffset( blurbuffer + pictbuffer + xOffset,
 
 1416                     blurbuffer + pictbuffer + componentHeight + yOffset );
 
 1418  pictp.drawPicture( imgOffset,
 
 1419                     component.picture );
 
 1422  pictp.setCompositionMode( QPainter::CompositionMode_SourceIn );
 
 1423  pictp.fillRect( blurImg.rect(), shadow.
color() );
 
 1427  if ( shadow.
blurRadius() > 0.0 && radius > 0 )
 
 1435  picti.begin( &blurImg );
 
 1436  picti.setBrush( Qt::Dense7Pattern );
 
 1437  QPen imgPen( QColor( 0, 0, 255, 255 ) );
 
 1438  imgPen.setWidth( 1 );
 
 1439  picti.setPen( imgPen );
 
 1440  picti.setOpacity( 0.1 );
 
 1441  picti.drawRect( 0, 0, blurImg.width(), blurImg.height() );
 
 1448  double angleRad = shadow.
offsetAngle() * M_PI / 180; 
 
 1456    angleRad -= ( component.rotation * M_PI / 180 + component.rotationOffset * M_PI / 180 );
 
 1459  QPointF transPt( -offsetDist * std::cos( angleRad + M_PI_2 ),
 
 1460                   -offsetDist * std::sin( angleRad + M_PI_2 ) );
 
 1466  p->setRenderHint( QPainter::SmoothPixmapTransform );
 
 1469    p->setCompositionMode( shadow.
blendMode() );
 
 1471  p->setOpacity( shadow.
opacity() );
 
 1473  double scale = shadow.
scale() / 100.0;
 
 1475  p->scale( scale, scale );
 
 1476  if ( component.useOrigin )
 
 1478    p->translate( component.origin.x(), component.origin.y() );
 
 1480  p->translate( transPt );
 
 1481  p->translate( -imgOffset.x(),
 
 1483  p->drawImage( 0, 0, blurImg );
 
 1490  p->setBrush( Qt::NoBrush );
 
 1491  QPen imgPen( QColor( 255, 0, 0, 10 ) );
 
 1492  imgPen.setWidth( 2 );
 
 1493  imgPen.setStyle( Qt::DashLine );
 
 1494  p->setPen( imgPen );
 
 1495  p->scale( scale, scale );
 
 1496  if ( component.useOrigin() )
 
 1498    p->translate( component.origin().x(), component.origin().y() );
 
 1500  p->translate( transPt );
 
 1501  p->translate( -imgOffset.x(),
 
 1503  p->drawRect( 0, 0, blurImg.width(), blurImg.height() );
 
 1508  p->setBrush( Qt::NoBrush );
 
 1509  QPen componentRectPen( QColor( 0, 255, 0, 70 ) );
 
 1510  componentRectPen.setWidth( 1 );
 
 1511  if ( component.useOrigin() )
 
 1513    p->translate( component.origin().x(), component.origin().y() );
 
 1515  p->setPen( componentRectPen );
 
 1516  p->drawRect( QRect( -xOffset, -componentHeight - yOffset, componentWidth, componentHeight ) );
 
 1525                                        const Component &component,
 
 1537  std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
 
 1548  referenceScaleOverride.reset();
 
 1550  double rotation = 0;
 
 1551  const Qgis::TextOrientation orientation = calculateRotationAndOrientationForComponent( format, component, rotation );
 
 1552  switch ( orientation )
 
 1556      drawTextInternalHorizontal( context, format, components, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
 
 1565        drawTextInternalVertical( context, format, 
Qgis::TextComponent::Buffer, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
 
 1567        drawTextInternalVertical( context, format, 
Qgis::TextComponent::Text, mode, component, document, metrics, fontScale, alignment, vAlignment, rotation );
 
 1573Qgis::TextOrientation QgsTextRenderer::calculateRotationAndOrientationForComponent( 
const QgsTextFormat &format, 
const QgsTextRenderer::Component &component, 
double &rotation )
 
 1575  rotation = -component.rotation * 180 / M_PI;
 
 1582      if ( rotation >= -315 && rotation < -90 )
 
 1587      else if ( rotation >= -90 && rotation < -45 )
 
 1603void QgsTextRenderer::calculateExtraSpacingForLineJustification( 
const double spaceToDistribute, 
const QgsTextBlock &block, 
double &extraWordSpace, 
double &extraLetterSpace )
 
 1606  QTextBoundaryFinder 
finder( QTextBoundaryFinder::Word, blockText );
 
 1608  int wordBoundaries = 0;
 
 1609  while ( 
finder.toNextBoundary() != -1 )
 
 1611    if ( 
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
 
 1615  if ( wordBoundaries > 0 )
 
 1618    extraWordSpace = spaceToDistribute / wordBoundaries;
 
 1623    QTextBoundaryFinder 
finder( QTextBoundaryFinder::Grapheme, blockText );
 
 1626    int graphemeBoundaries = 0;
 
 1627    while ( 
finder.toNextBoundary() != -1 )
 
 1629      if ( 
finder.boundaryReasons() & QTextBoundaryFinder::StartOfItem )
 
 1630        graphemeBoundaries++;
 
 1633    if ( graphemeBoundaries > 0 )
 
 1635      extraLetterSpace = spaceToDistribute / graphemeBoundaries;
 
 1640void QgsTextRenderer::applyExtraSpacingForLineJustification( QFont &font, 
double extraWordSpace, 
double extraLetterSpace )
 
 1642  const double prevWordSpace = font.wordSpacing();
 
 1643  font.setWordSpacing( prevWordSpace + extraWordSpace );
 
 1644  const double prevLetterSpace = font.letterSpacing();
 
 1645  font.setLetterSpacing( QFont::AbsoluteSpacing, prevLetterSpace + extraLetterSpace );
 
 1649void QgsTextRenderer::renderBlockHorizontal( 
const QgsTextBlock &block, 
int blockIndex,
 
 1652    QPainter *painter, 
bool forceRenderAsPaths,
 
 1653    double fontScale, 
double extraWordSpace, 
double extraLetterSpace,
 
 1659    int fragmentIndex = 0;
 
 1663      if ( !fragment.isWhitespace() && !fragment.isImage() )
 
 1665        QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
 
 1668          applyExtraSpacingForLineJustification( fragmentFont, extraWordSpace * fontScale, extraLetterSpace * fontScale );
 
 1672        QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
 
 1673        textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.opacity() );
 
 1675        if ( deferredRenderBlock )
 
 1677          DeferredRenderFragment renderFragment;
 
 1678          renderFragment.color = textColor;
 
 1679          if ( forceRenderAsPaths )
 
 1681            renderFragment.path.setFillRule( Qt::WindingFill );
 
 1682            renderFragment.path.addText( xOffset, yOffset, fragmentFont, fragment.text() );
 
 1684          renderFragment.font = fragmentFont;
 
 1685          renderFragment.point = QPointF( xOffset, yOffset );
 
 1686          renderFragment.text = fragment.text();
 
 1687          deferredRenderBlock->fragments.append( renderFragment );
 
 1689        else if ( forceRenderAsPaths )
 
 1691          painter->setBrush( textColor );
 
 1693          path.setFillRule( Qt::WindingFill );
 
 1694          path.addText( xOffset, yOffset, fragmentFont, fragment.text() );
 
 1695          painter->drawPath( path );
 
 1699          painter->setPen( textColor );
 
 1700          painter->setFont( fragmentFont );
 
 1701          painter->drawText( QPointF( xOffset, yOffset ), fragment.text() );
 
 1704      else if ( fragment.isImage() )
 
 1706        bool fitsInCache = 
false;
 
 1708        const double imageHeight = metrics.
fragmentFixedHeight( blockIndex, fragmentIndex, mode ) * fontScale;
 
 1711                             QSize( 
static_cast< int >( std::round( imageWidth ) ),
 
 1712                                    static_cast< int >( std::round( imageHeight ) ) ),
 
 1716        const double yOffset = imageBaseline - image.height();
 
 1717        if ( !image.isNull() )
 
 1718          painter->drawImage( QPointF( xOffset, yOffset ), image );
 
 1749      if ( format.
font().underline()
 
 1750           || format.
font().overline()
 
 1751           || format.
font().strikeOut()
 
 1752           || std::any_of( document.begin(), document.end(), []( 
const QgsTextBlock & block )
 
 1754      return std::any_of( block.begin(), block.end(), []( const QgsTextFragment & fragment )
 
 1756        return fragment.characterFormat().underline() == QgsTextCharacterFormat::BooleanValue::SetTrue
 
 1757                 || fragment.characterFormat().overline() == QgsTextCharacterFormat::BooleanValue::SetTrue
 
 1758                 || fragment.characterFormat().strikeOut() == QgsTextCharacterFormat::BooleanValue::SetTrue;
 
 1771  return std::any_of( document.begin(), document.end(), []( 
const QgsTextBlock & block )
 
 1773    return std::any_of( block.begin(), block.end(), []( const QgsTextFragment & fragment )
 
 1775      return fragment.isImage();
 
 1782  QVector< BlockMetrics > blockMetrics;
 
 1783  blockMetrics.reserve( document.
size() );
 
 1793                                      || document.
size() > 1 );
 
 1795    const bool isFinalLineInParagraph = ( blockIndex == document.
size() - 1 )
 
 1796                                        || document.
at( blockIndex + 1 ).
toPlainText().trimmed().isEmpty();
 
 1800    thisBlockMetrics.width = metrics.
blockWidth( blockIndex );
 
 1802    if ( adjustForAlignment )
 
 1804      double blockWidthDiff = 0;
 
 1805      switch ( blockAlignment )
 
 1812          blockWidthDiff = targetWidth - thisBlockMetrics.width - metrics.
blockRightMargin( blockIndex );
 
 1816          if ( !isFinalLineInParagraph && targetWidth > thisBlockMetrics.width )
 
 1818            calculateExtraSpacingForLineJustification( targetWidth - thisBlockMetrics.width, block, thisBlockMetrics.extraWordSpace, thisBlockMetrics.extraLetterSpace );
 
 1819            thisBlockMetrics.width = targetWidth;
 
 1835          thisBlockMetrics.xOffset = blockWidthDiff;
 
 1840          switch ( blockAlignment )
 
 1843              thisBlockMetrics.xOffset = blockWidthDiff - targetWidth;
 
 1847              thisBlockMetrics.xOffset = blockWidthDiff - targetWidth / 2.0;
 
 1869        thisBlockMetrics.backgroundWidth = targetWidth;
 
 1870        thisBlockMetrics.backgroundXOffset = 0;
 
 1874        thisBlockMetrics.backgroundWidth = thisBlockMetrics.width;
 
 1875        thisBlockMetrics.backgroundXOffset = thisBlockMetrics.xOffset;
 
 1879    blockMetrics << thisBlockMetrics;
 
 1882  return blockMetrics;
 
 1885QBrush QgsTextRenderer::createBrushForPath( 
QgsRenderContext &context, 
const QString &path )
 
 1887  bool fitsInCache = 
false;
 
 1891  const QSizeF originalSizeMmAt96Dpi = imageSize / 3.7795275590551185;
 
 1893  const double imageWidth = originalSizeMmAt96Dpi.width() * pixelsPerMm;
 
 1894  const double imageHeight = originalSizeMmAt96Dpi.height() * pixelsPerMm;
 
 1896  if ( imageWidth == 0 || imageHeight == 0 )
 
 1899                       QSize( 
static_cast< int >( std::round( imageWidth ) ),
 
 1900                              static_cast< int >( std::round( imageHeight ) ) ),
 
 1904  if ( !image.isNull() )
 
 1907    res.setTextureImage( image );
 
 1915  context.
painter()->translate( component.origin );
 
 1917    context.
painter()->rotate( rotation );
 
 1919  context.
painter()->setPen( Qt::NoPen );
 
 1920  context.
painter()->setBrush( Qt::NoBrush );
 
 1923    const double baseLineOffset = metrics.
baselineOffset( blockIndex, mode );
 
 1933        if ( backgroundImageBrush.style() == Qt::BrushStyle::TexturePattern )
 
 1934          backgroundBrush = backgroundImageBrush;
 
 1937      context.
painter()->setBrush( backgroundBrush );
 
 1938      context.
painter()->drawRect( QRectF( blockMetrics[ blockIndex ].backgroundXOffset, baseLineOffset - blockMaximumAscent, blockMetrics[ blockIndex ].backgroundWidth, blockMaximumDescent + blockMaximumAscent ) );
 
 1942    int fragmentIndex = 0;
 
 1947      const double ascent = metrics.
fragmentAscent( blockIndex, fragmentIndex, mode );
 
 1948      const double descent = metrics.
fragmentDescent( blockIndex, fragmentIndex, mode );
 
 1950      if ( fragment.characterFormat().hasBackground() )
 
 1954        QBrush backgroundBrush = fragment.characterFormat().backgroundBrush();
 
 1955        if ( !fragment.characterFormat().backgroundImagePath().isEmpty() )
 
 1957          const QBrush backgroundImageBrush = createBrushForPath( context, fragment.characterFormat().backgroundImagePath() );
 
 1958          if ( backgroundImageBrush.style() == Qt::BrushStyle::TexturePattern )
 
 1959            backgroundBrush = backgroundImageBrush;
 
 1962        context.
painter()->setBrush( backgroundBrush );
 
 1963        context.
painter()->drawRect( QRectF( blockMetrics[ blockIndex ].xOffset + xOffset,
 
 1964                                             baseLineOffset + verticalAlignOffset + yOffset - ascent, horizontalAdvance, ascent + descent ) );
 
 1967      xOffset += horizontalAdvance;
 
 1974  context.
painter()->setBrush( Qt::NoBrush );
 
 1977    context.
painter()->rotate( -rotation );
 
 1978  context.
painter()->translate( -component.origin );
 
 1988  double targetWidth = 0.0;
 
 1993      targetWidth = documentSize.width();
 
 1999      targetWidth = component.size.width();
 
 2003  double verticalAlignOffset = 0;
 
 2007    const double overallHeight = documentSize.height();
 
 2008    switch ( vAlignment )
 
 2015        verticalAlignOffset = ( component.size.height() - overallHeight ) * 0.5 + metrics.
blockVerticalMargin( - 1 );
 
 2019        verticalAlignOffset = ( component.size.height() - overallHeight ) + metrics.
blockVerticalMargin( - 1 );
 
 2029  const bool usePathsForText = usePathsToRender( context, format, document );
 
 2033  std::unique_ptr< std::vector< DeferredRenderBlock > > deferredBlocks;
 
 2040  if ( requiresMultiPassRendering )
 
 2042    deferredBlocks = std::make_unique< std::vector< DeferredRenderBlock > >();
 
 2043    deferredBlocks->reserve( document.
size() );
 
 2050    const QVector< BlockMetrics > blockMetrics = calculateBlockMetrics( document, metrics, mode, targetWidth, hAlignment );
 
 2054      renderDocumentBackgrounds( context, document, metrics, component, blockMetrics, mode, verticalAlignOffset, rotation );
 
 2060      const double blockHeight = metrics.
blockHeight( blockIndex );
 
 2062      DeferredRenderBlock *deferredBlock = 
nullptr;
 
 2063      if ( requiresMultiPassRendering && deferredBlocks )
 
 2065        deferredBlocks->emplace_back( DeferredRenderBlock() );
 
 2066        deferredBlock = &deferredBlocks->back();
 
 2067        deferredBlock->fragments.reserve( block.
size() );
 
 2072      context.
painter()->translate( component.origin );
 
 2074        context.
painter()->rotate( rotation );
 
 2079        maskPainter->save();
 
 2080        maskPainter->translate( component.origin );
 
 2082          maskPainter->rotate( rotation );
 
 2085      const BlockMetrics thisBlockMetrics = blockMetrics[ blockIndex ];
 
 2086      const double baseLineOffset = metrics.
baselineOffset( blockIndex, mode );
 
 2088      const QPointF blockOrigin( thisBlockMetrics.xOffset, baseLineOffset + verticalAlignOffset );
 
 2089      if ( deferredBlock )
 
 2090        deferredBlock->origin = blockOrigin;
 
 2092        context.
painter()->translate( blockOrigin );
 
 2094        maskPainter->translate( blockOrigin );
 
 2096      Component subComponent;
 
 2097      subComponent.block = block;
 
 2098      subComponent.blockIndex = blockIndex;
 
 2099      subComponent.
size = QSizeF( thisBlockMetrics.width, blockHeight );
 
 2100      subComponent.offset = QPointF( 0.0, -metrics.
ascentOffset() );
 
 2101      subComponent.rotation = -component.rotation * 180 / M_PI;
 
 2102      subComponent.rotationOffset = 0.0;
 
 2103      subComponent.extraWordSpacing = thisBlockMetrics.extraWordSpace * fontScale;
 
 2104      subComponent.extraLetterSpacing = thisBlockMetrics.extraLetterSpace * fontScale;
 
 2105      if ( deferredBlock )
 
 2106        deferredBlock->component = subComponent;
 
 2111        QgsTextRenderer::drawMask( context, subComponent, format, metrics, mode );
 
 2115      const bool needsPaths = usePathsForText
 
 2119      std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
 
 2127      referenceScaleOverride.reset();
 
 2136      context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
 
 2138      context.
painter()->scale( 1 / fontScale, 1 / fontScale );
 
 2139      context.
painter()->setPen( Qt::NoPen );
 
 2140      context.
painter()->setBrush( Qt::NoBrush );
 
 2142      renderBlockHorizontal( block, blockIndex, metrics, context, format, context.
painter(), needsPaths,
 
 2143                             fontScale, thisBlockMetrics.extraWordSpace, thisBlockMetrics.extraLetterSpace, mode, deferredBlock );
 
 2146        maskPainter->restore();
 
 2152  if ( deferredBlocks )
 
 2154    renderDeferredBlocks(
 
 2155      context, format, components, *deferredBlocks, usePathsForText, fontScale, component, rotation
 
 2163    const std::vector< DeferredRenderBlock > &deferredBlocks,
 
 2164    bool usePathsForText,
 
 2166    const Component &component,
 
 2171    renderDeferredBuffer( context, format, components, deferredBlocks, fontScale, component, rotation );
 
 2178    renderDeferredShadowForText( context, format, deferredBlocks, fontScale, component, rotation );
 
 2187    renderDeferredText( context, deferredBlocks, usePathsForText, fontScale, component, rotation );
 
 2191void QgsTextRenderer::renderDeferredShadowForText( 
QgsRenderContext &context,
 
 2193    const std::vector< DeferredRenderBlock > &deferredBlocks,
 
 2195    const Component &component,
 
 2200  context.
painter()->translate( component.origin );
 
 2202    context.
painter()->rotate( rotation );
 
 2204  context.
painter()->setPen( Qt::NoPen );
 
 2205  context.
painter()->setBrush( Qt::NoBrush );
 
 2207  for ( 
const DeferredRenderBlock &block : deferredBlocks )
 
 2209    Component subComponent = block.component;
 
 2211    QPainter painter( &subComponent.picture );
 
 2212    painter.setPen( Qt::NoPen );
 
 2213    painter.setBrush( Qt::NoBrush );
 
 2214    painter.scale( 1 / fontScale, 1 / fontScale );
 
 2216    for ( 
const DeferredRenderFragment &fragment : std::as_const( block.fragments ) )
 
 2218      if ( !fragment.path.isEmpty() )
 
 2220        painter.setBrush( fragment.color );
 
 2221        painter.drawPath( fragment.path );
 
 2225        painter.setPen( fragment.color );
 
 2226        painter.setFont( fragment.font );
 
 2227        painter.drawText( fragment.point, fragment.text );
 
 2232    subComponent.pictureBuffer = 1.0; 
 
 2233    subComponent.origin = QPointF( 0.0, 0.0 );
 
 2234    const QRectF pictureBoundingRect = subComponent.picture.boundingRect();
 
 2235    subComponent.size = pictureBoundingRect.size();
 
 2236    subComponent.offset = QPointF( -pictureBoundingRect.left(), -pictureBoundingRect.height() - pictureBoundingRect.top() );
 
 2238    context.
painter()->translate( block.origin );
 
 2239    drawShadow( context, subComponent, format );
 
 2240    context.
painter()->translate( -block.origin );
 
 2247    const std::vector< DeferredRenderBlock > &deferredBlocks,
 
 2249    const Component &component,
 
 2259  std::unique_ptr< QPicture > bufferPicture;
 
 2260  std::unique_ptr< QPainter > bufferPainter;
 
 2261  QPainter *prevPainter = context.
painter();
 
 2262  if ( needsShadowOnBuffer )
 
 2264    bufferPicture = std::make_unique< QPicture >();
 
 2265    bufferPainter = std::make_unique< QPainter >( bufferPicture.get() );
 
 2269  std::unique_ptr< QgsPaintEffect > tmpEffect;
 
 2273    tmpEffect->begin( context );
 
 2278  QPen pen( bufferColor );
 
 2283  pen.setWidthF( penSize * fontScale );
 
 2285  context.
painter()->setPen( pen );
 
 2290    bufferColor.setAlpha( 0 );
 
 2292  context.
painter()->setBrush( bufferColor );
 
 2294  context.
painter()->translate( component.origin );
 
 2296    context.
painter()->rotate( rotation );
 
 2303  for ( 
const DeferredRenderBlock &block : deferredBlocks )
 
 2305    context.
painter()->translate( block.origin );
 
 2306    context.
painter()->scale( 1 / fontScale, 1 / fontScale );
 
 2307    for ( 
const DeferredRenderFragment &fragment : std::as_const( block.fragments ) )
 
 2309      context.
painter()->drawPath( fragment.path );
 
 2311    context.
painter()->scale( fontScale, fontScale );
 
 2312    context.
painter()->translate( -block.origin );
 
 2317    tmpEffect->end( context );
 
 2320  if ( needsShadowOnBuffer && bufferPicture )
 
 2322    bufferPainter->end();
 
 2323    bufferPainter.reset();
 
 2326    QgsTextRenderer::Component bufferComponent = component;
 
 2327    bufferComponent.origin = QPointF( 0.0, 0.0 );
 
 2328    bufferComponent.picture = *bufferPicture;
 
 2329    bufferComponent.pictureBuffer = penSize / 2.0;
 
 2330    const QRectF bufferBoundingBox = bufferPicture->boundingRect();
 
 2331    bufferComponent.size = bufferBoundingBox.size();
 
 2332    bufferComponent.offset = QPointF( -bufferBoundingBox.left(), -bufferBoundingBox.height() - bufferBoundingBox.top() );
 
 2334    drawShadow( context, bufferComponent, format );
 
 2343    context.
painter()->scale( component.dpiRatio, component.dpiRatio );
 
 2349    const std::vector< DeferredRenderBlock > &deferredBlocks,
 
 2350    bool usePathsForText,
 
 2352    const Component &component,
 
 2357  context.
painter()->translate( component.origin );
 
 2359    context.
painter()->rotate( rotation );
 
 2361  context.
painter()->setPen( Qt::NoPen );
 
 2362  context.
painter()->setBrush( Qt::NoBrush );
 
 2365  for ( 
const DeferredRenderBlock &block : deferredBlocks )
 
 2367    context.
painter()->translate( block.origin );
 
 2368    context.
painter()->scale( 1 / fontScale, 1 / fontScale );
 
 2370    for ( 
const DeferredRenderFragment &fragment : std::as_const( block.fragments ) )
 
 2372      if ( usePathsForText )
 
 2374        context.
painter()->setBrush( fragment.color );
 
 2375        context.
painter()->drawPath( fragment.path );
 
 2379        context.
painter()->setPen( fragment.color );
 
 2380        context.
painter()->setFont( fragment.font );
 
 2381        context.
painter()->drawText( fragment.point, fragment.text );
 
 2385    context.
painter()->scale( fontScale, fontScale );
 
 2386    context.
painter()->translate( -block.origin );
 
 2390void QgsTextRenderer::drawTextInternalVertical( 
QgsRenderContext &context, 
const QgsTextFormat &format, 
Qgis::TextComponents components, 
Qgis::TextLayoutMode mode, 
const QgsTextRenderer::Component &component, 
const QgsTextDocument &document, 
const QgsTextDocumentMetrics &metrics, 
double fontScale, 
Qgis::TextHorizontalAlignment hAlignment, 
Qgis::TextVerticalAlignment, 
double rotation )
 
 2393  const QStringList textLines = document.
toPlainText();
 
 2395  std::optional< QgsScopedRenderContextReferenceScaleOverride > referenceScaleOverride;
 
 2406  referenceScaleOverride.reset();
 
 2409  const double actualTextWidth = documentSize.width();
 
 2410  double textRectWidth = 0.0;
 
 2416      textRectWidth = actualTextWidth;
 
 2422      textRectWidth = component.size.width();
 
 2426  int maxLineLength = 0;
 
 2427  for ( 
const QString &line : std::as_const( textLines ) )
 
 2429    maxLineLength = std::max( maxLineLength, 
static_cast<int>( line.length() ) );
 
 2432  const double actualLabelHeight = documentSize.height();
 
 2442    context.
painter()->translate( component.origin );
 
 2444      context.
painter()->rotate( rotation );
 
 2449      maskPainter->save();
 
 2450      maskPainter->translate( component.origin );
 
 2452        maskPainter->rotate( rotation );
 
 2459    if ( adjustForAlignment )
 
 2461      double hAlignmentOffset = 0;
 
 2462      switch ( hAlignment )
 
 2465          hAlignmentOffset = ( textRectWidth - actualTextWidth ) * 0.5;
 
 2469          hAlignmentOffset = textRectWidth - actualTextWidth;
 
 2483          xOffset += hAlignmentOffset;
 
 2491    double yOffset = 0.0;
 
 2497          if ( rotation >= -405 && rotation < -180 )
 
 2501          else if ( rotation >= 0 && rotation < 45 )
 
 2503            xOffset -= actualTextWidth;
 
 2509          yOffset = -actualLabelHeight;
 
 2514        yOffset = -actualLabelHeight;
 
 2524    context.
painter()->translate( QPointF( xOffset, yOffset ) );
 
 2526    double currentBlockYOffset = 0;
 
 2527    int fragmentIndex = 0;
 
 2535      const QFont fragmentFont = metrics.
fragmentFont( blockIndex, fragmentIndex );
 
 2537      QFontMetricsF fragmentMetrics( fragmentFont );
 
 2539      const double letterSpacing = fragmentFont.letterSpacing() / fontScale;
 
 2540      const double labelHeight = fragmentMetrics.ascent() / fontScale + ( fragmentMetrics.ascent() / fontScale + letterSpacing ) * ( line.length() - 1 );
 
 2542      Component subComponent;
 
 2544      subComponent.blockIndex = blockIndex;
 
 2545      subComponent.firstFragmentIndex = fragmentIndex;
 
 2546      subComponent.size = QSizeF( blockMaximumCharacterWidth, labelHeight + fragmentMetrics.descent() / fontScale );
 
 2547      subComponent.offset = QPointF( 0.0, currentBlockYOffset );
 
 2548      subComponent.rotation = -component.rotation * 180 / M_PI;
 
 2549      subComponent.rotationOffset = 0.0;
 
 2556        QgsTextRenderer::drawMask( context, subComponent, format );
 
 2562        currentBlockYOffset += QgsTextRenderer::drawBuffer( context, subComponent, format, metrics, mode );
 
 2568        path.setFillRule( Qt::WindingFill );
 
 2570        double partYOffset = 0.0;
 
 2571        for ( 
const QString &part : parts )
 
 2573          double partXOffset = ( blockMaximumCharacterWidth - ( fragmentMetrics.horizontalAdvance( part ) / fontScale - letterSpacing ) ) / 2;
 
 2574          partYOffset += fragmentMetrics.ascent() / fontScale;
 
 2575          path.addText( partXOffset * fontScale, partYOffset * fontScale, fragmentFont, part );
 
 2576          partYOffset += letterSpacing;
 
 2582        textp.begin( &textPict );
 
 2583        textp.setPen( Qt::NoPen );
 
 2584        QColor textColor = fragment.characterFormat().textColor().isValid() ? fragment.characterFormat().textColor() : format.
color();
 
 2585        textColor.setAlphaF( fragment.characterFormat().textColor().isValid() ? textColor.alphaF() * format.
opacity() : format.
opacity() );
 
 2586        textp.setBrush( textColor );
 
 2587        textp.scale( 1 / fontScale, 1 / fontScale );
 
 2588        textp.drawPath( path );
 
 2599          subComponent.picture = textPict;
 
 2600          subComponent.pictureBuffer = 0.0; 
 
 2601          subComponent.origin = QPointF( 0.0, currentBlockYOffset );
 
 2602          const double prevY = subComponent.offset.y();
 
 2603          subComponent.offset = QPointF( 0, -subComponent.size.height() );
 
 2604          subComponent.useOrigin = 
true;
 
 2605          QgsTextRenderer::drawShadow( context, subComponent, format );
 
 2606          subComponent.useOrigin = 
false;
 
 2607          subComponent.offset = QPointF( 0, prevY );
 
 2617        context.
painter()->scale( subComponent.dpiRatio, subComponent.dpiRatio );
 
 2621        context.
painter()->translate( 0, currentBlockYOffset );
 
 2623        context.
painter()->drawPicture( 0, 0, textPict );
 
 2624        currentBlockYOffset += partYOffset;
 
 2630      maskPainter->restore();
 
 2648  if ( pixelSize < 50 )
 
 2649    return 200 / pixelSize;
 
 2652  else if ( pixelSize > 200 )
 
 2653    return 200 / pixelSize;
 
 
@ ForceVector
Always force vector-based rendering, even when the result will be visually different to a raster-base...
 
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.
 
QFlags< TextComponent > TextComponents
Text components.
 
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.
 
Manages 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, and exception handling.
 
QSize originalSize(const QString &path, bool blocking=false) const
Returns the original size (in pixels) of the image at the specified path.
 
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 std::unique_ptr< 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.
 
Manages painter saving and restoring required for drawing on a different painter (mask painter for ex...
 
static void applyScaleFixForQPictureDpi(QPainter *painter)
Applies a workaround to a painter to avoid an issue with incorrect scaling when drawing QPictures.
 
static void drawPicture(QPainter *painter, const QPointF &point, const QPicture &picture)
Draws a picture onto a painter, correctly applying workarounds to avoid issues with incorrect scaling...
 
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 rendered 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.
 
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()
 
Qgis::RasterizedRenderingPolicy rasterizedRenderingPolicy() const
Returns the policy controlling when rasterisation of content during renders is permitted.
 
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.
 
A marker symbol layer which renders an SVG graphic.
 
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.
 
Abstract base class for symbol layers.
 
Encapsulates the context in which a symbol is being rendered.
 
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 hasBackground() const
Returns true if the block has a background set.
 
QBrush backgroundBrush() const
Returns the brush used for rendering the background of the block.
 
QString backgroundImagePath() const
Returns the path for the image to be used for rendering the background of the fragment.
 
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.
 
double fragmentDescent(int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode) const
Returns the descent of the fragment at the specified block and fragment index.
 
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 blockMaximumAscent(int blockIndex) const
Returns the maximum ascent encountered in the specified block.
 
double fragmentAscent(int blockIndex, int fragmentIndex, Qgis::TextLayoutMode mode) const
Returns the ascent of the fragment at the specified block and fragment 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.
 
bool hasBackgrounds() const
Returns true if any blocks or fragments in the document have background brushes set.
 
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