Skip to content

Commit

Permalink
[labeling] Fix evalution of letter/word spacing when font size is map…
Browse files Browse the repository at this point in the history
… units

Fixes #32825

(cherry picked from commit 0d6599a)
  • Loading branch information
nyalldawson committed Nov 21, 2019
1 parent ff97207 commit 4e18d91
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 6 deletions.
11 changes: 6 additions & 5 deletions src/core/qgspallabeling.cpp
Expand Up @@ -1786,9 +1786,10 @@ void QgsPalLayerSettings::registerFeature( const QgsFeature &f, QgsRenderContext
// calculate rest of font attributes and store any data defined values
// this is done here for later use in making label backgrounds part of collision management (when implemented)
labelFont.setCapitalization( QFont::MixedCase ); // reset this - we don't use QFont's handling as it breaks with curved labels

parseTextStyle( labelFont, fontunits, context );
if ( mDataDefinedProperties.hasActiveProperties() )
{
parseTextStyle( labelFont, fontunits, context );
parseTextFormatting( context );
parseTextBuffer( context );
parseShapeBackground( context );
Expand Down Expand Up @@ -2923,22 +2924,22 @@ void QgsPalLayerSettings::parseTextStyle( QFont &labelFont,
}

// data defined word spacing?
double wordspace = labelFont.wordSpacing();
if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::FontWordSpacing ) )
{
double wordspace = labelFont.wordSpacing();
context.expressionContext().setOriginalValueVariable( wordspace );
wordspace = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::FontWordSpacing, context.expressionContext(), wordspace );
labelFont.setWordSpacing( context.convertToPainterUnits( wordspace, fontunits, mFormat.sizeMapUnitScale() ) );
}
labelFont.setWordSpacing( context.convertToPainterUnits( wordspace, fontunits, mFormat.sizeMapUnitScale() ) );

// data defined letter spacing?
double letterspace = labelFont.letterSpacing();
if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::FontLetterSpacing ) )
{
double letterspace = labelFont.letterSpacing();
context.expressionContext().setOriginalValueVariable( letterspace );
letterspace = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::FontLetterSpacing, context.expressionContext(), letterspace );
labelFont.setLetterSpacing( QFont::AbsoluteSpacing, context.convertToPainterUnits( letterspace, fontunits, mFormat.sizeMapUnitScale() ) );
}
labelFont.setLetterSpacing( QFont::AbsoluteSpacing, context.convertToPainterUnits( letterspace, fontunits, mFormat.sizeMapUnitScale() ) );

// data defined strikeout font style?
if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Strikeout ) )
Expand Down
110 changes: 109 additions & 1 deletion tests/src/core/testqgslabelingengine.cpp
Expand Up @@ -77,6 +77,8 @@ class TestQgsLabelingEngine : public QObject
void testVerticalOrientationLetterLineSpacing();
void testRotationBasedOrientationPoint();
void testRotationBasedOrientationLine();
void testMapUnitLetterSpacing();
void testMapUnitWordSpacing();

private:
QgsVectorLayer *vl = nullptr;
Expand Down Expand Up @@ -2349,7 +2351,7 @@ void TestQgsLabelingEngine::testVerticalOrientationLetterLineSpacing()
format.setOrientation( QgsTextFormat::VerticalOrientation );
format.setLineHeight( 1.5 );
QFont font = format.font();
font.setLetterSpacing( QFont::AbsoluteSpacing, 5 );
font.setLetterSpacing( QFont::AbsoluteSpacing, 3.75 );
format.setFont( font );
settings.setFormat( format );

Expand Down Expand Up @@ -2467,5 +2469,111 @@ void TestQgsLabelingEngine::testRotationBasedOrientationLine()
QgsProject::instance()->removeMapLayer( vl2 );
}

