Skip to content
Permalink
Browse files

[api] Apply a font scale workaround factor to QgsTextRenderer

This is a hack which has been in place in layouts/composer for a long
time in order to provide more consistent and reliable text rendering
at small font sizes or when "zoomed out". Without this hack the font
rendering and metric based calculations for these small font sizes
can be unstable, leading to font sizes "jumping" around as a layout
is zoomed into or out of.
  • Loading branch information
nyalldawson committed Jul 7, 2020
1 parent 9eef5d7 commit 0dd1490fdce5e45139520ac708654b241f76dcab
@@ -108,10 +108,15 @@ Sets whether the format has overline ``enabled``.
.. seealso:: :py:func:`overline`
%End

void updateFontForFormat( QFont &font ) const;
void updateFontForFormat( QFont &font, double scaleFactor = 1.0 ) const;
%Docstring
Updates the specified ``font`` in place, applying character formatting options which
are applicable on a font level.

The optional ``scaleFactor`` parameter can specify a font size scaling factor. It is recommended to set this to
QgsTextRenderer.FONT_WORKAROUND_SCALE and then manually calculations
based on the resultant font metrics. Failure to do so will result in poor quality text rendering
at small font sizes.
%End

};
@@ -132,12 +132,16 @@ of rendered text.
.. seealso:: :py:func:`toQFont`
%End

QFont scaledFont( const QgsRenderContext &context ) const;
QFont scaledFont( const QgsRenderContext &context, double scaleFactor = 1.0 ) const;
%Docstring
Returns a font with the size scaled to match the format's size settings (including
units and map unit scale) for a specified render context.

:param context: destination render context
:param scaleFactor: optional font size scaling factor. It is recommended to set this to
QgsTextRenderer.FONT_WORKAROUND_SCALE and then manually scale painter devices or calculations
based on the resultant font metrics. Failure to do so will result in poor quality text rendering
at small font sizes.

:return: font with scaled size

@@ -64,13 +64,18 @@ Sets the character ``format`` for the fragment.
.. seealso:: :py:func:`characterFormat`
%End

double horizontalAdvance( const QFont &font, bool fontHasBeenUpdatedForFragment = false ) const;
double horizontalAdvance( const QFont &font, bool fontHasBeenUpdatedForFragment = false, double scaleFactor = 1.0 ) const;
%Docstring
Returns the horizontal advance associated with this fragment, when rendered using
the specified base ``font``.

Set ``fontHasBeenUpdatedForFragment`` to ``True`` if ``font`` already represents the character
format for this fragment.

The optional ``scaleFactor`` parameter can specify a font size scaling factor. It is recommended to set this to
QgsTextRenderer.FONT_WORKAROUND_SCALE and then manually calculations
based on the resultant font metrics. Failure to do so will result in poor quality text rendering
at small font sizes.
%End

};
@@ -143,12 +143,17 @@ Draws a single component of rendered text using the specified settings.
Private API only, will be removed in 4.0
%End

static QFontMetricsF fontMetrics( QgsRenderContext &context, const QgsTextFormat &format );
static QFontMetricsF fontMetrics( QgsRenderContext &context, const QgsTextFormat &format, double scaleFactor = 1.0 );
%Docstring
Returns the font metrics for the given text ``format``, when rendered
in the specified render ``context``. The font metrics will take into account
all scaling required by the render context.

The optional ``scaleFactor`` argument can specify a font size scaling factor. It is recommended to set this to
QgsTextRenderer.FONT_WORKAROUND_SCALE and then manually scale painter devices or calculations
based on the resultant font metrics. Failure to do so will result in poor quality text rendering
at small font sizes.

.. versionadded:: 3.2
%End

@@ -175,6 +180,8 @@ Returns the height of a text based on a given format.
:param fontMetrics: font metrics
%End

static const double FONT_WORKAROUND_SCALE;

};


@@ -72,8 +72,9 @@ void QgsTextCharacterFormat::setOverline( QgsTextCharacterFormat::BooleanValue e
mOverline = enabled;
}

