Skip to content

Commit

Permalink
Add a workaround for setting QFont objects to font families with
Browse files Browse the repository at this point in the history
odd characters in their names

This can result in the font falling back to a default system
font. It's notably an issue for the "ESRI Oil, Gas, & Water"
symbol font.
  • Loading branch information
nyalldawson committed Oct 3, 2023
1 parent 575f726 commit 52df647
Show file tree
Hide file tree
Showing 24 changed files with 112 additions and 41 deletions.
18 changes: 18 additions & 0 deletions python/core/auto_generated/qgsfontutils.sip.in
Expand Up @@ -250,6 +250,24 @@ Returns a list of recently used font families.
.. seealso:: :py:func:`addRecentFontFamily`

.. versionadded:: 3.0
%End

static void setFontFamily( QFont &font, const QString &family );
%Docstring
Sets the ``family`` for a ``font`` object.

Applies some workarounds for specific font quirks.

.. versionadded:: 3.34
%End

static QFont createFont( const QString &family, int pointSize = -1, int weight = -1, bool italic = false );
%Docstring
Creates a font with the specified ``family``.

Applies some workarounds for specific font quirks.

.. versionadded:: 3.34
%End
};

Expand Down
2 changes: 1 addition & 1 deletion src/app/labeling/qgslabelpropertydialog.cpp
Expand Up @@ -749,7 +749,7 @@ void QgsLabelPropertyDialog::mYCoordSpinBox_valueChanged( double d )

