23#include <QApplication> 
   26#include <QFontDatabase> 
   34  const QFontInfo fi = QFontInfo( f );
 
   35  return fi.exactMatch();
 
 
   40  const QFont tmpFont = QFont( family );
 
   42  return tmpFont.family().startsWith( family, Qt::CaseInsensitive );
 
 
   47  const QFontDatabase fontDB;
 
   51  if ( fontDB.styles( family ).contains( style ) )
 
   55  QString modified( style );
 
   56  if ( style == 
"Roman" )
 
   58  if ( style == 
"Oblique" )
 
   60  if ( style == 
"Bold Oblique" )
 
   61    modified = 
"Bold Italic";
 
   62  if ( fontDB.styles( family ).contains( modified ) )
 
 
   71  auto styleNameIsMatch = [&font]( 
const QString & candidate ) -> 
bool 
   74    QFont testFont( font.family() );
 
   75    testFont.setStyleName( candidate );
 
   76    return testFont.italic() == font.italic() && testFont.weight() == font.weight();
 
   80  const QFontInfo fontInfo( font );
 
   81  QString styleName = fontInfo.styleName();
 
   82  if ( !styleName.isEmpty() )
 
   84    if ( styleNameIsMatch( styleName ) )
 
   89  styleName = QFontDatabase().styleString( font );
 
   90  if ( !styleName.isEmpty() )
 
   92    if ( styleNameIsMatch( styleName ) )
 
 
  102  const QFontDatabase fontDB;
 
  103  const QStringList fontFamilies = fontDB.families();
 
  106  QList<QString>::const_iterator it = fontFamilies.constBegin();
 
  107  for ( ; it != fontFamilies.constEnd(); ++it )
 
  110    if ( it->startsWith( family, Qt::CaseInsensitive ) )
 
  117        *match = ( *it == family );
 
  133      const QFont f = QFont( family );
 
  134      *chosen = f.family();
 
 
  155  if ( fontstyle.isEmpty() )
 
  160  QFontDatabase fontDB;
 
  161  QString actualFontStyle = fontstyle;
 
  180  if ( actualFontStyle == fontDB.styleString( f ) )
 
  185  const QFont appfont = QApplication::font();
 
  186  const int defaultSize = appfont.pointSize(); 
 
  189  bool foundmatch = 
false;
 
  192  styledfont = fontDB.font( f.family(), actualFontStyle, defaultSize );
 
  193  if ( appfont != styledfont || actualFontStyle != fontDB.styleString( f ) )
 
  200  if ( fallback && !foundmatch )
 
  202    QFont testFont = QFont( f );
 
  203    testFont.setPointSize( defaultSize );
 
  206    const auto constFamily = fontDB.styles( f.family() );
 
  207    for ( 
const QString &style : constFamily )
 
  209      styledfont = fontDB.font( f.family(), style, defaultSize );
 
  210      styledfont = styledfont.resolve( f );
 
  211      if ( testFont.toString() == styledfont.toString() )
 
  221      for ( 
const QString &style : constFamily )
 
  223        styledfont = fontDB.font( f.family(), style, defaultSize );
 
  224        if ( QApplication::font() != styledfont )
 
  239      styledfont.setPointSizeF( f.pointSizeF() );
 
  241    else if ( f.pixelSize() != -1 )
 
  243      styledfont.setPixelSize( f.pixelSize() );
 
  245    styledfont.setCapitalization( f.capitalization() );
 
  246    styledfont.setUnderline( f.underline() );
 
  247    styledfont.setStrikeOut( f.strikeOut() );
 
  248    styledfont.setWordSpacing( f.wordSpacing() );
 
  249    styledfont.setLetterSpacing( QFont::AbsoluteSpacing, f.letterSpacing() );
 
 
  260  return QStringLiteral( 
"QGIS Vera Sans" );
 
 
  266  bool fontsLoaded = 