void QgsTextCharacterFormat::updateFontForFormat( QFont &font ) const
void QgsTextCharacterFormat::updateFontForFormat( QFont &font, const double scaleFactor ) const
{
Q_UNUSED( scaleFactor );
#if 0 // settings which affect font metrics are disabled for now
if ( mItalic != QgsTextCharacterFormat::BooleanValue::NotSet )
font.setItalic( mItalic == QgsTextCharacterFormat::BooleanValue::SetTrue );
@@ -156,8 +156,13 @@ class CORE_EXPORT QgsTextCharacterFormat
/**
* Updates the specified \a font in place, applying character formatting options which
* are applicable on a font level.
*
* The optional \a scaleFactor parameter can specify a font size scaling factor. It is recommended to set this to
* QgsTextRenderer::FONT_WORKAROUND_SCALE and then manually calculations
* based on the resultant font metrics. Failure to do so will result in poor quality text rendering
* at small font sizes.
*/
void updateFontForFormat( QFont &font ) const;
void updateFontForFormat( QFont &font, double scaleFactor = 1.0 ) const;

private:

@@ -64,12 +64,20 @@ QFont QgsTextFormat::font() const
return d->textFont;
}

QFont QgsTextFormat::scaledFont( const QgsRenderContext &context ) const
QFont QgsTextFormat::scaledFont( const QgsRenderContext &context, double scaleFactor ) const
{
QFont font = d->textFont;
int fontPixelSize = QgsTextRenderer::sizeToPixel( d->fontSize, context, d->fontSizeUnits,
d->fontSizeMapUnitScale );
font.setPixelSize( fontPixelSize );
if ( scaleFactor == 1 )
{
int fontPixelSize = QgsTextRenderer::sizeToPixel( d->fontSize, context, d->fontSizeUnits,
d->fontSizeMapUnitScale );
font.setPixelSize( fontPixelSize );
}
else
{
double fontPixelSize = context.convertToPainterUnits( d->fontSize, d->fontSizeUnits, d->fontSizeMapUnitScale );
font.setPixelSize( std::round( scaleFactor * fontPixelSize + 0.5 ) );
}
return font;
}

@@ -154,11 +154,15 @@ class CORE_EXPORT QgsTextFormat
* Returns a font with the size scaled to match the format's size settings (including
* units and map unit scale) for a specified render context.
* \param context destination render context
* \param scaleFactor optional font size scaling factor. It is recommended to set this to
* QgsTextRenderer::FONT_WORKAROUND_SCALE and then manually scale painter devices or calculations
* based on the resultant font metrics. Failure to do so will result in poor quality text rendering
* at small font sizes.
* \returns font with scaled size
* \see font()
* \see size()
*/
QFont scaledFont( const QgsRenderContext &context ) const;
QFont scaledFont( const QgsRenderContext &context, double scaleFactor = 1.0 ) const;

/**
* Sets the font used for rendering text. Note that the size of the font
@@ -44,7 +44,7 @@ void QgsTextFragment::setCharacterFormat( const QgsTextCharacterFormat &charForm
mCharFormat = charFormat;
}

double QgsTextFragment::horizontalAdvance( const QFont &font, bool fontHasBeenUpdatedForFragment ) const
double QgsTextFragment::horizontalAdvance( const QFont &font, bool fontHasBeenUpdatedForFragment, double scaleFactor ) const
{
if ( fontHasBeenUpdatedForFragment )
{
@@ -58,7 +58,7 @@ double QgsTextFragment::horizontalAdvance( const QFont &font, bool fontHasBeenUp
else
{
QFont updatedFont = font;
mCharFormat.updateFontForFormat( updatedFont );
mCharFormat.updateFontForFormat( updatedFont, scaleFactor );
QFontMetricsF fm( updatedFont );
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
return fm.width( mText );
@@ -79,8 +79,13 @@ class CORE_EXPORT QgsTextFragment
*
* Set \a fontHasBeenUpdatedForFragment to TRUE if \a font already represents the character
* format for this fragment.
*
* The optional \a scaleFactor parameter can specify a font size scaling factor. It is recommended to set this to
* QgsTextRenderer::FONT_WORKAROUND_SCALE and then manually calculations
* based on the resultant font metrics. Failure to do so will result in poor quality text rendering
* at small font sizes.
*/
double horizontalAdvance( const QFont &font, bool fontHasBeenUpdatedForFragment = false ) const;
double horizontalAdvance( const QFont &font, bool fontHasBeenUpdatedForFragment = false, double scaleFactor = 1.0 ) const;

private:

0 comments on commit 0dd1490

Please sign in to comment.
You can’t perform that action at this time.