File indexing completed on 2025-01-12 05:02:06
0001 /* 0002 SPDX-FileCopyrightText: 2003-2007 Craig Drummond <craig@kde.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "Fc.h" 0007 #include <QHash> 0008 #include <QTextStream> 0009 #include <QUrlQuery> 0010 // 0011 // KDE font chooser always seems to use Italic - for both Oblique, and Italic. So I guess 0012 // the fonts:/ should do too - so as to appear more unified. 0013 // 0014 // ditto with respect to Medium/Regular 0015 #define KFI_HAVE_OBLIQUE // Do we differentiate between Italic and Oblique when comparing slants? 0016 #define KFI_DISPLAY_OBLIQUE // Do we want to list "Oblique"? Or always use Italic? 0017 #define KFI_HAVE_MEDIUM_WEIGHT // Do we differentiate between Medium and Regular weights when comparing weights? 0018 #define KFI_DISPLAY_MEDIUM // Do we want to list "Medium"? Or always use Regular? 0019 0020 namespace KFI 0021 { 0022 namespace FC 0023 { 0024 #define FC_PROTOCOL QString::fromLatin1("fontconfig") 0025 #define FC_STYLE_QUERY QString::fromLatin1("style") 0026 #define FC_FILE_QUERY QString::fromLatin1("file") 0027 #define FC_INDEX_QUERY QString::fromLatin1("index") 0028 0029 QUrl encode(const QString &name, quint32 style, const QString &file, int index) 0030 { 0031 QUrl url(QUrl::fromLocalFile(name)); 0032 QUrlQuery query; 0033 0034 url.setScheme(FC_PROTOCOL); 0035 query.addQueryItem(FC_STYLE_QUERY, QString::number(style)); 0036 if (!file.isEmpty()) { 0037 query.addQueryItem(FC_FILE_QUERY, file); 0038 } 0039 if (index > 0) { 0040 query.addQueryItem(FC_INDEX_QUERY, QString::number(index)); 0041 } 0042 0043 url.setQuery(query); 0044 return url; 0045 } 0046 0047 Misc::TFont decode(const QUrl &url) 0048 { 0049 QUrlQuery query(url); 0050 return FC_PROTOCOL == url.scheme() ? Misc::TFont(url.path(), query.queryItemValue(FC_STYLE_QUERY).toUInt()) : Misc::TFont(QString(), 0); 0051 } 0052 0053 QString getFile(const QUrl &url) 0054 { 0055 QUrlQuery query(url); 0056 return FC_PROTOCOL == url.scheme() ? query.queryItemValue(FC_FILE_QUERY) : QString(); 0057 } 0058 0059 int getIndex(const QUrl &url) 0060 { 0061 QUrlQuery query(url); 0062 return FC_PROTOCOL == url.scheme() ? query.queryItemValue(FC_INDEX_QUERY).toInt() : 0; 0063 } 0064 0065 int weight(int w) 0066 { 0067 if (KFI_NULL_SETTING == w) { 0068 #ifdef KFI_HAVE_MEDIUM_WEIGHT 0069 return FC_WEIGHT_MEDIUM; 0070 } 0071 #else 0072 return FC_WEIGHT_REGULAR; 0073 #endif 0074 0075 if (w < FC_WEIGHT_EXTRALIGHT) { 0076 return FC_WEIGHT_THIN; 0077 } 0078 0079 if (w < (FC_WEIGHT_EXTRALIGHT + FC_WEIGHT_LIGHT) / 2) { 0080 return FC_WEIGHT_EXTRALIGHT; 0081 } 0082 0083 if (w < (FC_WEIGHT_LIGHT + FC_WEIGHT_REGULAR) / 2) { 0084 return FC_WEIGHT_LIGHT; 0085 } 0086 0087 #ifdef KFI_HAVE_MEDIUM_WEIGHT 0088 if (w < (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2) { 0089 return FC_WEIGHT_REGULAR; 0090 } 0091 0092 if (w < (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) { 0093 return FC_WEIGHT_MEDIUM; 0094 } 0095 #else 0096 if (w < (FC_WEIGHT_REGULAR + FC_WEIGHT_DEMIBOLD) / 2) 0097 return FC_WEIGHT_REGULAR; 0098 #endif 0099 0100 if (w < (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) { 0101 return FC_WEIGHT_DEMIBOLD; 0102 } 0103 0104 if (w < (FC_WEIGHT_BOLD + FC_WEIGHT_EXTRABOLD) / 2) { 0105 return FC_WEIGHT_BOLD; 0106 } 0107 0108 if (w < (FC_WEIGHT_EXTRABOLD + FC_WEIGHT_BLACK) / 2) { 0109 return FC_WEIGHT_EXTRABOLD; 0110 } 0111 0112 return FC_WEIGHT_BLACK; 0113 } 0114 0115 int width(int w) 0116 { 0117 if (KFI_NULL_SETTING == w) { 0118 return KFI_FC_WIDTH_NORMAL; 0119 } 0120 0121 if (w < KFI_FC_WIDTH_EXTRACONDENSED) { 0122 return KFI_FC_WIDTH_EXTRACONDENSED; 0123 } 0124 0125 if (w < (KFI_FC_WIDTH_EXTRACONDENSED + KFI_FC_WIDTH_CONDENSED) / 2) { 0126 return KFI_FC_WIDTH_EXTRACONDENSED; 0127 } 0128 0129 if (w < (KFI_FC_WIDTH_CONDENSED + KFI_FC_WIDTH_SEMICONDENSED) / 2) { 0130 return KFI_FC_WIDTH_CONDENSED; 0131 } 0132 0133 if (w < (KFI_FC_WIDTH_SEMICONDENSED + KFI_FC_WIDTH_NORMAL) / 2) { 0134 return KFI_FC_WIDTH_SEMICONDENSED; 0135 } 0136 0137 if (w < (KFI_FC_WIDTH_NORMAL + KFI_FC_WIDTH_SEMIEXPANDED) / 2) { 0138 return KFI_FC_WIDTH_NORMAL; 0139 } 0140 0141 if (w < (KFI_FC_WIDTH_SEMIEXPANDED + KFI_FC_WIDTH_EXPANDED) / 2) { 0142 return KFI_FC_WIDTH_SEMIEXPANDED; 0143 } 0144 0145 if (w < (KFI_FC_WIDTH_EXPANDED + KFI_FC_WIDTH_EXTRAEXPANDED) / 2) { 0146 return KFI_FC_WIDTH_EXPANDED; 0147 } 0148 0149 if (w < (KFI_FC_WIDTH_EXTRAEXPANDED + KFI_FC_WIDTH_ULTRAEXPANDED) / 2) { 0150 return KFI_FC_WIDTH_EXTRAEXPANDED; 0151 } 0152 0153 return KFI_FC_WIDTH_ULTRAEXPANDED; 0154 } 0155 0156 int slant(int s) 0157 { 0158 if (KFI_NULL_SETTING == s || s < FC_SLANT_ITALIC) { 0159 return FC_SLANT_ROMAN; 0160 } 0161 0162 #ifdef KFI_HAVE_OBLIQUE 0163 if (s < (FC_SLANT_ITALIC + FC_SLANT_OBLIQUE) / 2) { 0164 return FC_SLANT_ITALIC; 0165 } 0166 0167 return FC_SLANT_OBLIQUE; 0168 #else 0169 return FC_SLANT_ITALIC; 0170 #endif 0171 } 0172 0173 int spacing(int s) 0174 { 0175 if (s < FC_MONO) { 0176 return FC_PROPORTIONAL; 0177 } 0178 0179 if (s < (FC_MONO + FC_CHARCELL) / 2) { 0180 return FC_MONO; 0181 } 0182 0183 return FC_CHARCELL; 0184 } 0185 0186 int strToWeight(const QString &str, QString &newStr) 0187 { 0188 if (0 == str.indexOf(KFI_WEIGHT_THIN.toString(), 0, Qt::CaseInsensitive)) { 0189 newStr = str.mid(KFI_WEIGHT_THIN.toString().length()); 0190 return FC_WEIGHT_THIN; 0191 } 0192 if (0 == str.indexOf(KFI_WEIGHT_EXTRALIGHT.toString(), 0, Qt::CaseInsensitive)) { 0193 newStr = str.mid(KFI_WEIGHT_EXTRALIGHT.toString().length()); 0194 return FC_WEIGHT_EXTRALIGHT; 0195 } 0196 // if(0==str.indexOf(i18n(KFI_WEIGHT_ULTRALIGHT), 0, Qt::CaseInsensitive)) 0197 //{ 0198 // newStr=str.mid(i18n(KFI_WEIGHT_ULTRALIGHT).length()); 0199 // return FC_WEIGHT_ULTRALIGHT; 0200 //} 0201 if (0 == str.indexOf(KFI_WEIGHT_LIGHT.toString(), 0, Qt::CaseInsensitive)) { 0202 newStr = str.mid(KFI_WEIGHT_LIGHT.toString().length()); 0203 return FC_WEIGHT_LIGHT; 0204 } 0205 if (0 == str.indexOf(KFI_WEIGHT_REGULAR.toString(), 0, Qt::CaseInsensitive)) { 0206 newStr = str.mid(KFI_WEIGHT_REGULAR.toString().length()); 0207 return FC_WEIGHT_REGULAR; 0208 } 0209 // if(0==str.indexOf(i18n(KFI_WEIGHT_NORMAL), 0, Qt::CaseInsensitive)) 0210 //{ 0211 // newStr=str.mid(i18n(KFI_WEIGHT_NORMAL).length()); 0212 // return FC_WEIGHT_NORMAL; 0213 //} 0214 if (0 == str.indexOf(KFI_WEIGHT_MEDIUM.toString(), 0, Qt::CaseInsensitive)) { 0215 newStr = str.mid(KFI_WEIGHT_MEDIUM.toString().length()); 0216 return FC_WEIGHT_MEDIUM; 0217 } 0218 if (0 == str.indexOf(KFI_WEIGHT_DEMIBOLD.toString(), 0, Qt::CaseInsensitive)) { 0219 newStr = str.mid(KFI_WEIGHT_DEMIBOLD.toString().length()); 0220 return FC_WEIGHT_DEMIBOLD; 0221 } 0222 // if(0==str.indexOf(i18n(KFI_WEIGHT_SEMIBOLD), 0, Qt::CaseInsensitive)) 0223 //{ 0224 // newStr=str.mid(i18n(KFI_WEIGHT_SEMIBOLD).length()); 0225 // return FC_WEIGHT_SEMIBOLD; 0226 //} 0227 if (0 == str.indexOf(KFI_WEIGHT_BOLD.toString(), 0, Qt::CaseInsensitive)) { 0228 newStr = str.mid(KFI_WEIGHT_BOLD.toString().length()); 0229 return FC_WEIGHT_BOLD; 0230 } 0231 if (0 == str.indexOf(KFI_WEIGHT_EXTRABOLD.toString(), 0, Qt::CaseInsensitive)) { 0232 newStr = str.mid(KFI_WEIGHT_EXTRABOLD.toString().length()); 0233 return FC_WEIGHT_EXTRABOLD; 0234 } 0235 // if(0==str.indexOf(i18n(KFI_WEIGHT_ULTRABOLD), 0, Qt::CaseInsensitive)) 0236 //{ 0237 // newStr=str.mid(i18n(KFI_WEIGHT_ULTRABOLD).length()); 0238 // return FC_WEIGHT_ULTRABOLD; 0239 //} 0240 if (0 == str.indexOf(KFI_WEIGHT_BLACK.toString(), 0, Qt::CaseInsensitive)) { 0241 newStr = str.mid(KFI_WEIGHT_BLACK.toString().length()); 0242 return FC_WEIGHT_BLACK; 0243 } 0244 if (0 == str.indexOf(KFI_WEIGHT_BLACK.toString(), 0, Qt::CaseInsensitive)) { 0245 newStr = str.mid(KFI_WEIGHT_BLACK.toString().length()); 0246 return FC_WEIGHT_BLACK; 0247 } 0248 0249 newStr = str; 0250 return FC_WEIGHT_REGULAR; 0251 } 0252 0253 int strToWidth(const QString &str, QString &newStr) 0254 { 0255 if (0 == str.indexOf(KFI_WIDTH_ULTRACONDENSED.toString(), 0, Qt::CaseInsensitive)) { 0256 newStr = str.mid(KFI_WIDTH_ULTRACONDENSED.toString().length()); 0257 return KFI_FC_WIDTH_ULTRACONDENSED; 0258 } 0259 if (0 == str.indexOf(KFI_WIDTH_EXTRACONDENSED.toString(), 0, Qt::CaseInsensitive)) { 0260 newStr = str.mid(KFI_WIDTH_EXTRACONDENSED.toString().length()); 0261 return KFI_FC_WIDTH_EXTRACONDENSED; 0262 } 0263 if (0 == str.indexOf(KFI_WIDTH_CONDENSED.toString(), 0, Qt::CaseInsensitive)) { 0264 newStr = str.mid(KFI_WIDTH_CONDENSED.toString().length()); 0265 return KFI_FC_WIDTH_CONDENSED; 0266 } 0267 if (0 == str.indexOf(KFI_WIDTH_SEMICONDENSED.toString(), 0, Qt::CaseInsensitive)) { 0268 newStr = str.mid(KFI_WIDTH_SEMICONDENSED.toString().length()); 0269 return KFI_FC_WIDTH_SEMICONDENSED; 0270 } 0271 if (0 == str.indexOf(KFI_WIDTH_NORMAL.toString(), 0, Qt::CaseInsensitive)) { 0272 newStr = str.mid(KFI_WIDTH_NORMAL.toString().length()); 0273 return KFI_FC_WIDTH_NORMAL; 0274 } 0275 if (0 == str.indexOf(KFI_WIDTH_SEMIEXPANDED.toString(), 0, Qt::CaseInsensitive)) { 0276 newStr = str.mid(KFI_WIDTH_SEMIEXPANDED.toString().length()); 0277 return KFI_FC_WIDTH_SEMIEXPANDED; 0278 } 0279 if (0 == str.indexOf(KFI_WIDTH_EXPANDED.toString(), 0, Qt::CaseInsensitive)) { 0280 newStr = str.mid(KFI_WIDTH_EXPANDED.toString().length()); 0281 return KFI_FC_WIDTH_EXPANDED; 0282 } 0283 if (0 == str.indexOf(KFI_WIDTH_EXTRAEXPANDED.toString(), 0, Qt::CaseInsensitive)) { 0284 newStr = str.mid(KFI_WIDTH_EXTRAEXPANDED.toString().length()); 0285 return KFI_FC_WIDTH_EXTRAEXPANDED; 0286 } 0287 if (0 == str.indexOf(KFI_WIDTH_ULTRAEXPANDED.toString(), 0, Qt::CaseInsensitive)) { 0288 newStr = str.mid(KFI_WIDTH_ULTRAEXPANDED.toString().length()); 0289 return KFI_FC_WIDTH_ULTRAEXPANDED; 0290 } 0291 0292 newStr = str; 0293 return KFI_FC_WIDTH_NORMAL; 0294 } 0295 0296 int strToSlant(const QString &str) 0297 { 0298 if (-1 != str.indexOf(KFI_SLANT_ITALIC.toString())) { 0299 return FC_SLANT_ITALIC; 0300 } 0301 if (-1 != str.indexOf(KFI_SLANT_OBLIQUE.toString())) { 0302 return FC_SLANT_OBLIQUE; 0303 } 0304 return FC_SLANT_ROMAN; 0305 } 0306 0307 quint32 createStyleVal(const QString &name) 0308 { 0309 int pos; 0310 0311 if (-1 == (pos = name.indexOf(", "))) { // No style information... 0312 return createStyleVal(FC_WEIGHT_REGULAR, 0313 #ifdef KFI_FC_NO_WIDTHS 0314 KFI_NULL_SETTING 0315 #else 0316 KFI_FC_WIDTH_NORMAL 0317 #endif 0318 , 0319 FC_SLANT_ROMAN); 0320 } else { 0321 QString style(name.mid(pos + 2)); 0322 0323 return createStyleVal(strToWeight(style, style), 0324 #ifdef KFI_FC_NO_WIDTHS 0325 KFI_NULL_SETTING 0326 #else 0327 strToWidth(style, style) 0328 #endif 0329 , 0330 strToSlant(style)); 0331 } 0332 } 0333 0334 QString styleValToStr(quint32 style) 0335 { 0336 return QStringLiteral("0X%1\n").arg(style, 6, 16, QLatin1Char('0')).toUpper(); 0337 } 0338 0339 void decomposeStyleVal(quint32 styleInfo, int &weight, int &width, int &slant) 0340 { 0341 weight = (styleInfo & 0xFF0000) >> 16; 0342 width = (styleInfo & 0x00FF00) >> 8; 0343 slant = (styleInfo & 0x0000FF); 0344 } 0345 0346 quint32 styleValFromStr(const QString &style) 0347 { 0348 if (style.isEmpty()) { 0349 return KFI_NO_STYLE_INFO; 0350 } else { 0351 quint32 val; 0352 0353 QTextStream(const_cast<QString *>(&style), QIODevice::ReadOnly) >> val; 0354 return val; 0355 } 0356 } 0357 0358 QString getFcString(FcPattern *pat, const char *val, int index) 0359 { 0360 QString rv; 0361 FcChar8 *fcStr; 0362 0363 if (FcResultMatch == FcPatternGetString(pat, val, index, &fcStr)) { 0364 rv = QString::fromUtf8((char *)fcStr); 0365 } 0366 0367 return rv; 0368 } 0369 0370 // 0371 // TODO: How correct is this? 0372 // Qt/Gtk seem to prefer font family names with FAMILY_LANG=="en" 0373 // ...so if possible, use that. Else, use the first non "xx" lang. 0374 QString getFcLangString(FcPattern *pat, const char *val, const char *valLang) 0375 { 0376 int langIndex = -1; 0377 0378 for (int i = 0; true; ++i) { 0379 QString lang = getFcString(pat, valLang, i); 0380 0381 if (lang.isEmpty()) { 0382 break; 0383 } else if (QString::fromLatin1("en") == lang) { 0384 return getFcString(pat, val, i); 0385 } else if (QString::fromLatin1("xx") != lang && -1 == langIndex) { 0386 langIndex = i; 0387 } 0388 } 0389 0390 return getFcString(pat, val, langIndex > 0 ? langIndex : 0); 0391 } 0392 0393 int getFcInt(FcPattern *pat, const char *val, int index, int def) 0394 { 0395 int rv; 0396 0397 if (FcResultMatch == FcPatternGetInteger(pat, val, index, &rv)) { 0398 return rv; 0399 } 0400 return def; 0401 } 0402 0403 QString getName(const QString &file) 0404 { 0405 int count = 0; 0406 FcPattern *pat = FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(file).constData()), 0, nullptr, &count); 0407 QString name(i18n("Unknown")); 0408 0409 if (pat) { 0410 name = FC::createName(pat); 0411 FcPatternDestroy(pat); 0412 } 0413 0414 return name; 0415 } 0416 0417 void getDetails(FcPattern *pat, QString &family, quint32 &styleVal, int &index, QString &foundry) 0418 { 0419 int weight = getFcInt(pat, FC_WEIGHT, 0, KFI_NULL_SETTING), 0420 width = 0421 #ifdef KFI_FC_NO_WIDTHS 0422 KFI_NULL_SETTING, 0423 #else 0424 getFcInt(pat, FC_WIDTH, 0, KFI_NULL_SETTING), 0425 #endif 0426 slant = getFcInt(pat, FC_SLANT, 0, KFI_NULL_SETTING); 0427 0428 index = getFcInt(pat, FC_INDEX, 0, 0); 0429 // #ifdef KFI_USE_TRANSLATED_FAMILY_NAME 0430 family = getFcLangString(pat, FC_FAMILY, FC_FAMILYLANG); 0431 // #else 0432 // family=getFcString(pat, FC_FAMILY, 0); 0433 // #endif 0434 styleVal = createStyleVal(weight, width, slant); 0435 foundry = getFcString(pat, FC_FOUNDRY, 0); 0436 } 0437 0438 QString createName(FcPattern *pat) 0439 { 0440 QString family, foundry; 0441 quint32 styleVal; 0442 int index; 0443 0444 getDetails(pat, family, styleVal, index, foundry); 0445 return createName(family, styleVal); 0446 } 0447 0448 QString createName(const QString &family, quint32 styleInfo) 0449 { 0450 int weight, width, slant; 0451 0452 decomposeStyleVal(styleInfo, weight, width, slant); 0453 return createName(family, weight, width, slant); 0454 } 0455 0456 QString createName(const QString &family, int weight, int width, int slant) 0457 { 0458 return family + QString::fromLatin1(", ") + createStyleName(weight, width, slant); 0459 } 0460 0461 QString createStyleName(quint32 styleInfo) 0462 { 0463 int weight, width, slant; 0464 0465 decomposeStyleVal(styleInfo, weight, width, slant); 0466 return createStyleName(weight, width, slant); 0467 } 0468 0469 QString createStyleName(int weight, int width, int slant) 0470 { 0471 // 0472 // CPD: TODO: the names *need* to match up with kfontchooser's... 0473 // : Removing KFI_DISPLAY_OBLIQUE and KFI_DISPLAY_MEDIUM help this. 0474 // However, I have at least one bad font: 0475 // Rockwell Extra Bold. Both fontconfig, and kcmshell fonts list family 0476 // as "Rockwell Extra Bold" -- good (well at least they match). *But* fontconfig 0477 // is returning the weight "Extra Bold", and kcmshell fonts is using "Bold" :-( 0478 // 0479 QString name, weightString, widthString, slantString; 0480 0481 #ifndef KFI_FC_NO_WIDTHS 0482 if (KFI_NULL_SETTING != width) { 0483 widthString = widthStr(width); 0484 } 0485 #endif 0486 0487 if (KFI_NULL_SETTING != slant) { 0488 slantString = slantStr(slant); 0489 } 0490 0491 // 0492 // If weight is "Regular", we only want to display it if slant and width are empty. 0493 if (KFI_NULL_SETTING != weight) { 0494 weightString = weightStr(weight, !slantString.isEmpty() || !widthString.isEmpty()); 0495 0496 if (!weightString.isEmpty()) { 0497 name = weightString; 0498 } 0499 } 0500 0501 #ifndef KFI_FC_NO_WIDTHS 0502 if (!widthString.isEmpty()) { 0503 if (!name.isEmpty()) { 0504 name += QChar(' '); 0505 } 0506 name += widthString; 0507 } 0508 #endif 0509 0510 if (!slantString.isEmpty()) { 0511 if (!name.isEmpty()) { 0512 name += QChar(' '); 0513 } 0514 name += slantString; 0515 } 0516 return name; 0517 } 0518 0519 QString weightStr(int w, bool emptyNormal) 0520 { 0521 switch (weight(w)) { 0522 case FC_WEIGHT_THIN: 0523 return KFI_WEIGHT_THIN.toString(); 0524 case FC_WEIGHT_EXTRALIGHT: 0525 return KFI_WEIGHT_EXTRALIGHT.toString(); 0526 case FC_WEIGHT_LIGHT: 0527 return KFI_WEIGHT_LIGHT.toString(); 0528 case FC_WEIGHT_MEDIUM: 0529 #ifdef KFI_DISPLAY_MEDIUM 0530 return KFI_WEIGHT_MEDIUM.toString(); 0531 #endif 0532 case FC_WEIGHT_REGULAR: 0533 return emptyNormal ? QString() : KFI_WEIGHT_REGULAR.toString(); 0534 case FC_WEIGHT_DEMIBOLD: 0535 return KFI_WEIGHT_DEMIBOLD.toString(); 0536 case FC_WEIGHT_BOLD: 0537 return KFI_WEIGHT_BOLD.toString(); 0538 case FC_WEIGHT_EXTRABOLD: 0539 return KFI_WEIGHT_EXTRABOLD.toString(); 0540 default: 0541 return KFI_WEIGHT_BLACK.toString(); 0542 } 0543 } 0544 0545 QString widthStr(int w, bool emptyNormal) 0546 { 0547 switch (width(w)) { 0548 case KFI_FC_WIDTH_ULTRACONDENSED: 0549 return KFI_WIDTH_ULTRACONDENSED.toString(); 0550 case KFI_FC_WIDTH_EXTRACONDENSED: 0551 return KFI_WIDTH_EXTRACONDENSED.toString(); 0552 case KFI_FC_WIDTH_CONDENSED: 0553 return KFI_WIDTH_CONDENSED.toString(); 0554 case KFI_FC_WIDTH_SEMICONDENSED: 0555 return KFI_WIDTH_SEMICONDENSED.toString(); 0556 case KFI_FC_WIDTH_NORMAL: 0557 return emptyNormal ? QString() : KFI_WIDTH_NORMAL.toString(); 0558 case KFI_FC_WIDTH_SEMIEXPANDED: 0559 return KFI_WIDTH_SEMIEXPANDED.toString(); 0560 case KFI_FC_WIDTH_EXPANDED: 0561 return KFI_WIDTH_EXPANDED.toString(); 0562 case KFI_FC_WIDTH_EXTRAEXPANDED: 0563 return KFI_WIDTH_EXTRAEXPANDED.toString(); 0564 default: 0565 return KFI_WIDTH_ULTRAEXPANDED.toString(); 0566 } 0567 } 0568 0569 QString slantStr(int s, bool emptyNormal) 0570 { 0571 switch (slant(s)) { 0572 case FC_SLANT_OBLIQUE: 0573 #ifdef KFI_DISPLAY_OBLIQUE 0574 return KFI_SLANT_OBLIQUE.toString(); 0575 #endif 0576 case FC_SLANT_ITALIC: 0577 return KFI_SLANT_ITALIC.toString(); 0578 default: 0579 return emptyNormal ? QString() : KFI_SLANT_ROMAN.toString(); 0580 } 0581 } 0582 0583 QString spacingStr(int s) 0584 { 0585 switch (spacing(s)) { 0586 case FC_MONO: 0587 return KFI_SPACING_MONO.toString(); 0588 case FC_CHARCELL: 0589 return KFI_SPACING_CHARCELL.toString(); 0590 default: 0591 return KFI_SPACING_PROPORTIONAL.toString(); 0592 } 0593 } 0594 0595 bool bitmapsEnabled() 0596 { 0597 // 0598 // On some systems, such as KUbuntu, fontconfig is configured to ignore all bitmap fonts. 0599 // The following check tries to get a list of installed bitmaps, if it an empty list is returned 0600 // it is assumed that bitmaps are disabled. 0601 0602 static bool enabled(false); 0603 static bool checked(false); // Do not keep on checking! 0604 0605 if (!checked) { 0606 FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, (void *)nullptr); 0607 FcPattern *pat = FcPatternBuild(nullptr, FC_SCALABLE, FcTypeBool, FcFalse, NULL); 0608 FcFontSet *set = FcFontList(nullptr, pat, os); 0609 0610 FcPatternDestroy(pat); 0611 FcObjectSetDestroy(os); 0612 0613 if (set) { 0614 if (set->nfont) { 0615 enabled = true; 0616 } 0617 0618 FcFontSetDestroy(set); 0619 } 0620 checked = true; 0621 } 0622 0623 return enabled; 0624 } 0625 0626 } 0627 0628 }