Add a workaround for setting QFont objects to font families with

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.
This commit is contained in:
Nyall Dawson 2023-09-28 09:14:03 +10:00
parent 575f726355
commit 52df64779c
24 changed files with 112 additions and 41 deletions

View File

@ -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
};

View File

@ -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() );
}

View File

@ -34,7 +34,7 @@
#include "qgsnewauxiliarylayerdialog.h"
#include "qgsadvanceddigitizingdockwidget.h"
#include "qgssettingsentryimpl.h"
#include "qgsfontutils.h"
#include <QMouseEvent>
@ -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

View File

@ -25,6 +25,7 @@
#include "qgshelp.h"
#include "qgsfillsymbol.h"
#include "qgssettingsentryimpl.h"
#include "qgsfontutils.h"
#include <QColorDialog>
#include <QGraphicsScene>
@ -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() )

View File

@ -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 );
@ -3301,7 +3301,7 @@ void QgsPalLayerSettings::parseTextStyle( QFont &labelFont,
}
else
{
newFont = QFont( ddFontFamily );
newFont = QgsFontUtils::createFont( ddFontFamily );
newFontBuilt = true;
}
}

View File

@ -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

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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 );

View File

@ -24,6 +24,7 @@
#include "qgstextrenderer.h"
#include "qgsmarkersymbol.h"
#include "qgslinesymbol.h"
#include "qgsfontutils.h"
QgsDataDefinedSizeLegend::QgsDataDefinedSizeLegend()
{
@ -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() ) );

View File

@ -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;
}

View File

@ -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

View File

@ -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 ) );
@ -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 ) )
{

View File

@ -15,6 +15,7 @@
#include "qgstextcharacterformat.h"
#include "qgsrendercontext.h"
#include "qgsfontutils.h"
#include <QTextCharFormat>
@ -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 ) );

View File

@ -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() );
@ -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()
@ -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 );
@ -989,7 +989,7 @@ void QgsTextFormat::updateDataDefinedProperties( QgsRenderContext &context )
}
else
{
newFont = QFont( ddFontFamily );
newFont = QgsFontUtils::createFont( ddFontFamily );
newFontBuilt = true;
}
}

View File

@ -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;
@ -1340,7 +1340,7 @@ 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;
@ -1348,7 +1348,7 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,
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;

View File

@ -22,6 +22,7 @@
#include "qgscodeeditorcolorschemeregistry.h"
#include "qgscodeeditorhistorydialog.h"
#include "qgsstringutils.h"
#include "qgsfontutils.h"
#include <QLabel>
#include <QWidget>
@ -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 )
@ -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();

View File

@ -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,
@ -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 );
@ -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 );
@ -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 );
@ -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 );
}

View File

@ -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 );
@ -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() );
@ -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;

View File

@ -15,6 +15,8 @@
***************************************************************************/
#include "qgsformlabelformatwidget.h"
#include "qgsguiutils.h"
#include "qgsfontutils.h"
#include <QGroupBox>
/// @cond private
@ -73,7 +75,7 @@ QgsAttributeEditorElement::LabelStyle QgsFormLabelFormatWidget::labelStyle() con
QgsAttributeEditorElement::LabelStyle style;
style.color = btnTextColor->color();
QFont currentFont;
currentFont.setFamily( mFontFamilyCmbBx->currentFont().family() );
QgsFontUtils::setFontFamily( currentFont, mFontFamilyCmbBx->currentFont().family() );
currentFont.setBold( mFontBoldBtn->isChecked() );
currentFont.setItalic( mFontItalicBtn->isChecked() );
currentFont.setUnderline( mFontUnderlineBtn->isChecked() );

View File

@ -1493,7 +1493,7 @@ void QgsTextFormatWidget::populateFontStyleComboBox()
QString targetStyle = mFontDB.styleString( mRefFont );
if ( !styles.contains( targetStyle ) )
{
const QFont f = QFont( mRefFont.family() );
const QFont f = QgsFontUtils::createFont( mRefFont.family() );
targetStyle = QFontInfo( f ).styleName();
mRefFont.setStyleName( targetStyle );
}
@ -1515,7 +1515,7 @@ void QgsTextFormatWidget::mFontSizeSpinBox_valueChanged( double d )
void QgsTextFormatWidget::mFontFamilyCmbBx_currentFontChanged( const QFont &f )
{
mRefFont.setFamily( f.family() );
QgsFontUtils::setFontFamily( mRefFont, f.family() );
updateFont( mRefFont );
}

View File

@ -45,6 +45,7 @@
#include "characterwidget.h"
#include "qgsapplication.h"
#include "qgsfontutils.h"
#include <QFontDatabase>
#include <QMouseEvent>
@ -65,7 +66,7 @@ CharacterWidget::CharacterWidget( QWidget *parent )
void CharacterWidget::setFont( const QFont &font )
{
mDisplayFont.setFamily( font.family() );
QgsFontUtils::setFontFamily( mDisplayFont, font.family() );
mSquareSize = std::max( 34, QFontMetrics( mDisplayFont ).xHeight() * 3 );
adjustSize();
update();

View File

@ -3590,7 +3590,7 @@ void QgsFontMarkerSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
// layer type is correct, we can do the cast
mLayer = static_cast<QgsFontMarkerSymbolLayer *>( layer );
mRefFont.setFamily( mLayer->fontFamily() );
QgsFontUtils::setFontFamily( mRefFont, mLayer->fontFamily() );
mRefFont.setStyleName( QgsFontUtils::translateNamedStyle( mLayer->fontStyle() ) );
mFontStyleComboBox->blockSignals( true );
@ -3666,7 +3666,7 @@ void QgsFontMarkerSymbolLayerWidget::setFontFamily( const QFont &font )
if ( mLayer )
{
mLayer->setFontFamily( font.family() );
mRefFont.setFamily( font.family() );
QgsFontUtils::setFontFamily( mRefFont, font.family() );
widgetChar->setFont( mRefFont );
mCharPreview->setFont( mRefFont );
populateFontStyleComboBox();
@ -3815,7 +3815,7 @@ void QgsFontMarkerSymbolLayerWidget::populateFontStyleComboBox()
QString targetStyle = mFontDB.styleString( mRefFont );
if ( !styles.contains( targetStyle ) )
{
const QFont f = QFont( mRefFont.family() );
const QFont f = QgsFontUtils::createFont( mRefFont.family() );
targetStyle = QFontInfo( f ).styleName();
mRefFont.setStyleName( targetStyle );
}

View File

@ -20,6 +20,8 @@
#include "qgsmaplayerserverproperties.h"
#include "qgsmessagelog.h"
#include "qgswmsserviceexception.h"
#include "qgsfontutils.h"
#include <QRegularExpression>
const QString EXTERNAL_LAYER_PREFIX = QStringLiteral( "EXTERNAL_WMS:" );
@ -1264,7 +1266,7 @@ namespace QgsWms
font.setPointSizeF( layerFontSizeAsDouble() );
if ( !layerFontFamily().isEmpty() )
font.setFamily( layerFontFamily() );
QgsFontUtils::setFontFamily( font, layerFontFamily() );
return font;
}
@ -1281,7 +1283,7 @@ namespace QgsWms
font.setPointSizeF( itemFontSizeAsDouble() );
if ( !itemFontFamily().isEmpty() )
font.setFamily( itemFontFamily() );
QgsFontUtils::setFontFamily( font, itemFontFamily() );
return font;
}