From e10c5f76d12eb08fb0c16eb998f9eb297363a13d Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 28 May 2024 11:25:04 +1000 Subject: [PATCH 1/6] Fix rotation based orientation when html labeling enabled --- src/core/labeling/qgspallabeling.cpp | 9 ++++- tests/src/core/testqgslabelingengine.cpp | 50 ++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/core/labeling/qgspallabeling.cpp b/src/core/labeling/qgspallabeling.cpp index d125cbfea3a..10c16cec67d 100644 --- a/src/core/labeling/qgspallabeling.cpp +++ b/src/core/labeling/qgspallabeling.cpp @@ -1708,9 +1708,16 @@ 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 ); + 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 { diff --git a/tests/src/core/testqgslabelingengine.cpp b/tests/src/core/testqgslabelingengine.cpp index 807b5ce1691..3d6dcf00220 100644 --- a/tests/src/core/testqgslabelingengine.cpp +++ b/tests/src/core/testqgslabelingengine.cpp @@ -119,6 +119,7 @@ class TestQgsLabelingEngine : public QgsTest void testVerticalOrientation(); void testVerticalOrientationLetterLineSpacing(); void testRotationBasedOrientationPoint(); + void testRotationBasedOrientationPointHtmlLabel(); void testRotationBasedOrientationLine(); void testMapUnitLetterSpacing(); void testMapUnitWordSpacing(); @@ -4956,6 +4957,55 @@ 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() << 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( "'' || \"Class\" || ''" ); + 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.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly ); + 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"; From ad2645daecc494f09c15713ec289ad2b740f26b9 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 28 May 2024 11:26:40 +1000 Subject: [PATCH 2/6] Add test masks --- ...expected_label_absolute_line_spacing_mask.png | Bin 0 -> 5649 bytes ...expected_label_curved_html_rendering_mask.png | Bin 0 -> 2779 bytes .../expected_label_point_html_rendering_mask.png | Bin 0 -> 2513 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/testdata/control_images/labelingengine/expected_label_absolute_line_spacing/expected_label_absolute_line_spacing_mask.png create mode 100644 tests/testdata/control_images/labelingengine/expected_label_curved_html_rendering/expected_label_curved_html_rendering_mask.png create mode 100644 tests/testdata/control_images/labelingengine/expected_label_point_html_rendering/expected_label_point_html_rendering_mask.png diff --git a/tests/testdata/control_images/labelingengine/expected_label_absolute_line_spacing/expected_label_absolute_line_spacing_mask.png b/tests/testdata/control_images/labelingengine/expected_label_absolute_line_spacing/expected_label_absolute_line_spacing_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..b0375bbc9a4802374cc833ca2e8e410cf78eaade GIT binary patch literal 5649 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 S3f}P|r_HQR79YR-)4u^}v8=TK literal 0 HcmV?d00001 diff --git a/tests/testdata/control_images/labelingengine/expected_label_curved_html_rendering/expected_label_curved_html_rendering_mask.png b/tests/testdata/control_images/labelingengine/expected_label_curved_html_rendering/expected_label_curved_html_rendering_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..6d8d2d6bde5d5aae8a123fd7fca81345e7c2d621 GIT binary patch literal 2779 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV0^&A1{5*9c;^X_;wFJzX3_D(1Ys>z_3_nxXxnaP-=U|BcG(eBI2){q8hLm)M_+Y2e@!anzdWvBLD& z5ep%`kR99aya@kfcb=>6@bo#w`_3GbxXsAmaBS;Jb_RwI<(v)-4HAqT39N`#MG#Uh>sbDlC44Jav%)=|p4Bw8PJb7|Q?eA|_ zjP-IiM)Vv$e7NxSwY4jk{}DX>v`AB9g2{;pge^Wp33>l>ri9@|^}ec8NC!k>TE z*i?K-h}pf(e!u?O>#sjPJ3IU1+uPe$E`KwHf#t@;^z-w2-TUQyZ69B{x3AW^ufPBJ z;dcJz^FFzsdH(t1%gf6@J~=rVXly}Mm6cunKN~swI-9Rk=2rat^t9sFmzO&VA0N9C zT=wkGpPHIKKMLP771RsKGBo^mftR%942)$@fNpyH&zg{COo<@5k2cjS)V!sp|Lk*W2^)@f|yO@F39ew5?ISPm3(S_RO8# zYq%}ApMl}Q`$85TNyJ>JpluP2+$etY%k-}+x4A0Pkm@9%F5 zE2~*mr&wp7P0KNxz4vFqr<*r#TG-jiZN8cFO4EAt-Mr(w%iphiqP*z8GXv9`6Q7@- zKR(yGeA&FhOrVzh$M2^DU66Ng56~6&qt=F13paEhO}ewUy8M--_4h|dyZ3TCxF0~S zWp*%gY*1bww|Cbhe%^m)%XZ&g?frXy@znR0aZhunZ;e}j{NclYOOH<1k6$)#L-9XO t76yf5f(E1Y)o7JH+G-hyhT9qc7jxzx*RgSE1h!TgJYD@<);T3K0RSiwXqx~4 literal 0 HcmV?d00001 diff --git a/tests/testdata/control_images/labelingengine/expected_label_point_html_rendering/expected_label_point_html_rendering_mask.png b/tests/testdata/control_images/labelingengine/expected_label_point_html_rendering/expected_label_point_html_rendering_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..4f4a28169a71db86f4f1b999547d986da5759145 GIT binary patch literal 2513 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV0^&A1{5*9c;^X_;w`E{-7;bKc%H%t{JmXuCK&aaP02Zja-Mh*r6 zWd=ruBo+k*hn`VIqd_p53Pv-+Xjwq3;&A_RIfm~^X0v;bCVhPQ`ET9-r{#LnPv@^= zIwtY>?c3Zre#=*;AGj;fP_X!Ek>$15U$3U?>+Apja_;%_=O4d(`EoY(K-y->_3PIM zpKsXxkV68wC@*Jt=r;Xy>YK9NtIym0{+nO6d#-iE2YH$P<15t<#8yfq*Z9~nF*MA7 zjH<1ksZrY2&aUrgjonwC2VJM18l8Lo`HJy_JPwB)7qhnh`r@r{U`q`r%f4fR2FN+% z9mApCd-v}j2U=6bR&exT!Hg=VJEHMSj0_!xEIgyN%4o$pJlYm# Date: Tue, 28 May 2024 11:44:15 +1000 Subject: [PATCH 3/6] Fix data defined font size is ignored when HTML labeling is active --- src/core/labeling/qgspallabeling.cpp | 51 +++++++++++++--------- src/core/labeling/qgspallabeling.h | 2 +- tests/src/core/testqgslabelingengine.cpp | 55 ++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 21 deletions(-) diff --git a/src/core/labeling/qgspallabeling.cpp b/src/core/labeling/qgspallabeling.cpp index 10c16cec67d..3882b7c4cb6 100644 --- a/src/core/labeling/qgspallabeling.cpp +++ b/src/core/labeling/qgspallabeling.cpp @@ -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,7 +1709,7 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt { document->splitLines( wrapchr, evalAutoWrapLength, useMaxLineLengthForAutoWrap ); - *documentMetrics = QgsTextDocumentMetrics::calculateMetrics( *document, mFormat, *rc ); + *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(); @@ -1724,13 +1726,13 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QSt 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 ) ) { @@ -1741,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 ) ) @@ -1763,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; @@ -1918,11 +1920,13 @@ std::unique_ptr 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 ) ) { @@ -1937,7 +1941,7 @@ std::unique_ptr QgsPalLayerSettings::registerFeatureWithDetails } //data defined label size? - double fontSize = mFormat.size(); + double fontSize = evaluatedFormat.size(); if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Property::Size ) ) { context.expressionContext().setOriginalValueVariable( fontSize ); @@ -1948,7 +1952,7 @@ std::unique_ptr 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 ) { @@ -1990,6 +1994,13 @@ std::unique_ptr 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. @@ -2023,7 +2034,7 @@ std::unique_ptr 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 ) { @@ -2116,15 +2127,15 @@ std::unique_ptr QgsPalLayerSettings::registerFeatureWithDetails QgsTextDocument doc; QgsTextDocumentMetrics documentMetrics; QRectF outerBounds; - if ( format().allowHtmlFormatting() && !labelText.isEmpty() ) + if ( evaluatedFormat.allowHtmlFormatting() && !labelText.isEmpty() ) { 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 ); + 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, nullptr, nullptr, &outerBounds ); + calculateLabelSize( labelFontMetrics.get(), labelText, labelWidth, labelHeight, mCurFeat, &context, &rotatedLabelX, &rotatedLabelY, &evaluatedFormat, nullptr, nullptr, &outerBounds ); } // maximum angle between curved label characters (hardcoded defaults used in QGIS <2.0) @@ -2825,7 +2836,7 @@ std::unique_ptr 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; } diff --git a/src/core/labeling/qgspallabeling.h b/src/core/labeling/qgspallabeling.h index 78d1be339e3..7fa69a83469 100644 --- a/src/core/labeling/qgspallabeling.h +++ b/src/core/labeling/qgspallabeling.h @@ -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 diff --git a/tests/src/core/testqgslabelingengine.cpp b/tests/src/core/testqgslabelingengine.cpp index 3d6dcf00220..f00f9778e4f 100644 --- a/tests/src/core/testqgslabelingengine.cpp +++ b/tests/src/core/testqgslabelingengine.cpp @@ -75,6 +75,7 @@ class TestQgsLabelingEngine : public QgsTest void testCurvedPerimeterLabelsHtmlFormatting(); void testCurvedLabelsHtmlSuperSubscript(); void testPointLabelHtmlFormatting(); + void testPointLabelHtmlFormattingDataDefinedSize(); void testCurvedLabelsWithTinySegments(); void testCurvedLabelCorrectLinePlacement(); void testCurvedLabelNegativeDistance(); @@ -1736,6 +1737,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( "'test HTML label