void QgsLabelPropertyDialog::mFontFamilyCmbBx_currentFontChanged( const QFont &f )
{
mLabelFont.setFamily( f.family() );
QgsFontUtils::setFontFamily( mLabelFont, f.family() );
updateFont( mLabelFont );
insertChangedValue( QgsPalLayerSettings::Family, f.family() );
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/labeling/qgsmaptoollabel.cpp
Expand Up @@ -34,7 +34,7 @@
#include "qgsnewauxiliarylayerdialog.h"
#include "qgsadvanceddigitizingdockwidget.h"
#include "qgssettingsentryimpl.h"

#include "qgsfontutils.h"

#include <QMouseEvent>

Expand Down Expand Up @@ -511,7 +511,7 @@ QFont QgsMapToolLabel::currentLabelFont()
int fmIndx = dataDefinedColumnIndex( QgsPalLayerSettings::Family, labelSettings, vlayer );
if ( fmIndx != -1 )
{
font.setFamily( f.attribute( fmIndx ).toString() );
QgsFontUtils::setFontFamily( font, f.attribute( fmIndx ).toString() );
}

//underline
Expand Down
3 changes: 2 additions & 1 deletion src/app/qgstextannotationdialog.cpp
Expand Up @@ -25,6 +25,7 @@
#include "qgshelp.h"
#include "qgsfillsymbol.h"
#include "qgssettingsentryimpl.h"
#include "qgsfontutils.h"

#include <QColorDialog>
#include <QGraphicsScene>
Expand Down Expand Up @@ -119,7 +120,7 @@ void QgsTextAnnotationDialog::applyTextToItem()
void QgsTextAnnotationDialog::changeCurrentFormat()
{
QFont newFont;
newFont.setFamily( mFontComboBox->currentFont().family() );
QgsFontUtils::setFontFamily( newFont, mFontComboBox->currentFont().family() );

//bold
if ( mBoldPushButton->isChecked() )
Expand Down
4 changes: 2 additions & 2 deletions src/core/labeling/qgspallabeling.cpp
Expand Up @@ -3260,7 +3260,7 @@ void QgsPalLayerSettings::parseTextStyle( QFont &labelFont,
if ( ddBold || ddItalic )
{
// new font needs built, since existing style needs removed
newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : labelFont.family() );
newFont = QgsFontUtils::createFont( !ddFontFamily.isEmpty() ? ddFontFamily : labelFont.family() );
newFontBuilt = true;
newFont.setBold( ddBold );
newFont.setItalic( ddItalic );
Expand Down Expand Up @@ -3301,7 +3301,7 @@ void QgsPalLayerSettings::parseTextStyle( QFont &labelFont,
}
else
{
newFont = QFont( ddFontFamily );
newFont = QgsFontUtils::createFont( ddFontFamily );
newFontBuilt = true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/layout/qgslayoutitemattributetable.cpp
Expand Up @@ -677,7 +677,7 @@ QgsTextFormat QgsLayoutItemAttributeTable::textFormatForCell( int row, int colum
{
QFont newFont = format.font();
// we want to keep all the other font settings, like word/letter spacing
newFont.setFamily( styleFont.family() );
QgsFontUtils::setFontFamily( newFont, styleFont.family() );

// warning -- there's a potential trap here! We can't just read QFont::styleName(), as that may be blank even when
// the font has the bold or italic attributes set! Reading the style name via QFontInfo avoids this and always returns
Expand Down
2 changes: 1 addition & 1 deletion src/core/layout/qgslayoutitemlabel.cpp
Expand Up @@ -51,7 +51,7 @@ QgsLayoutItemLabel::QgsLayoutItemLabel( QgsLayout *layout )
if ( !defaultFontString.isEmpty() )
{
QFont f = mFormat.font();
f.setFamily( defaultFontString );
QgsFontUtils::setFontFamily( f, defaultFontString );
mFormat.setFont( f );
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/layout/qgslayoutitemmapgrid.cpp
Expand Up @@ -195,7 +195,7 @@ QgsLayoutItemMapGrid::QgsLayoutItemMapGrid( const QString &name, QgsLayoutItemMa
if ( !defaultFontString.isEmpty() )
{
QFont font;
font.setFamily( defaultFontString );
QgsFontUtils::setFontFamily( font, defaultFontString );
mAnnotationFormat.setFont( font );
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/layout/qgslayoutitemscalebar.cpp
Expand Up @@ -673,7 +673,7 @@ void QgsLayoutItemScaleBar::applyDefaultSettings()
QFont f;
if ( !defaultFontString.isEmpty() )
{
f.setFamily( defaultFontString );
QgsFontUtils::setFontFamily( f, defaultFontString );
}
format.setFont( f );
format.setSize( 12.0 );
Expand Down
5 changes: 3 additions & 2 deletions src/core/qgsdatadefinedsizelegend.cpp
Expand Up @@ -24,6 +24,7 @@
#include "qgstextrenderer.h"
#include "qgsmarkersymbol.h"
#include "qgslinesymbol.h"
#include "qgsfontutils.h"

QgsDataDefinedSizeLegend::QgsDataDefinedSizeLegend()
{
Expand Down Expand Up @@ -397,8 +398,8 @@ QgsDataDefinedSizeLegend *QgsDataDefinedSizeLegend::readXml( const QDomElement &
QDomElement elemFont = elemTextStyle.firstChildElement( QStringLiteral( "font" ) );
if ( !elemFont.isNull() )
{
ddsLegend->setFont( QFont( elemFont.attribute( QStringLiteral( "family" ) ), elemFont.attribute( QStringLiteral( "size" ) ).toInt(),
elemFont.attribute( QStringLiteral( "weight" ) ).toInt(), elemFont.attribute( QStringLiteral( "italic" ) ).toInt() ) );
ddsLegend->setFont( QgsFontUtils::createFont( elemFont.attribute( QStringLiteral( "family" ) ), elemFont.attribute( QStringLiteral( "size" ) ).toInt(),
elemFont.attribute( QStringLiteral( "weight" ) ).toInt(), elemFont.attribute( QStringLiteral( "italic" ) ).toInt() ) );
}
ddsLegend->setTextColor( QgsSymbolLayerUtils::decodeColor( elemTextStyle.attribute( QStringLiteral( "color" ) ) ) );
ddsLegend->setTextAlignment( static_cast<Qt::AlignmentFlag>( elemTextStyle.attribute( QStringLiteral( "align" ) ).toInt() ) );
Expand Down
25 changes: 25 additions & 0 deletions src/core/qgsfontutils.cpp
Expand Up @@ -605,3 +605,28 @@ QStringList QgsFontUtils::recentFontFamilies()
const QgsSettings settings;
return settings.value( QStringLiteral( "fonts/recent" ) ).toStringList();
}

void QgsFontUtils::setFontFamily( QFont &font, const QString &family )
{
font.setFamily( family );
if ( !font.exactMatch() )
{
// some Qt versions struggle with fonts with certain unusual characters
// in their names, eg "ESRI Oil, Gas, & Water". Calling "setFamilies"
// can workaround these issues... (in some cases!)
font.setFamilies( { family } );
}
}

QFont QgsFontUtils::createFont( const QString &family, int pointSize, int weight, bool italic )
{
QFont font( family, pointSize, weight, italic );
if ( !font.exactMatch() )
{
// some Qt versions struggle with fonts with certain unusual characters
// in their names, eg "ESRI Oil, Gas, & Water". Calling "setFamilies"
// can workaround these issues... (in some cases!)
font.setFamilies( { family } );
}
return font;
}
18 changes: 18 additions & 0 deletions src/core/qgsfontutils.h
Expand Up @@ -207,6 +207,24 @@ class CORE_EXPORT QgsFontUtils
* \since QGIS 3.0
*/
static QStringList recentFontFamilies();

/**
* Sets the \a family for a \a font object.
*
* Applies some workarounds for specific font quirks.
*
* \since QGIS 3.34
*/
static void setFontFamily( QFont &font, const QString &family );

/**
* Creates a font with the specified \a family.
*
* Applies some workarounds for specific font quirks.
*
* \since QGIS 3.34
*/
static QFont createFont( const QString &family, int pointSize = -1, int weight = -1, bool italic = false );
};

// clazy:excludeall=qstring-allocations
Expand Down
4 changes: 2 additions & 2 deletions src/core/symbology/qgsmarkersymbollayer.cpp
Expand Up @@ -3536,7 +3536,7 @@ void QgsFontMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
mPen.setJoinStyle( mPenJoinStyle );
mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );

mFont = QFont( QgsApplication::fontManager()->processFontFamilyName( mFontFamily ) );
mFont = QgsFontUtils::createFont( QgsApplication::fontManager()->processFontFamilyName( mFontFamily ) );
if ( !mFontStyle.isEmpty() )
{
mFont.setStyleName( QgsFontUtils::translateNamedStyle( mFontStyle ) );
Expand Down Expand Up @@ -3744,7 +3744,7 @@ void QgsFontMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContex
context.setOriginalValueVariable( mFontFamily );
const QString fontFamily = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyFontFamily, context.renderContext().expressionContext(), mFontFamily, &ok );
const QString processedFamily = QgsApplication::fontManager()->processFontFamilyName( ok ? fontFamily : mFontFamily );
mFont.setFamily( processedFamily );
QgsFontUtils::setFontFamily( mFont, processedFamily );
}
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontStyle ) )
{
Expand Down
3 changes: 2 additions & 1 deletion src/core/textrenderer/qgstextcharacterformat.cpp
Expand Up @@ -15,6 +15,7 @@

#include "qgstextcharacterformat.h"
#include "qgsrendercontext.h"
#include "qgsfontutils.h"

#include <QTextCharFormat>

Expand Down Expand Up @@ -119,7 +120,7 @@ void QgsTextCharacterFormat::updateFontForFormat( QFont &font, const QgsRenderCo
{
// important -- MUST set family first
if ( !mFontFamily.isEmpty() )
font.setFamily( mFontFamily );
QgsFontUtils::setFontFamily( font, mFontFamily );

if ( mFontPointSize != -1 )
font.setPixelSize( scaleFactor * context.convertToPainterUnits( mFontPointSize, Qgis::RenderUnit::Points ) );
Expand Down
8 changes: 4 additions & 4 deletions src/core/textrenderer/qgstextformat.cpp
Expand Up @@ -482,7 +482,7 @@ void QgsTextFormat::readFromLayer( QgsVectorLayer *layer )
}
int fontWeight = layer->customProperty( QStringLiteral( "labeling/fontWeight" ) ).toInt();
bool fontItalic = layer->customProperty( QStringLiteral( "labeling/fontItalic" ) ).toBool();
d->textFont = QFont( fontFamily, d->fontSize, fontWeight, fontItalic );
d->textFont = QgsFontUtils::createFont( fontFamily, d->fontSize, fontWeight, fontItalic );
d->textNamedStyle = QgsFontUtils::translateNamedStyle( layer->customProperty( QStringLiteral( "labeling/namedStyle" ), QVariant( "" ) ).toString() );
QgsFontUtils::updateFontViaStyle( d->textFont, d->textNamedStyle ); // must come after textFont.setPointSizeF()
d->capitalization = static_cast< Qgis::Capitalization >( layer->customProperty( QStringLiteral( "labeling/fontCapitals" ), QVariant( 0 ) ).toUInt() );
Expand Down Expand Up @@ -604,7 +604,7 @@ void QgsTextFormat::readXml( const QDomElement &elem, const QgsReadWriteContext
}
int fontWeight = textStyleElem.attribute( QStringLiteral( "fontWeight" ) ).toInt();
bool fontItalic = textStyleElem.attribute( QStringLiteral( "fontItalic" ) ).toInt();
d->textFont = QFont( fontFamily, d->fontSize, fontWeight, fontItalic );
d->textFont = QgsFontUtils::createFont( fontFamily, d->fontSize, fontWeight, fontItalic );
d->textFont.setPointSizeF( d->fontSize ); //double precision needed because of map units
d->textNamedStyle = QgsFontUtils::translateNamedStyle( textStyleElem.attribute( QStringLiteral( "namedStyle" ) ) );
QgsFontUtils::updateFontViaStyle( d->textFont, d->textNamedStyle ); // must come after textFont.setPointSizeF()
Expand Down Expand Up @@ -953,7 +953,7 @@ void QgsTextFormat::updateDataDefinedProperties( QgsRenderContext &context )
if ( ddBold || ddItalic )
{
// new font needs built, since existing style needs removed
newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : d->textFont.family() );
newFont = QgsFontUtils::createFont( !ddFontFamily.isEmpty() ? ddFontFamily : d->textFont.family() );
newFontBuilt = true;
newFont.setBold( ddBold );
newFont.setItalic( ddItalic );
Expand Down Expand Up @@ -989,7 +989,7 @@ void QgsTextFormat::updateDataDefinedProperties( QgsRenderContext &context )
}
else
{
newFont = QFont( ddFontFamily );
newFont = QgsFontUtils::createFont( ddFontFamily );
newFontBuilt = true;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/core/vectortile/qgsmapboxglstyleconverter.cpp
Expand Up @@ -1327,7 +1327,7 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,
QString fontFamily;
if ( splitFontFamily( fontName, fontFamily, fontStyleName ) )
{
textFont = QFont( fontFamily );
textFont = QgsFontUtils::createFont( fontFamily );
if ( !fontStyleName.isEmpty() )
textFont.setStyleName( fontStyleName );
foundFont = true;
Expand All @@ -1340,15 +1340,15 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,
if ( QgsFontUtils::fontFamilyHasStyle( QStringLiteral( "Open Sans" ), QStringLiteral( "Regular" ) ) )
{
fontName = QStringLiteral( "Open Sans" );
textFont = QFont( fontName );
textFont = QgsFontUtils::createFont( fontName );
textFont.setStyleName( QStringLiteral( "Regular" ) );
fontStyleName = QStringLiteral( "Regular" );
foundFont = true;
}
else if ( QgsFontUtils::fontFamilyHasStyle( QStringLiteral( "Arial Unicode MS" ), QStringLiteral( "Regular" ) ) )
{
fontName = QStringLiteral( "Arial Unicode MS" );
textFont = QFont( fontName );
textFont = QgsFontUtils::createFont( fontName );
textFont.setStyleName( QStringLiteral( "Regular" ) );
fontStyleName = QStringLiteral( "Regular" );
foundFont = true;
Expand Down
5 changes: 3 additions & 2 deletions src/gui/codeeditors/qgscodeeditor.cpp
Expand Up @@ -22,6 +22,7 @@
#include "qgscodeeditorcolorschemeregistry.h"
#include "qgscodeeditorhistorydialog.h"
#include "qgsstringutils.h"
#include "qgsfontutils.h"

#include <QLabel>
#include <QWidget>
Expand Down Expand Up @@ -363,7 +364,7 @@ QFont QgsCodeEditor::lexerFont() const

const QgsSettings settings;
if ( !mFontFamily.isEmpty() )
font.setFamily( mFontFamily );
QgsFontUtils::setFontFamily( font, mFontFamily );

#ifdef Q_OS_MAC
if ( mFontSize > 0 )
Expand Down Expand Up @@ -1019,7 +1020,7 @@ QFont QgsCodeEditor::getMonospaceFont()

const QgsSettings settings;
if ( !settings.value( QStringLiteral( "codeEditor/fontfamily" ), QString(), QgsSettings::Gui ).toString().isEmpty() )
font.setFamily( settings.value( QStringLiteral( "codeEditor/fontfamily" ), QString(), QgsSettings::Gui ).toString() );
QgsFontUtils::setFontFamily( font, settings.value( QStringLiteral( "codeEditor/fontfamily" ), QString(), QgsSettings::Gui ).toString() );

const int fontSize = settings.value( QStringLiteral( "codeEditor/fontsize" ), 0, QgsSettings::Gui ).toInt();

Expand Down
11 changes: 6 additions & 5 deletions src/gui/layout/qgslayoutguiutils.cpp
Expand Up @@ -47,6 +47,7 @@
#include "qgslayoutelevationprofilewidget.h"
#include "qgsmapcanvas.h"
#include "qgsplot.h"
#include "qgsfontutils.h"

/**
* Attempts to find the best guess at a map item to link \a referenceItem to,
Expand Down Expand Up @@ -232,7 +233,7 @@ void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
if ( !defaultFontString.isEmpty() )
{
QFont font;
font.setFamily( defaultFontString );
QgsFontUtils::setFontFamily( font, defaultFontString );

QgsTextFormat f = legend->rstyle( QgsLegendStyle::Title ).textFormat();
f.setFont( font );
Expand Down Expand Up @@ -464,7 +465,7 @@ void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
{
QgsTextFormat format;
QFont f = format.font();
f.setFamily( defaultFontString );
QgsFontUtils::setFontFamily( f, defaultFontString );
format.setFont( f );
tableMultiFrame->setContentTextFormat( format );
f.setBold( true );
Expand Down Expand Up @@ -506,7 +507,7 @@ void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
{
QgsTextFormat format;
QFont f = format.font();
f.setFamily( defaultFontString );
QgsFontUtils::setFontFamily( f, defaultFontString );
format.setFont( f );
tableMultiFrame->setContentTextFormat( format );
f.setBold( true );
Expand Down Expand Up @@ -543,13 +544,13 @@ void QgsLayoutGuiUtils::registerGuiForKnownItemTypes( QgsMapCanvas *mapCanvas )
{
QgsTextFormat format = profileItem->plot()->xAxis().textFormat();
QFont f = format.font();
f.setFamily( defaultFontString );
QgsFontUtils::setFontFamily( f, defaultFontString );
format.setFont( f );
profileItem->plot()->xAxis().setTextFormat( format );

format = profileItem->plot()->yAxis().textFormat();
f = format.font();
f.setFamily( defaultFontString );
QgsFontUtils::setFontFamily( f, defaultFontString );
format.setFont( f );
profileItem->plot()->yAxis().setTextFormat( format );
}
Expand Down
6 changes: 3 additions & 3 deletions src/gui/qgsfontbutton.cpp
Expand Up @@ -612,7 +612,7 @@ void QgsFontButton::prepareMenu()
{
QAction *fontAction = new QAction( family, recentFontMenu );
QFont f = fontAction->font();
f.setFamily( family );
QgsFontUtils::setFontFamily( f, family );
fontAction->setFont( f );
fontAction->setToolTip( family );
recentFontMenu->addAction( fontAction );
Expand All @@ -630,7 +630,7 @@ void QgsFontButton::prepareMenu()
{
QgsTextFormat newFormat = mFormat;
QFont f = newFormat.font();
f.setFamily( family );
QgsFontUtils::setFontFamily( f, family );
newFormat.setFont( f );
setTextFormat( newFormat );
QgsFontUtils::addRecentFontFamily( mFormat.font().family() );
Expand All @@ -639,7 +639,7 @@ void QgsFontButton::prepareMenu()
case ModeQFont:
{
QFont font = mFont;
font.setFamily( family );
QgsFontUtils::setFontFamily( font, family );
setCurrentFont( font );
QgsFontUtils::addRecentFontFamily( family );
break;
Expand Down

0 comments on commit 52df647

Please sign in to comment.