false;
 
  268  QMap<QString, QString> fontStyles;
 
  269  fontStyles.insert( QStringLiteral( 
"Roman" ), QStringLiteral( 
"QGIS-Vera/QGIS-Vera.ttf" ) );
 
  270  fontStyles.insert( QStringLiteral( 
"Oblique" ), QStringLiteral( 
"QGIS-Vera/QGIS-VeraIt.ttf" ) );
 
  271  fontStyles.insert( QStringLiteral( 
"Bold" ), QStringLiteral( 
"QGIS-Vera/QGIS-VeraBd.ttf" ) );
 
  272  fontStyles.insert( QStringLiteral( 
"Bold Oblique" ), QStringLiteral( 
"QGIS-Vera/QGIS-VeraBI.ttf" ) );
 
  273  fontStyles.insert( QStringLiteral( 
"Deja Bold" ), QStringLiteral( 
"QGIS-DejaVu/QGISDejaVuSans-Bold.ttf" ) );
 
  275  QMap<QString, QString>::const_iterator f = fontStyles.constBegin();
 
  276  for ( ; f != fontStyles.constEnd(); ++f )
 
  278    const QString fontpath( f.value() );
 
  279    if ( !( loadstyles.contains( f.key() ) || loadstyles.contains( QStringLiteral( 
"All" ) ) ) )
 
  284    const QString fontFamily = !f.key().startsWith( QLatin1String( 
"Deja" ) ) ? 
standardTestFontFamily() : QStringLiteral( 
"QGIS DejaVu Sans" );
 
  285    const QString fontstyle  = !f.key().startsWith( QLatin1String( 
"Deja" ) ) ?  f.key() : f.key().mid( 5 );
 
  289      QgsDebugMsgLevel( QStringLiteral( 
"Test font '%1 %2' already available" ).arg( fontFamily, fontstyle ), 2 );
 
  301        const int fontID = QFontDatabase::addApplicationFont( fontPath );
 
  302        loaded = ( fontID != -1 );
 
  303        fontsLoaded = ( fontsLoaded || loaded );
 
  304        QgsDebugMsgLevel( QStringLiteral( 
"Test font '%1 %2' %3 from filesystem [%4]" )
 
  305                          .arg( fontFamily, fontstyle, loaded ? 
"loaded" : 
"FAILED to load", fontPath ), 2 );
 
  306        QgsDebugMsgLevel( QStringLiteral( 
"font families in %1: %2" ).arg( fontID ).arg( QFontDatabase().applicationFontFamilies( fontID ).join( 
"," ) ), 2 );
 
  310        QFile fontResource( 
":/testdata/font/" + fontpath );
 
  311        if ( fontResource.open( QIODevice::ReadOnly ) )
 
  313          const int fontID = QFontDatabase::addApplicationFontFromData( fontResource.readAll() );
 
  314          loaded = ( fontID != -1 );
 
  315          fontsLoaded = ( fontsLoaded || loaded );
 
  317        QgsDebugMsgLevel( QStringLiteral( 
"Test font '%1' (%2) %3 from testdata.qrc" )
 
  318                          .arg( fontFamily, fontstyle, loaded ? 
"loaded" : 
"FAILED to load" ), 2 );
 
 
  328  const QString fontFamily = !style.startsWith( QLatin1String( 
"Deja" ) ) ? 
standardTestFontFamily() : QStringLiteral( 
"QGIS DejaVu Sans" );
 
  329  const QString fontStyle  = !style.startsWith( QLatin1String( 
"Deja" ) ) ?  style : style.mid( 5 );
 
  336  const QFontDatabase fontDB;
 
  337  QFont f = fontDB.font( fontFamily, fontStyle, pointsize );
 
  339  if ( !f.exactMatch() )
 
  342    if ( fontStyle == 
"Roman" )
 
  344    else if ( fontStyle == 
"Oblique" )
 
  346    else if ( fontStyle == 
"Bold Oblique" )
 
  347      modified = 
