Merge pull request #57582 from nyalldawson/next_vertex

Misc HTML labeling fixes
This commit is contained in:
Alessandro Pasotti 2024-06-04 16:47:12 +02:00 committed by GitHub
commit 9e12e2d59c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 301 additions and 45 deletions

View File

@ -1542,13 +1542,15 @@ bool QgsPalLayerSettings::checkMinimumSizeMM( const QgsRenderContext &ct, const
return QgsPalLabeling::checkMinimumSizeMM( ct, geom, minSize );
}
void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QString &text, double &labelX, double &labelY, const QgsFeature *f, QgsRenderContext *context, double *rotatedLabelX, double *rotatedLabelY, QgsTextDocument *document, QgsTextDocumentMetrics *documentMetrics, QRectF *outerBounds )
void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QString &text, double &labelX, double &labelY, const QgsFeature *f, QgsRenderContext *context, double *rotatedLabelX, double *rotatedLabelY, QgsTextFormat *specifiedFormat, QgsTextDocument *document, QgsTextDocumentMetrics *documentMetrics, QRectF *outerBounds )
{
if ( !fm || !f )
{
return;
}
const QgsTextFormat *format = specifiedFormat ? specifiedFormat : &mFormat;
QString textCopy( text );
//try to keep < 2.12 API - handle no passed render context
@ -1563,8 +1565,8 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt
QString wrapchr = wrapChar;
int evalAutoWrapLength = autoWrapLength;
double multilineH = mFormat.lineHeight();
Qgis::TextOrientation orientation = mFormat.orientation();
double multilineH = format->lineHeight();
Qgis::TextOrientation orientation = format->orientation();
bool addDirSymb = mLineSettings.addDirectionSymbol();
QString leftDirSymb = mLineSettings.leftDirectionSymbol();
@ -1707,23 +1709,30 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt
{
document->splitLines( wrapchr, evalAutoWrapLength, useMaxLineLengthForAutoWrap );
*documentMetrics = QgsTextDocumentMetrics::calculateMetrics( *document, mFormat, *rc );
const QSizeF size = documentMetrics->documentSize( Qgis::TextLayoutMode::Labeling, orientation );
*documentMetrics = QgsTextDocumentMetrics::calculateMetrics( *document, *format, *rc );
const QSizeF size = documentMetrics->documentSize( Qgis::TextLayoutMode::Labeling, orientation != Qgis::TextOrientation::RotationBased ? orientation : Qgis::TextOrientation::Horizontal );
w = size.width();
h = size.height();
if ( orientation == Qgis::TextOrientation::RotationBased )
{
const QSizeF rotatedSize = documentMetrics->documentSize( Qgis::TextLayoutMode::Labeling, Qgis::TextOrientation::Vertical );
rh = rotatedSize.width();
rw = rotatedSize.height();
}
}
else
{
const QStringList multiLineSplit = QgsPalLabeling::splitToLines( textCopy, wrapchr, evalAutoWrapLength, useMaxLineLengthForAutoWrap );
const int lines = multiLineSplit.size();
const double lineHeightPainterUnits = rc->convertToPainterUnits( mFormat.lineHeight(), mFormat.lineHeightUnit() );
const double lineHeightPainterUnits = rc->convertToPainterUnits( format->lineHeight(), format->lineHeightUnit() );
switch ( orientation )
{
case Qgis::TextOrientation::Horizontal:
{
h += fm->height() + static_cast< double >( ( lines - 1 ) * ( mFormat.lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( labelHeight * multilineH ) : lineHeightPainterUnits ) );
h += fm->height() + static_cast< double >( ( lines - 1 ) * ( format->lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( labelHeight * multilineH ) : lineHeightPainterUnits ) );
for ( const QString &line : std::as_const( multiLineSplit ) )
{
@ -1734,9 +1743,9 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt
case Qgis::TextOrientation::Vertical:
{
double letterSpacing = mFormat.scaledFont( *context ).letterSpacing();
double letterSpacing = format->scaledFont( *context ).letterSpacing();
double labelWidth = fm->maxWidth();
w = labelWidth + ( lines - 1 ) * ( mFormat.lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( labelWidth * multilineH ) : lineHeightPainterUnits );
w = labelWidth + ( lines - 1 ) * ( format->lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( labelWidth * multilineH ) : lineHeightPainterUnits );
int maxLineLength = 0;
for ( const QString &line : std::as_const( multiLineSplit ) )
@ -1756,12 +1765,12 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt
}
double widthVertical = 0.0;
double letterSpacing = mFormat.scaledFont( *context ).letterSpacing();
double letterSpacing = format->scaledFont( *context ).letterSpacing();
double labelWidth = fm->maxWidth();
widthVertical = labelWidth + ( lines - 1 ) * ( mFormat.lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( labelWidth * multilineH ) : lineHeightPainterUnits );
widthVertical = labelWidth + ( lines - 1 ) * ( format->lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( labelWidth * multilineH ) : lineHeightPainterUnits );
double heightHorizontal = 0.0;
heightHorizontal += fm->height() + static_cast< double >( ( lines - 1 ) * ( mFormat.lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( labelHeight * multilineH ) : lineHeightPainterUnits ) );
heightHorizontal += fm->height() + static_cast< double >( ( lines - 1 ) * ( format->lineHeightUnit() == Qgis::RenderUnit::Percentage ? ( labelHeight * multilineH ) : lineHeightPainterUnits ) );
double heightVertical = 0.0;
int maxLineLength = 0;
@ -1911,11 +1920,13 @@ std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails
}
}
QFont labelFont = mFormat.font();
QgsTextFormat evaluatedFormat = mFormat;
QFont labelFont = evaluatedFormat.font();
// labelFont will be added to label feature for use during label painting
// data defined font units?
Qgis::RenderUnit fontunits = mFormat.sizeUnit();
Qgis::RenderUnit fontunits = evaluatedFormat.sizeUnit();
exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::Property::FontSizeUnit, context.expressionContext() );
if ( !QgsVariantUtils::isNull( exprVal ) )
{
@ -1930,7 +1941,7 @@ std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails
}
//data defined label size?
double fontSize = mFormat.size();
double fontSize = evaluatedFormat.size();
if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Property::Size ) )
{
context.expressionContext().setOriginalValueVariable( fontSize );
@ -1941,7 +1952,7 @@ std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails
return nullptr;
}
int fontPixelSize = QgsTextRenderer::sizeToPixel( fontSize, context, fontunits, mFormat.sizeMapUnitScale() );
int fontPixelSize = QgsTextRenderer::sizeToPixel( fontSize, context, fontunits, evaluatedFormat.sizeMapUnitScale() );
// don't try to show font sizes less than 1 pixel (Qt complains)
if ( fontPixelSize < 1 )
{
@ -1983,6 +1994,13 @@ std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails
parseDropShadow( context );
}
evaluatedFormat.setFont( labelFont );
// undo scaling by symbology reference scale, as this would have been applied in the previous call to QgsTextRenderer::sizeToPixel and we risk
// double-applying it if we don't re-adjust, since all the text format metric calculations assume an unscaled format font size is present
const double symbologyReferenceScaleFactor = context.symbologyReferenceScale() > 0 ? context.symbologyReferenceScale() / context.rendererScale() : 1;
evaluatedFormat.setSize( labelFont.pixelSize() / symbologyReferenceScaleFactor );
evaluatedFormat.setSizeUnit( Qgis::RenderUnit::Pixels );
QString labelText;
// Check to see if we are a expression string.
@ -2016,7 +2034,7 @@ std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails
}
// apply capitalization
Qgis::Capitalization capitalization = mFormat.capitalization();
Qgis::Capitalization capitalization = evaluatedFormat.capitalization();
// maintain API - capitalization may have been set in textFont
if ( capitalization == Qgis::Capitalization::MixedCase && mFormat.font().capitalization() != QFont::MixedCase )
{
@ -2109,15 +2127,45 @@ std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails
QgsTextDocument doc;
QgsTextDocumentMetrics documentMetrics;
QRectF outerBounds;
if ( format().allowHtmlFormatting() && !labelText.isEmpty() )
switch ( placement )
{
doc = QgsTextDocument::fromHtml( QStringList() << labelText );
// also applies the line split to doc and calculates document metrics!
calculateLabelSize( labelFontMetrics.get(), labelText, labelWidth, labelHeight, mCurFeat, &context, &rotatedLabelX, &rotatedLabelY, &doc, &documentMetrics, &outerBounds );
}
else
{
calculateLabelSize( labelFontMetrics.get(), labelText, labelWidth, labelHeight, mCurFeat, &context, &rotatedLabelX, &rotatedLabelY, nullptr, nullptr, &outerBounds );
case Qgis::LabelPlacement::PerimeterCurved:
case Qgis::LabelPlacement::Curved:
{
// avoid calculating document and metrics if we don't require them for curved labels
if ( evaluatedFormat.allowHtmlFormatting() && !labelText.isEmpty() )
{
doc = QgsTextDocument::fromHtml( QStringList() << labelText );
calculateLabelSize( labelFontMetrics.get(), labelText, labelWidth, labelHeight, mCurFeat, &context, &rotatedLabelX, &rotatedLabelY, &evaluatedFormat, &doc, &documentMetrics, &outerBounds );
}
else
{
calculateLabelSize( labelFontMetrics.get(), labelText, labelWidth, labelHeight, mCurFeat, &context, &rotatedLabelX, &rotatedLabelY, &evaluatedFormat, nullptr, nullptr, &outerBounds );
}
break;
}
case Qgis::LabelPlacement::AroundPoint:
case Qgis::LabelPlacement::OverPoint:
case Qgis::LabelPlacement::Line:
case Qgis::LabelPlacement::Horizontal:
case Qgis::LabelPlacement::Free:
case Qgis::LabelPlacement::OrderedPositionsAroundPoint:
case Qgis::LabelPlacement::OutsidePolygons:
{
// non-curved labels always require document and metrics
if ( evaluatedFormat.allowHtmlFormatting() && !labelText.isEmpty() )
{
doc = QgsTextDocument::fromHtml( QStringList() << labelText );
}
else
{
doc = QgsTextDocument::fromPlainText( { labelText } );
}
calculateLabelSize( labelFontMetrics.get(), labelText, labelWidth, labelHeight, mCurFeat, &context, &rotatedLabelX, &rotatedLabelY, &evaluatedFormat, &doc, &documentMetrics, &outerBounds );
break;
}
}
// maximum angle between curved label characters (hardcoded defaults used in QGIS <2.0)
@ -2818,7 +2866,7 @@ std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails
case Qgis::LabelPlacement::Curved:
case Qgis::LabelPlacement::PerimeterCurved:
labelFeature->setTextMetrics( QgsTextLabelFeature::calculateTextMetrics( xform, context, labelFont, *labelFontMetrics, labelFont.letterSpacing(), labelFont.wordSpacing(), labelText, format().allowHtmlFormatting() ? &doc : nullptr, format().allowHtmlFormatting() ? &documentMetrics : nullptr ) );
labelFeature->setTextMetrics( QgsTextLabelFeature::calculateTextMetrics( xform, context, labelFont, *labelFontMetrics, labelFont.letterSpacing(), labelFont.wordSpacing(), labelText, evaluatedFormat.allowHtmlFormatting() ? &doc : nullptr, evaluatedFormat.allowHtmlFormatting() ? &documentMetrics : nullptr ) );
break;
}
@ -3541,7 +3589,6 @@ void QgsPalLayerSettings::parseTextFormatting( QgsRenderContext &context )
// data defined multiline text align?
if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Property::MultiLineAlignment ) )
{
context.expressionContext().setOriginalValueVariable( mFormat.lineHeight() );
exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::Property::MultiLineAlignment, context.expressionContext() );
if ( !QgsVariantUtils::isNull( exprVal ) )
{

View File

@ -638,7 +638,7 @@ class CORE_EXPORT QgsPalLayerSettings
*/
#ifndef SIP_RUN
void calculateLabelSize( const QFontMetricsF *fm, const QString &text, double &labelX, double &labelY, const QgsFeature *f = nullptr, QgsRenderContext *context = nullptr, double *rotatedLabelX SIP_OUT = nullptr, double *rotatedLabelY SIP_OUT = nullptr,
QgsTextDocument *document = nullptr, QgsTextDocumentMetrics *documentMetrics = nullptr, QRectF *outerBounds = nullptr );
QgsTextFormat *format = nullptr, QgsTextDocument *document = nullptr, QgsTextDocumentMetrics *documentMetrics = nullptr, QRectF *outerBounds = nullptr );
#else
void calculateLabelSize( const QFontMetricsF *fm, const QString &text, double &labelX, double &labelY, const QgsFeature *f = nullptr, QgsRenderContext *context = nullptr, double *rotatedLabelX SIP_OUT = nullptr, double *rotatedLabelY SIP_OUT = nullptr );
#endif