point'" ); + 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() << 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 From 886ebefed178ed9154ee992bec6de291704d47e9 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 28 May 2024 12:06:42 +1000 Subject: [PATCH 4/6] Don't set @value to line height when evaluating multi line alignment --- src/core/labeling/qgspallabeling.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/labeling/qgspallabeling.cpp b/src/core/labeling/qgspallabeling.cpp index 3882b7c4cb6..906725284a5 100644 --- a/src/core/labeling/qgspallabeling.cpp +++ b/src/core/labeling/qgspallabeling.cpp @@ -3559,7 +3559,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 ) ) { From b09e48f78b1ae5bdee78271cd5738e8002f6c87c Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 28 May 2024 12:33:03 +1000 Subject: [PATCH 5/6] Always calculate label document metrics at registration time Instead of calculating these at render time, calculate them at the time of label registration (for all labels except curved labels), as this means that we use the correct metrics for the label width and height as calculated by QgsTextDocumentMetrics. This ensures the label width/height is always calculated using the same rules as the text will be rendered. Previously we only did this for HTML enabled labels, but given that we will end up calculating the metrics when drawing the labels anyway there's no added cost in calculating them early. Among other fixes, this ensures that the correct label size is used in the engine for labels with tab characters. --- src/core/labeling/qgspallabeling.cpp | 46 ++++++-- .../labeling/qgsvectorlayerlabelprovider.cpp | 31 +++-- tests/src/core/testqgslabelingengine.cpp | 108 ++++++++++++++++++ .../expected_label_point_tabs.png | Bin 0 -> 7302 bytes .../expected_label_point_tabs_mask.png | Bin 0 -> 7548 bytes 5 files changed, 160 insertions(+), 25 deletions(-) create mode 100644 tests/testdata/control_images/labelingengine/expected_label_point_tabs/expected_label_point_tabs.png create mode 100644 tests/testdata/control_images/labelingengine/expected_label_point_tabs/expected_label_point_tabs_mask.png diff --git a/src/core/labeling/qgspallabeling.cpp b/src/core/labeling/qgspallabeling.cpp index 906725284a5..589b45bfe06 100644 --- a/src/core/labeling/qgspallabeling.cpp +++ b/src/core/labeling/qgspallabeling.cpp @@ -2127,15 +2127,45 @@ std::unique_ptr QgsPalLayerSettings::registerFeatureWithDetails QgsTextDocument doc; QgsTextDocumentMetrics documentMetrics; QRectF outerBounds; - if ( evaluatedFormat.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, &evaluatedFormat, &doc, &documentMetrics, &outerBounds ); - } - else - { - calculateLabelSize( labelFontMetrics.get(), labelText, labelWidth, labelHeight, mCurFeat, &context, &rotatedLabelX, &rotatedLabelY, &evaluatedFormat, 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) diff --git a/src/core/labeling/qgsvectorlayerlabelprovider.cpp b/src/core/labeling/qgsvectorlayerlabelprovider.cpp index 625c8218585..732d252e0b6 100644 --- a/src/core/labeling/qgsvectorlayerlabelprovider.cpp +++ b/src/core/labeling/qgsvectorlayerlabelprovider.cpp @@ -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 ) diff --git a/tests/src/core/testqgslabelingengine.cpp b/tests/src/core/testqgslabelingengine.cpp index f00f9778e4f..8d068bbab13 100644 --- a/tests/src/core/testqgslabelingengine.cpp +++ b/tests/src/core/testqgslabelingengine.cpp @@ -74,6 +74,8 @@ class TestQgsLabelingEngine : public QgsTest void testCurvedLabelsHtmlFormatting(); void testCurvedPerimeterLabelsHtmlFormatting(); void testCurvedLabelsHtmlSuperSubscript(); + void testPointLabelTabs(); + void testPointLabelTabsHtml(); void testPointLabelHtmlFormatting(); void testPointLabelHtmlFormattingDataDefinedSize(); void testCurvedLabelsWithTinySegments(); @@ -1684,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() << 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( "'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() << 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 diff --git a/tests/testdata/control_images/labelingengine/expected_label_point_tabs/expected_label_point_tabs.png b/tests/testdata/control_images/labelingengine/expected_label_point_tabs/expected_label_point_tabs.png new file mode 100644 index 0000000000000000000000000000000000000000..80d70259ceb8ffc5a58c54612db433e549ad7db2 GIT binary patch literal 7302 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 Date: Tue, 4 Jun 2024 20:28:40 +1000 Subject: [PATCH 6/6] Remove outdated comment --- tests/src/core/testqgslabelingengine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/src/core/testqgslabelingengine.cpp b/tests/src/core/testqgslabelingengine.cpp index 8d068bbab13..37366863826 100644 --- a/tests/src/core/testqgslabelingengine.cpp +++ b/tests/src/core/testqgslabelingengine.cpp @@ -5159,7 +5159,6 @@ void TestQgsLabelingEngine::testRotationBasedOrientationPointHtmlLabel() QgsDefaultLabelingEngine engine; engine.setMapSettings( mapSettings ); engine.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) ); - //engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly ); engine.run( context ); p.end();