void TestQgsLabelingEngine::testMapUnitLetterSpacing()
{
QgsPalLayerSettings settings;
setDefaultLabelParams( settings );

QgsTextFormat format = settings.format();
format.setSize( 50 );
format.setSizeUnit( QgsUnitTypes::RenderMapUnits );
format.setColor( QColor( 0, 0, 0 ) );
settings.setFormat( format );

settings.fieldName = QStringLiteral( "'XX'" );
settings.isExpression = true;
settings.placement = QgsPalLayerSettings::Line;
QFont font = format.font();
font.setLetterSpacing( QFont::AbsoluteSpacing, 30 );
format.setFont( font );
settings.setFormat( format );

std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:3946&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
vl2->setRenderer( new QgsNullSymbolRenderer() );

QgsFeature f;
f.setAttributes( QgsAttributes() << 1 );
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString (190020 5000000, 190180 5000000)" ) ) );
QVERIFY( vl2->dataProvider()->addFeature( f ) );

vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
vl2->setLabelsEnabled( true );

// make a fake render context
QSize size( 640, 480 );
QgsMapSettings mapSettings;
mapSettings.setDestinationCrs( vl2->crs() );

mapSettings.setOutputSize( size );
mapSettings.setExtent( QgsRectangle( 190000, 5000000, 190200, 5000010 ) );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl2.get() );
mapSettings.setOutputDpi( 96 );

QgsLabelingEngineSettings engineSettings = mapSettings.labelingEngineSettings();
engineSettings.setFlag( QgsLabelingEngineSettings::UsePartialCandidates, false );
//engineSettings.setFlag( QgsLabelingEngineSettings::DrawCandidates, true );
mapSettings.setLabelingEngineSettings( engineSettings );

QgsMapRendererSequentialJob job( mapSettings );
job.start();
job.waitForFinished();

QImage img = job.renderedImage();
QVERIFY( imageCheck( QStringLiteral( "label_letter_spacing_map_units" ), img, 20 ) );
}

void TestQgsLabelingEngine::testMapUnitWordSpacing()
{
QgsPalLayerSettings settings;
setDefaultLabelParams( settings );

QgsTextFormat format = settings.format();
format.setSize( 50 );
format.setSizeUnit( QgsUnitTypes::RenderMapUnits );
format.setColor( QColor( 0, 0, 0 ) );
settings.setFormat( format );

settings.fieldName = QStringLiteral( "'X X'" );
settings.isExpression = true;
settings.placement = QgsPalLayerSettings::Line;
QFont font = format.font();
font.setWordSpacing( 30 );
format.setFont( font );
settings.setFormat( format );

std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:3946&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
vl2->setRenderer( new QgsNullSymbolRenderer() );

QgsFeature f;
f.setAttributes( QgsAttributes() << 1 );
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString (190020 5000000, 190180 5000000)" ) ) );
QVERIFY( vl2->dataProvider()->addFeature( f ) );

vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
vl2->setLabelsEnabled( true );

// make a fake render context
QSize size( 640, 480 );
QgsMapSettings mapSettings;
mapSettings.setDestinationCrs( vl2->crs() );

mapSettings.setOutputSize( size );
mapSettings.setExtent( QgsRectangle( 190000, 5000000, 190200, 5000010 ) );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl2.get() );
mapSettings.setOutputDpi( 96 );

QgsLabelingEngineSettings engineSettings = mapSettings.labelingEngineSettings();
engineSettings.setFlag( QgsLabelingEngineSettings::UsePartialCandidates, false );
//engineSettings.setFlag( QgsLabelingEngineSettings::DrawCandidates, true );
mapSettings.setLabelingEngineSettings( engineSettings );

QgsMapRendererSequentialJob job( mapSettings );
job.start();
job.waitForFinished();

QImage img = job.renderedImage();
QVERIFY( imageCheck( QStringLiteral( "label_word_spacing_map_units" ), img, 20 ) );
}

QGSTEST_MAIN( TestQgsLabelingEngine )
#include "testqgslabelingengine.moc"
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 4e18d91

Please sign in to comment.