View File

@ -760,25 +760,22 @@ void QgsVectorLayerLabelProvider::drawLabelPrivate( pal::LabelPosition *label, Q
// If we are using non-curved, HTML formatted labels then we've already precalculated the text metrics.
// Otherwise we'll need to calculate them now.
bool metricsRequired = !tmpLyr.format().allowHtmlFormatting();
if ( !metricsRequired )
bool metricsRequired = false;
switch ( tmpLyr.placement )
{
switch ( tmpLyr.placement )
{
case Qgis::LabelPlacement::Curved:
case Qgis::LabelPlacement::PerimeterCurved:
metricsRequired = true;
break;
case Qgis::LabelPlacement::Curved:
case Qgis::LabelPlacement::PerimeterCurved:
metricsRequired = true;
break;
case Qgis::LabelPlacement::AroundPoint:
case Qgis::LabelPlacement::OverPoint:
case Qgis::LabelPlacement::Line:
case Qgis::LabelPlacement::Horizontal:
case Qgis::LabelPlacement::Free:
case Qgis::LabelPlacement::OrderedPositionsAroundPoint:
case Qgis::LabelPlacement::OutsidePolygons:
break;
}
case Qgis::LabelPlacement::AroundPoint:
case Qgis::LabelPlacement::OverPoint:
case Qgis::LabelPlacement::Line:
case Qgis::LabelPlacement::Horizontal:
case Qgis::LabelPlacement::Free:
case Qgis::LabelPlacement::OrderedPositionsAroundPoint:
case Qgis::LabelPlacement::OutsidePolygons:
break;
}
if ( metricsRequired )

View File

@ -74,7 +74,10 @@ class TestQgsLabelingEngine : public QgsTest
void testCurvedLabelsHtmlFormatting();
void testCurvedPerimeterLabelsHtmlFormatting();
void testCurvedLabelsHtmlSuperSubscript();
void testPointLabelTabs();
void testPointLabelTabsHtml();
void testPointLabelHtmlFormatting();
void testPointLabelHtmlFormattingDataDefinedSize();
void testCurvedLabelsWithTinySegments();
void testCurvedLabelCorrectLinePlacement();
void testCurvedLabelNegativeDistance();
@ -119,6 +122,7 @@ class TestQgsLabelingEngine : public QgsTest
void testVerticalOrientation();
void testVerticalOrientationLetterLineSpacing();
void testRotationBasedOrientationPoint();
void testRotationBasedOrientationPointHtmlLabel();
void testRotationBasedOrientationLine();
void testMapUnitLetterSpacing();
void testMapUnitWordSpacing();
@ -1682,6 +1686,112 @@ void TestQgsLabelingEngine::testMergingLinesWithMinimumSize()
QVERIFY( imageCheck( QStringLiteral( "label_merged_minimum_size" ), img, 20 ) );
}
void TestQgsLabelingEngine::testPointLabelTabs()
{
// test point label rendering with tab characters
QgsPalLayerSettings settings;
setDefaultLabelParams( settings );
QgsTextFormat format = settings.format();
format.setSize( 40 );
format.setColor( QColor( 0, 0, 0 ) );
settings.setFormat( format );
settings.fieldName = QStringLiteral( "'test\ttabs'" );
settings.isExpression = true;
settings.placement = Qgis::LabelPlacement::OverPoint;
settings.labelPerPart = false;
std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:3946&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
vl2->setRenderer( new QgsNullSymbolRenderer() );
QgsFeature f;
f.setAttributes( QgsAttributes() << 1 );
const QgsGeometry refGeom = QgsGeometry::fromWkt( QStringLiteral( "LineString (190000 5000010, 190100 5000000, 190200 5000000)" ) );
f.setGeometry( refGeom.centroid() );
QVERIFY( vl2->dataProvider()->addFeature( f ) );
vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
vl2->setLabelsEnabled( true );
// make a fake render context
const QSize size( 640, 480 );
QgsMapSettings mapSettings;
mapSettings.setLabelingEngineSettings( createLabelEngineSettings() );
mapSettings.setDestinationCrs( vl2->crs() );
mapSettings.setOutputSize( size );
mapSettings.setExtent( refGeom.boundingBox() );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl2.get() );
mapSettings.setOutputDpi( 96 );
QgsLabelingEngineSettings engineSettings = mapSettings.labelingEngineSettings();
engineSettings.setFlag( Qgis::LabelingFlag::UsePartialCandidates, false );
engineSettings.setFlag( Qgis::LabelingFlag::DrawCandidates, true );
mapSettings.setLabelingEngineSettings( engineSettings );
QgsMapRendererSequentialJob job( mapSettings );
job.start();
job.waitForFinished();
QImage img = job.renderedImage();
QVERIFY( imageCheck( QStringLiteral( "label_point_tabs" ), img, 20 ) );
}
void TestQgsLabelingEngine::testPointLabelTabsHtml()
{
// test point label rendering with tab characters
QgsPalLayerSettings settings;
setDefaultLabelParams( settings );
QgsTextFormat format = settings.format();
format.setSize( 20 );
format.setTabStopDistance( 11.8 );
format.setColor( QColor( 0, 0, 0 ) );
format.setAllowHtmlFormatting( true );
settings.setFormat( format );
settings.fieldName = QStringLiteral( "'<span style=\"font-size: 40pt\">test\ttabs</span>'" );
settings.isExpression = true;
settings.placement = Qgis::LabelPlacement::OverPoint;
settings.labelPerPart = false;
std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:3946&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
vl2->setRenderer( new QgsNullSymbolRenderer() );
QgsFeature f;
f.setAttributes( QgsAttributes() << 1 );
const QgsGeometry refGeom = QgsGeometry::fromWkt( QStringLiteral( "LineString (190000 5000010, 190100 5000000, 190200 5000000)" ) );
f.setGeometry( refGeom.centroid() );
QVERIFY( vl2->dataProvider()->addFeature( f ) );
vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
vl2->setLabelsEnabled( true );
// make a fake render context
const QSize size( 640, 480 );
QgsMapSettings mapSettings;
mapSettings.setLabelingEngineSettings( createLabelEngineSettings() );
mapSettings.setDestinationCrs( vl2->crs() );
mapSettings.setOutputSize( size );
mapSettings.setExtent( refGeom.boundingBox() );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl2.get() );
mapSettings.setOutputDpi( 96 );
QgsLabelingEngineSettings engineSettings = mapSettings.labelingEngineSettings();
engineSettings.setFlag( Qgis::LabelingFlag::UsePartialCandidates, false );
engineSettings.setFlag( Qgis::LabelingFlag::DrawCandidates, true );
mapSettings.setLabelingEngineSettings( engineSettings );
QgsMapRendererSequentialJob job( mapSettings );
job.start();
job.waitForFinished();
QImage img = job.renderedImage();
QVERIFY( imageCheck( QStringLiteral( "label_point_tabs" ), img, 20 ) );
}
void TestQgsLabelingEngine::testPointLabelHtmlFormatting()
{
// test point label rendering with HTML formatting
@ -1735,6 +1845,60 @@ void TestQgsLabelingEngine::testPointLabelHtmlFormatting()
QVERIFY( imageCheck( QStringLiteral( "label_point_html_rendering" ), img, 20 ) );
}
void TestQgsLabelingEngine::testPointLabelHtmlFormattingDataDefinedSize()
{
// test point label rendering with HTML formatting
QgsPalLayerSettings settings;
setDefaultLabelParams( settings );
QgsTextFormat format = settings.format();
format.setSize( 10 );
format.setColor( QColor( 0, 0, 0 ) );
format.setAllowHtmlFormatting( true );
settings.setFormat( format );
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::Property::Size, QgsProperty::fromExpression( QStringLiteral( "10+10" ) ) );
settings.fieldName = QStringLiteral( "'<i>test</i> <b style=\"font-size: 30pt\">HTML</b> <span style=\"color: red\">label<p><span style=\"color: rgba(255,0,0,0.5); text-decoration: underline; font-size:60pt\">point</span></span>'" );
settings.isExpression = true;
settings.placement = Qgis::LabelPlacement::OverPoint;
settings.labelPerPart = false;
std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:3946&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
vl2->setRenderer( new QgsNullSymbolRenderer() );
QgsFeature f;
f.setAttributes( QgsAttributes() << 1 );
const QgsGeometry refGeom = QgsGeometry::fromWkt( QStringLiteral( "LineString (190000 5000010, 190100 5000000, 190200 5000000)" ) );
f.setGeometry( refGeom.centroid() );
QVERIFY( vl2->dataProvider()->addFeature( f ) );
vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
vl2->setLabelsEnabled( true );
// make a fake render context
const QSize size( 640, 480 );
QgsMapSettings mapSettings;
mapSettings.setLabelingEngineSettings( createLabelEngineSettings() );
mapSettings.setDestinationCrs( vl2->crs() );
mapSettings.setOutputSize( size );
mapSettings.setExtent( refGeom.boundingBox() );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl2.get() );
mapSettings.setOutputDpi( 96 );
QgsLabelingEngineSettings engineSettings = mapSettings.labelingEngineSettings();
engineSettings.setFlag( Qgis::LabelingFlag::UsePartialCandidates, false );
engineSettings.setFlag( Qgis::LabelingFlag::DrawCandidates, true );
mapSettings.setLabelingEngineSettings( engineSettings );
QgsMapRendererSequentialJob job( mapSettings );
job.start();
job.waitForFinished();
QImage img = job.renderedImage();
QVERIFY( imageCheck( QStringLiteral( "label_point_html_rendering" ), img, 20 ) );
}
void TestQgsLabelingEngine::testCurvedLabelsHtmlSuperSubscript()
{
// test line label rendering with HTML formatting
@ -4956,6 +5120,54 @@ void TestQgsLabelingEngine::testRotationBasedOrientationPoint()
vl->setLabeling( nullptr );
}
void TestQgsLabelingEngine::testRotationBasedOrientationPointHtmlLabel()
{
const QSize size( 640, 480 );
QgsMapSettings mapSettings;
mapSettings.setLabelingEngineSettings( createLabelEngineSettings() );
mapSettings.setOutputSize( size );
mapSettings.setExtent( vl->extent() );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl );
mapSettings.setOutputDpi( 96 );
// first render the map and labeling separately
QgsMapRendererSequentialJob job( mapSettings );
job.start();
job.waitForFinished();
QImage img = job.renderedImage();
QPainter p( &img );
QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
context.setPainter( &p );
QgsPalLayerSettings settings;
settings.fieldName = QStringLiteral( "'<span style=\"font-size: 12.3pt\">' || \"Class\" || '</span>'" );
settings.isExpression = true;
setDefaultLabelParams( settings );
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::Property::LabelRotation, QgsProperty::fromExpression( QStringLiteral( "\"Heading\"" ) ) );
QgsTextFormat format = settings.format();
format.setSize( 26 );
format.setOrientation( Qgis::TextOrientation::RotationBased );
format.setAllowHtmlFormatting( true );
settings.setFormat( format );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
vl->setLabelsEnabled( true );
QgsDefaultLabelingEngine engine;
engine.setMapSettings( mapSettings );
engine.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
engine.run( context );
p.end();
QVERIFY( imageCheck( "labeling_rotation_based_orientation_point", img, 20 ) );
vl->setLabeling( nullptr );
}
void TestQgsLabelingEngine::testRotationBasedOrientationLine()
{
const QString filename = QStringLiteral( TEST_DATA_DIR ) + "/lines.shp";

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB