Skip to content

Commit cd8d418

Browse files
committedMay 31, 2021
Don't try to render font marker symbols in massive font sizes
Instead, scale the painter after the font exceeds a certain threshold. The end result looks the same, but should avoid issues like the crash described in #42270 Fixes #42270 (cherry picked from commit a87e3d2)
1 parent 665d40d commit cd8d418

File tree

4 files changed

+42
-1
lines changed

4 files changed

+42
-1
lines changed
 

‎src/core/symbology/qgsmarkersymbollayer.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
Q_GUI_EXPORT extern int qt_defaultDpiX();
4040
Q_GUI_EXPORT extern int qt_defaultDpiY();
4141

42+
static constexpr int MAX_FONT_CHARACTER_SIZE_IN_PIXELS = 500;
43+
4244
static void _fixQPictureDPI( QPainter *p )
4345
{
4446
// QPicture makes an assumption that we drawing to it with system DPI.
@@ -3174,8 +3176,20 @@ void QgsFontMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
31743176
mFont.setStyleName( QgsFontUtils::translateNamedStyle( mFontStyle ) );
31753177
}
31763178

3177-
const double sizePixels = context.renderContext().convertToPainterUnits( mSize, mSizeUnit, mSizeMapUnitScale );
3179+
double sizePixels = context.renderContext().convertToPainterUnits( mSize, mSizeUnit, mSizeMapUnitScale );
31783180
mNonZeroFontSize = !qgsDoubleNear( sizePixels, 0.0 );
3181+
3182+
if ( mNonZeroFontSize && sizePixels > MAX_FONT_CHARACTER_SIZE_IN_PIXELS )
3183+
{
3184+
// if font is too large (e.g using map units and map is very zoomed in), then we limit
3185+
// the font size and instead scale up the painter.
3186+
// this avoids issues with massive font sizes (eg https://github.com/qgis/QGIS/issues/42270)
3187+
mFontSizeScale = sizePixels / MAX_FONT_CHARACTER_SIZE_IN_PIXELS;
3188+
sizePixels = MAX_FONT_CHARACTER_SIZE_IN_PIXELS;
3189+
}
3190+
else
3191+
mFontSizeScale = 1.0;
3192+
31793193
// if a non zero, but small pixel size results, round up to 2 pixels so that a "dot" is at least visible
31803194
// (if we set a <=1 pixel size here Qt will reset the font to a default size, leading to much too large symbols)
31813195
mFont.setPixelSize( std::max( 2, static_cast< int >( std::round( sizePixels ) ) ) );
@@ -3405,6 +3419,9 @@ void QgsFontMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContex
34053419
transform.scale( s, s );
34063420
}
34073421

3422+
if ( !qgsDoubleNear( mFontSizeScale, 1.0 ) )
3423+
transform.scale( mFontSizeScale, mFontSizeScale );
3424+
34083425
if ( mUseCachedPath )
34093426
{
34103427
p->drawPath( transform.map( mCachedPath ) );
@@ -3514,6 +3531,7 @@ QRectF QgsFontMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &
35143531
{
35153532
chrWidth *= scaledSize / mOrigSize;
35163533
}
3534+
chrWidth *= mFontSizeScale;
35173535

35183536
bool hasDataDefinedRotation = false;
35193537
QPointF offset;

‎src/core/symbology/qgsmarkersymbollayer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -996,6 +996,8 @@ class CORE_EXPORT QgsFontMarkerSymbolLayer : public QgsMarkerSymbolLayer
996996

997997
double mChrWidth = 0;
998998
QPointF mChrOffset;
999+
//! Scaling for font sizes, used if font size grows too large
1000+
double mFontSizeScale = 1.0;
9991001
double mOrigSize;
10001002

10011003
QColor mStrokeColor;

‎tests/src/core/testqgsfontmarker.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class TestQgsFontMarkerSymbol : public QObject
6060
void bounds();
6161
void fontMarkerSymbolDataDefinedProperties();
6262
void opacityWithDataDefinedColor();
63+
void massiveFont();
6364

6465
private:
6566
bool mTestHasError = false ;
@@ -219,6 +220,26 @@ void TestQgsFontMarkerSymbol::opacityWithDataDefinedColor()
219220
QVERIFY( result );
220221
}
221222

223+
void TestQgsFontMarkerSymbol::massiveFont()
224+
{
225+
// test rendering a massive font
226+
mFontMarkerLayer->setColor( QColor( 0, 0, 0, 100 ) );
227+
mFontMarkerLayer->setStrokeColor( QColor( 0, 0, 0, 0 ) );
228+
QFont font = QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) );
229+
mFontMarkerLayer->setFontFamily( font.family() );
230+
mFontMarkerLayer->setDataDefinedProperties( QgsPropertyCollection() );
231+
mFontMarkerLayer->setCharacter( QChar( 'X' ) );
232+
mFontMarkerLayer->setSize( 200 );
233+
mFontMarkerLayer->setSizeUnit( QgsUnitTypes::RenderMillimeters );
234+
mFontMarkerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, QgsProperty::fromExpression( QStringLiteral( "if(importance > 2, 100, 350)" ) ) );
235+
mFontMarkerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyLayerEnabled, QgsProperty::fromExpression( QStringLiteral( "$id in (1, 4)" ) ) ); // 3
236+
mFontMarkerLayer->setStrokeWidth( 0.5 );
237+
238+
bool result = imageCheck( QStringLiteral( "fontmarker_largesize" ) );
239+
mFontMarkerLayer->setDataDefinedProperties( QgsPropertyCollection() );
240+
QVERIFY( result );
241+
}
242+
222243
//
223244
// Private helper functions not called directly by CTest
224245
//

0 commit comments

Comments
 (0)
Please sign in to comment.