"Bold Italic";
 
  348    if ( !modified.isEmpty() )
 
  349      f = fontDB.font( fontFamily, modified, pointsize );
 
  351  if ( !f.exactMatch() )
 
  353    QgsDebugMsgLevel( QStringLiteral( 
"Inexact font match - consider installing the %1 font." ).arg( fontFamily ), 2 );
 
  354    QgsDebugMsgLevel( QStringLiteral( 
"Requested: %1" ).arg( f.toString() ), 2 );
 
  356    QgsDebugMsgLevel( QStringLiteral( 
"Replaced:  %1,%2,%3,%4,%5,%6,%7,%8,%9" ).arg( fi.family() ).arg( fi.pointSizeF() ).arg( fi.pixelSize() ).arg( fi.styleHint() ).arg( fi.weight() ).arg( fi.style() ).arg( fi.underline() ).arg( fi.strikeOut() ).arg( fi.fixedPitch() ), 2 );
 
  360  f.setBold( fontStyle.contains( QLatin1String( 
"Bold" ) ) );
 
  361  f.setItalic( fontStyle.contains( QLatin1String( 
"Oblique" ) ) || fontStyle.contains( QLatin1String( 
"Italic" ) ) );
 
 
  368  QDomElement fontElem = document.createElement( elementName );
 
  369  fontElem.setAttribute( QStringLiteral( 
"description" ), font.toString() );
 
  371  fontElem.setAttribute( QStringLiteral( 
"bold" ), font.bold() ? QChar( 
'1' ) : QChar( 
'0' ) );
 
  372  fontElem.setAttribute( QStringLiteral( 
"italic" ), font.italic() ? QChar( 
'1' ) : QChar( 
'0' ) );
 
  373  fontElem.setAttribute( QStringLiteral( 
"underline" ), font.underline() ? QChar( 
'1' ) : QChar( 
'0' ) );
 
  374  fontElem.setAttribute( QStringLiteral( 
"strikethrough" ), font.strikeOut() ? QChar( 
'1' ) : QChar( 
'0' ) );
 
 
  380  if ( element.isNull() )
 
  385  font.fromString( element.attribute( QStringLiteral( 
"description" ) ) );
 
  387  if ( element.hasAttribute( QStringLiteral( 
"bold" ) ) && element.attribute( QStringLiteral( 
"bold" ) ) == QChar( 
'1' ) )
 
  389    font.setBold( 
true );
 
  391  if ( element.hasAttribute( QStringLiteral( 
"italic" ) ) )
 
  393    font.setItalic( element.attribute( QStringLiteral( 
"italic" ) ) == QChar( 
'1' ) );
 
  395  if ( element.hasAttribute( QStringLiteral( 
"underline" ) ) )
 
  397    font.setUnderline( element.attribute( QStringLiteral( 
"underline" ) ) == QChar( 
'1' ) );
 
  399  if ( element.hasAttribute( QStringLiteral( 
"strikethrough" ) ) )
 
  401    font.setStrikeOut( element.attribute( QStringLiteral( 
"strikethrough" ) ) == QChar( 
'1' ) );
 
  404  if ( element.hasAttribute( QStringLiteral( 
"style" ) ) )
 
 
  414  if ( element.isNull() )
 
  419  const QDomNodeList nodeList = element.elementsByTagName( childNode );
 
  420  if ( !nodeList.isEmpty() )
 
  422    const QDomElement fontElem = nodeList.at( 0 ).toElement();
 
 
  433  std::unique_ptr< QMimeData >mimeData( 
new QMimeData );
 
  435  QDomDocument fontDoc;
 
  436  const QDomElement fontElem = 
toXmlElement( font, fontDoc, QStringLiteral( 
"font" ) );
 
  437  fontDoc.appendChild( fontElem );
 
  438  mimeData->setText( fontDoc.toString() );
 
  440  return mimeData.release();
 
 
  452  const QString text = data->text();
 
  453  if ( !text.isEmpty() )
 
  458    if ( doc.setContent( text ) )
 
  460      elem = doc.documentElement();
 
  462      if ( elem.nodeName() != QLatin1String( 
"font" ) )
 
  463        elem = elem.firstChildElement( QStringLiteral( 
"font" ) );
 
 
  476static QMap<QString, QString> createTranslatedStyleMap()
 
  478  QMap<QString, QString> translatedStyleMap;
 
  479  const QStringList words = QStringList()
 
  480                            << QStringLiteral( 
"Normal" )
 
  481                            << QStringLiteral( 
"Regular" )
 
  482                            << QStringLiteral( 
"Light" )
 
  483                            << QStringLiteral( 
"Bold" )
 
  484                            << QStringLiteral( 
"Black" )
 
  485                            << QStringLiteral( 
"Demi" )
 
  486                            << QStringLiteral( 
"Italic" )
 
  487                            << QStringLiteral( 
"Oblique" );
 
  488  const auto constWords = words;
 
  489  for ( 
const QString &word : constWords )
 
  491    translatedStyleMap.insert( QCoreApplication::translate( 
"QFontDatabase", qPrintable( word ) ), word );
 
  493  return translatedStyleMap;
 
  498  QStringList words = namedStyle.split( 
' ', Qt::SkipEmptyParts );
 
  499  for ( 
int i = 0, n = words.length(); i < n; ++i )
 
  501    words[i] = QCoreApplication::translate( 
"QFontDatabase", words[i].toLocal8Bit().constData() );
 
  503  return words.join( QLatin1Char( 
' ' ) );
 
 
  508  static const QMap<QString, QString> translatedStyleMap = createTranslatedStyleMap();
 
  509  QStringList words = namedStyle.split( 
' ', Qt::SkipEmptyParts );
 
  511  for ( 
int i = 0, n = words.length(); i < n; ++i )
 
  513    if ( translatedStyleMap.contains( words[i] ) )
 
  515      words[i] = translatedStyleMap.value( words[i] );
 
  519      QgsDebugMsgLevel( QStringLiteral( 
"Warning: style map does not contain %1" ).arg( words[i] ), 2 );
 
  522  return words.join( QLatin1Char( 
' ' ) );
 
 
  527  QString css = QStringLiteral( 
"font-family: " ) + font.family() + 
';';
 
  530  css += QLatin1String( 
"font-style: " );
 
  531  switch ( font.style() )
 
  533    case QFont::StyleNormal:
 
  534      css += QLatin1String( 
"normal" );
 
  536    case QFont::StyleItalic:
 
  537      css += QLatin1String( 
"italic" );
 
  539    case QFont::StyleOblique:
 
  540      css += QLatin1String( 
"oblique" );
 
  547  switch ( font.weight() )
 
  555    case QFont::DemiBold:
 
  567    case QFont::ExtraLight:
 
  573    case QFont::ExtraBold:
 
  577  css += QStringLiteral( 
"font-weight: %1;" ).arg( cssWeight );
 
  580  css += QStringLiteral( 
"font-size: %1px;" ).arg( font.pointSizeF() >= 0 ? font.pointSizeF() * pointToPixelScale : font.pixelSize() );
 
 
  587  if ( family.isEmpty() )
 
  593  QStringList recentFamilies = settings.
value( QStringLiteral( 
"fonts/recent" ) ).toStringList();
 
  596  recentFamilies.removeAll( family );
 
  599  recentFamilies.prepend( family );
 
  602  recentFamilies = recentFamilies.mid( 0, 10 );
 
  604  settings.
setValue( QStringLiteral( 
"fonts/recent" ), recentFamilies );
 
 
  610  return settings.
value( QStringLiteral( 
"fonts/recent" ) ).toStringList();
 
 
  615  font.setFamily( family );
 
  616  if ( !font.exactMatch() )
 
  621    font.setFamilies( { family } );
 
 
  627  QFont font( family, pointSize, weight, italic );
 
  628  if ( !font.exactMatch() )
 
  633    font.setFamilies( { family } );
 
 
static QString buildSourcePath()
Returns path to the source directory. Valid only when running from build directory.
 
static bool isRunningFromBuildDir()
Indicates whether running from build directory (not installed)
 
static QString resolveFontStyleName(const QFont &font)
Attempts to resolve the style name corresponding to the specified font object.
 
static QString asCSS(const QFont &font, double pointToPixelMultiplier=1.0)
Returns a CSS string representing the specified font as closely as possible.
 
static QString translateNamedStyle(const QString &namedStyle)
Returns the localized named style of a font, if such a translation is available.
 
static QString untranslateNamedStyle(const QString &namedStyle)
Returns the english named style of a font, if possible.
 
static bool setFromXmlElement(QFont &font, const QDomElement &element)
Sets the properties of a font to match the properties stored in an XML element.
 
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
 
static QFont createFont(const QString &family, int pointSize=-1, int weight=-1, bool italic=false)
Creates a font with the specified family.
 
static QMimeData * toMimeData(const QFont &font)
Returns new mime data representing the specified font settings.
 
static bool fontFamilyMatchOnSystem(const QString &family, QString *chosen=nullptr, bool *match=nullptr)
Check whether font family is on system.
 
static bool fontFamilyOnSystem(const QString &family)
Check whether font family is on system in a quick manner, which does not compare [foundry].
 
static bool updateFontViaStyle(QFont &f, const QString &fontstyle, bool fallback=false)
Updates font with named style and retain all font properties.
 
static bool fontMatchOnSystem(const QFont &f)
Check whether exact font is on system.
 
static bool loadStandardTestFonts(const QStringList &loadstyles)
Loads standard test fonts from filesystem or qrc resource.
 
static QFont getStandardTestFont(const QString &style="Roman", int pointsize=12)
Gets standard test font with specific style.
 
static void setFontFamily(QFont &font, const QString &family)
Sets the family for a font object.
 
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
 
static void addRecentFontFamily(const QString &family)
Adds a font family to the list of recently used font families.
 
static QString standardTestFontFamily()
Gets standard test font family.
 
static QFont fromMimeData(const QMimeData *data, bool *ok=nullptr)
Attempts to parse the provided mime data as a QFont.
 
static bool fontFamilyHasStyle(const QString &family, const QString &style)
Check whether font family on system has specific style.
 
static QStringList recentFontFamilies()
Returns a list of recently used font families.
 
Stores settings for use within QGIS.
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
 
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
 
#define QgsDebugMsgLevel(str, level)