2 * KFontInst - KDE Font Installer
4 * Copyright 2003-2007 Craig Drummond <craig@kde.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 #include <QtCore/QTextStream>
28 // KDE font chooser always seems to use Italic - for both Oblique, and Italic. So I guees
29 // the fonts:/ should do too - so as to appear more unified.
31 // ditto with respect to Medium/Regular
32 #define KFI_HAVE_OBLIQUE // Do we differentiate between Italic and Oblique when comparing slants?
33 #define KFI_DISPLAY_OBLIQUE // Do we want to list "Oblique"? Or always use Italic?
34 #define KFI_HAVE_MEDIUM_WEIGHT // Do we differentiate between Medium and Regular weights when comparing weights?
35 #define KFI_DISPLAY_MEDIUM // Do we want to list "Medium"? Or always use Regular?
45 if(KFI_NULL_SETTING
==w
)
46 #ifdef KFI_HAVE_MEDIUM_WEIGHT
47 return FC_WEIGHT_MEDIUM
;
49 return FC_WEIGHT_REGULAR
;
52 if(w
<FC_WEIGHT_EXTRALIGHT
)
53 return FC_WEIGHT_THIN
;
55 if(w
<(FC_WEIGHT_EXTRALIGHT
+FC_WEIGHT_LIGHT
)/2)
56 return FC_WEIGHT_EXTRALIGHT
;
58 if(w
<(FC_WEIGHT_LIGHT
+FC_WEIGHT_REGULAR
)/2)
59 return FC_WEIGHT_LIGHT
;
61 #ifdef KFI_HAVE_MEDIUM_WEIGHT
62 if(w
<(FC_WEIGHT_REGULAR
+FC_WEIGHT_MEDIUM
)/2)
63 return FC_WEIGHT_REGULAR
;
65 if(w
<(FC_WEIGHT_MEDIUM
+FC_WEIGHT_DEMIBOLD
)/2)
66 return FC_WEIGHT_MEDIUM
;
68 if(w
<(FC_WEIGHT_REGULAR
+FC_WEIGHT_DEMIBOLD
)/2)
69 return FC_WEIGHT_REGULAR
;
72 if(w
<(FC_WEIGHT_DEMIBOLD
+FC_WEIGHT_BOLD
)/2)
73 return FC_WEIGHT_DEMIBOLD
;
75 if(w
<(FC_WEIGHT_BOLD
+FC_WEIGHT_EXTRABOLD
)/2)
76 return FC_WEIGHT_BOLD
;
78 if(w
<(FC_WEIGHT_EXTRABOLD
+FC_WEIGHT_BLACK
)/2)
79 return FC_WEIGHT_EXTRABOLD
;
81 return FC_WEIGHT_BLACK
;
86 if(KFI_NULL_SETTING
==w
)
87 return KFI_FC_WIDTH_NORMAL
;
89 if(w
<KFI_FC_WIDTH_EXTRACONDENSED
)
90 return KFI_FC_WIDTH_EXTRACONDENSED
;
92 if(w
<(KFI_FC_WIDTH_EXTRACONDENSED
+KFI_FC_WIDTH_CONDENSED
)/2)
93 return KFI_FC_WIDTH_EXTRACONDENSED
;
95 if(w
<(KFI_FC_WIDTH_CONDENSED
+KFI_FC_WIDTH_SEMICONDENSED
)/2)
96 return KFI_FC_WIDTH_CONDENSED
;
98 if(w
<(KFI_FC_WIDTH_SEMICONDENSED
+KFI_FC_WIDTH_NORMAL
)/2)
99 return KFI_FC_WIDTH_SEMICONDENSED
;
101 if(w
<(KFI_FC_WIDTH_NORMAL
+KFI_FC_WIDTH_SEMIEXPANDED
)/2)
102 return KFI_FC_WIDTH_NORMAL
;
104 if(w
<(KFI_FC_WIDTH_SEMIEXPANDED
+KFI_FC_WIDTH_EXPANDED
)/2)
105 return KFI_FC_WIDTH_SEMIEXPANDED
;
107 if(w
<(KFI_FC_WIDTH_EXPANDED
+KFI_FC_WIDTH_EXTRAEXPANDED
)/2)
108 return KFI_FC_WIDTH_EXPANDED
;
110 if(w
<(KFI_FC_WIDTH_EXTRAEXPANDED
+KFI_FC_WIDTH_ULTRAEXPANDED
)/2)
111 return KFI_FC_WIDTH_EXTRAEXPANDED
;
113 return KFI_FC_WIDTH_ULTRAEXPANDED
;
118 if(KFI_NULL_SETTING
==s
|| s
<FC_SLANT_ITALIC
)
119 return FC_SLANT_ROMAN
;
121 #ifdef KFI_HAVE_OBLIQUE
122 if(s
<(FC_SLANT_ITALIC
+FC_SLANT_OBLIQUE
)/2)
123 return FC_SLANT_ITALIC
;
125 return FC_SLANT_OBLIQUE
;
127 return FC_SLANT_ITALIC
;
134 return FC_PROPORTIONAL
;
136 if(s
<(FC_MONO
+FC_CHARCELL
)/2)
142 int strToWeight(const QString
&str
, QString
&newStr
)
144 if(0==str
.indexOf(i18n(KFI_WEIGHT_THIN
), 0, Qt::CaseInsensitive
))
146 newStr
=str
.mid(i18n(KFI_WEIGHT_THIN
).length());
147 return FC_WEIGHT_THIN
;
149 if(0==str
.indexOf(i18n(KFI_WEIGHT_EXTRALIGHT
), 0, Qt::CaseInsensitive
))
151 newStr
=str
.mid(i18n(KFI_WEIGHT_EXTRALIGHT
).length());
152 return FC_WEIGHT_EXTRALIGHT
;
154 //if(0==str.indexOf(i18n(KFI_WEIGHT_ULTRALIGHT), 0, Qt::CaseInsensitive))
156 // newStr=str.mid(i18n(KFI_WEIGHT_ULTRALIGHT).length());
157 // return FC_WEIGHT_ULTRALIGHT;
159 if(0==str
.indexOf(i18n(KFI_WEIGHT_LIGHT
), 0, Qt::CaseInsensitive
))
161 newStr
=str
.mid(i18n(KFI_WEIGHT_LIGHT
).length());
162 return FC_WEIGHT_LIGHT
;
164 if(0==str
.indexOf(i18n(KFI_WEIGHT_REGULAR
), 0, Qt::CaseInsensitive
))
166 newStr
=str
.mid(i18n(KFI_WEIGHT_REGULAR
).length());
167 return FC_WEIGHT_REGULAR
;
169 //if(0==str.indexOf(i18n(KFI_WEIGHT_NORMAL), 0, Qt::CaseInsensitive))
171 // newStr=str.mid(i18n(KFI_WEIGHT_NORMAL).length());
172 // return FC_WEIGHT_NORMAL;
174 if(0==str
.indexOf(i18n(KFI_WEIGHT_MEDIUM
), 0, Qt::CaseInsensitive
))
176 newStr
=str
.mid(i18n(KFI_WEIGHT_MEDIUM
).length());
177 return FC_WEIGHT_MEDIUM
;
179 if(0==str
.indexOf(i18n(KFI_WEIGHT_DEMIBOLD
), 0, Qt::CaseInsensitive
))
181 newStr
=str
.mid(i18n(KFI_WEIGHT_DEMIBOLD
).length());
182 return FC_WEIGHT_DEMIBOLD
;
184 //if(0==str.indexOf(i18n(KFI_WEIGHT_SEMIBOLD), 0, Qt::CaseInsensitive))
186 // newStr=str.mid(i18n(KFI_WEIGHT_SEMIBOLD).length());
187 // return FC_WEIGHT_SEMIBOLD;
189 if(0==str
.indexOf(i18n(KFI_WEIGHT_BOLD
), 0, Qt::CaseInsensitive
))
191 newStr
=str
.mid(i18n(KFI_WEIGHT_BOLD
).length());
192 return FC_WEIGHT_BOLD
;
194 if(0==str
.indexOf(i18n(KFI_WEIGHT_EXTRABOLD
), 0, Qt::CaseInsensitive
))
196 newStr
=str
.mid(i18n(KFI_WEIGHT_EXTRABOLD
).length());
197 return FC_WEIGHT_EXTRABOLD
;
199 //if(0==str.indexOf(i18n(KFI_WEIGHT_ULTRABOLD), 0, Qt::CaseInsensitive))
201 // newStr=str.mid(i18n(KFI_WEIGHT_ULTRABOLD).length());
202 // return FC_WEIGHT_ULTRABOLD;
204 if(0==str
.indexOf(i18n(KFI_WEIGHT_BLACK
), 0, Qt::CaseInsensitive
))
206 newStr
=str
.mid(i18n(KFI_WEIGHT_BLACK
).length());
207 return FC_WEIGHT_BLACK
;
209 if(0==str
.indexOf(i18n(KFI_WEIGHT_BLACK
), 0, Qt::CaseInsensitive
))
211 newStr
=str
.mid(i18n(KFI_WEIGHT_BLACK
).length());
212 return FC_WEIGHT_BLACK
;
216 return FC_WEIGHT_REGULAR
;
219 int strToWidth(const QString
&str
, QString
&newStr
)
221 if(0==str
.indexOf(i18n(KFI_WIDTH_ULTRACONDENSED
), 0, Qt::CaseInsensitive
))
223 newStr
=str
.mid(i18n(KFI_WIDTH_ULTRACONDENSED
).length());
224 return KFI_FC_WIDTH_ULTRACONDENSED
;
226 if(0==str
.indexOf(i18n(KFI_WIDTH_EXTRACONDENSED
), 0, Qt::CaseInsensitive
))
228 newStr
=str
.mid(i18n(KFI_WIDTH_EXTRACONDENSED
).length());
229 return KFI_FC_WIDTH_EXTRACONDENSED
;
231 if(0==str
.indexOf(i18n(KFI_WIDTH_CONDENSED
), 0, Qt::CaseInsensitive
))
233 newStr
=str
.mid(i18n(KFI_WIDTH_CONDENSED
).length());
234 return KFI_FC_WIDTH_CONDENSED
;
236 if(0==str
.indexOf(i18n(KFI_WIDTH_SEMICONDENSED
), 0, Qt::CaseInsensitive
))
238 newStr
=str
.mid(i18n(KFI_WIDTH_SEMICONDENSED
).length());
239 return KFI_FC_WIDTH_SEMICONDENSED
;
241 if(0==str
.indexOf(i18n(KFI_WIDTH_NORMAL
), 0, Qt::CaseInsensitive
))
243 newStr
=str
.mid(i18n(KFI_WIDTH_NORMAL
).length());
244 return KFI_FC_WIDTH_NORMAL
;
246 if(0==str
.indexOf(i18n(KFI_WIDTH_SEMIEXPANDED
), 0, Qt::CaseInsensitive
))
248 newStr
=str
.mid(i18n(KFI_WIDTH_SEMIEXPANDED
).length());
249 return KFI_FC_WIDTH_SEMIEXPANDED
;
251 if(0==str
.indexOf(i18n(KFI_WIDTH_EXPANDED
), 0, Qt::CaseInsensitive
))
253 newStr
=str
.mid(i18n(KFI_WIDTH_EXPANDED
).length());
254 return KFI_FC_WIDTH_EXPANDED
;
256 if(0==str
.indexOf(i18n(KFI_WIDTH_EXTRAEXPANDED
), 0, Qt::CaseInsensitive
))
258 newStr
=str
.mid(i18n(KFI_WIDTH_EXTRAEXPANDED
).length());
259 return KFI_FC_WIDTH_EXTRAEXPANDED
;
261 if(0==str
.indexOf(i18n(KFI_WIDTH_ULTRAEXPANDED
), 0, Qt::CaseInsensitive
))
263 newStr
=str
.mid(i18n(KFI_WIDTH_ULTRAEXPANDED
).length());
264 return KFI_FC_WIDTH_ULTRAEXPANDED
;
268 return KFI_FC_WIDTH_NORMAL
;
271 int strToSlant(const QString
&str
)
273 if(-1!=str
.indexOf(i18n(KFI_SLANT_ITALIC
)))
274 return FC_SLANT_ITALIC
;
275 if(-1!=str
.indexOf(i18n(KFI_SLANT_OBLIQUE
)))
276 return FC_SLANT_OBLIQUE
;
277 return FC_SLANT_ROMAN
;
280 quint32
createStyleVal(const QString
&name
)
284 if(-1==(pos
=name
.indexOf(", "))) // No style information...
285 return createStyleVal(FC_WEIGHT_REGULAR
,
286 #ifdef KFI_FC_NO_WIDTHS
294 QString
style(name
.mid(pos
+2));
296 return createStyleVal(strToWeight(style
, style
),
297 #ifdef KFI_FC_NO_WIDTHS
300 strToWidth(style
, style
)
302 , strToSlant(style
));
306 QString
styleValToStr(quint32 style
)
309 int weight
, width
, slant
;
311 decomposeStyleVal(style
, weight
, width
, slant
);
312 str
.sprintf("0X%02X%02X%02X\n", weight
, width
, slant
);
316 void decomposeStyleVal(quint32 styleInfo
, int &weight
, int &width
, int &slant
)
318 weight
=(styleInfo
&0xFF0000)>>16;
319 width
=(styleInfo
&0x00FF00)>>8;
320 slant
=(styleInfo
&0x0000FF);
323 quint32
styleValFromStr(const QString
&style
)
326 return KFI_NO_STYLE_INFO
;
331 QTextStream(const_cast<QString
*>(&style
), QIODevice::ReadOnly
) >> val
;
336 QString
getFcString(FcPattern
*pat
, const char *val
, int index
)
341 if(FcResultMatch
==FcPatternGetString(pat
, val
, index
, &fcStr
))
342 rv
=QString::fromUtf8((char *)fcStr
);
347 #ifdef KFI_USE_TRANSLATED_FAMILY_NAME
349 // Try to get the 'string' that matches the users KDE locale..
350 QString
getFcLangString(FcPattern
*pat
, const char *val
, const char *valLang
)
353 QStringList kdeLangs
=KGlobal::locale()->languageList(),
355 QStringList::ConstIterator
it(kdeLangs
.begin()),
358 // Create list of langs that this font's 'val' is encoded in...
359 for(int i
=0; true; ++i
)
361 QString lang
=getFcString(pat
, valLang
, i
);
366 fontLangs
.append(lang
);
369 // Now go through the user's KDE locale, and try to find a font match...
372 int index
=fontLangs
.findIndex(*it
);
376 rv
=getFcString(pat
, val
, index
);
384 rv
=getFcString(pat
, val
, 0);
389 int getFcInt(FcPattern
*pat
, const char *val
, int index
, int def
)
393 if (FcResultMatch
==FcPatternGetInteger(pat
, val
, index
, &rv
))
398 void getDetails(FcPattern
*pat
, QString
&name
, quint32
&styleVal
, int &index
)
400 int weight
=getFcInt(pat
, FC_WEIGHT
, 0, KFI_NULL_SETTING
),
402 #ifdef KFI_FC_NO_WIDTHS
405 getFcInt(pat
, FC_WIDTH
, 0, KFI_NULL_SETTING
),
407 slant
=getFcInt(pat
, FC_SLANT
, 0, KFI_NULL_SETTING
);
409 index
=getFcInt(pat
, FC_INDEX
, 0, 0);
410 name
=createName(pat
, weight
, width
, slant
);
411 styleVal
=createStyleVal(weight
, width
, slant
);
414 QString
createName(FcPattern
*pat
)
416 return createName(pat
, getFcInt(pat
, FC_WEIGHT
, 0),
417 #ifdef KFI_FC_NO_WIDTHS
420 getFcInt(pat
, FC_WIDTH
, 0),
422 getFcInt(pat
, FC_SLANT
, 0));
425 QString
createName(FcPattern
*pat
, int weight
, int width
, int slant
)
427 #ifdef KFI_USE_TRANSLATED_FAMILY_NAME
428 QString
family(getFcLangString(pat
, FC_FAMILY
, FC_FAMILYLANG
));
430 QString
family(getFcString(pat
, FC_FAMILY
, 0));
433 return createName(family
, weight
, width
, slant
);
436 QString
createName(const QString
&family
, quint32 styleInfo
)
438 int weight
, width
, slant
;
440 decomposeStyleVal(styleInfo
, weight
, width
, slant
);
441 return createName(family
, weight
, width
, slant
);
444 QString
createName(const QString
&family
, int weight
, int width
, int slant
)
447 //CPD: TODO: the names *need* to match up with kfontchooser's...
448 // : Removing KFI_DISPLAY_OBLIQUE and KFI_DISPLAY_MEDIUM help this.
449 // However, I have at least one bad font:
450 // Rockwell Extra Bold. Both fontconfig, and kcmshell fonts list family
451 // as "Rockwell Extra Bold" -- good (well at least they match). *But* fontconfig
452 // is returning the weight "Extra Bold", and kcmshell fonts is using "Bold" :-(
454 QString
name(family
),
460 #ifndef KFI_FC_NO_WIDTHS
461 if(KFI_NULL_SETTING
!=width
)
462 widthString
=widthStr(width
);
465 if(KFI_NULL_SETTING
!=slant
)
466 slantString
=slantStr(slant
);
469 // If weight is "Regular", we only want to display it if slant and width are empty.
470 if(KFI_NULL_SETTING
!=weight
)
472 weightString
=weightStr(weight
, !slantString
.isEmpty() || !widthString
.isEmpty());
474 if(!weightString
.isEmpty())
476 name
+=QString(", ")+weightString
;
481 #ifndef KFI_FC_NO_WIDTHS
482 if(!widthString
.isEmpty())
489 name
+=QChar(' ')+widthString
;
493 if(!slantString
.isEmpty())
500 name
+=QChar(' ')+slantString
;
506 QString
weightStr(int w
, bool emptyNormal
)
511 return i18n(KFI_WEIGHT_THIN
);
512 case FC_WEIGHT_EXTRALIGHT
:
513 return i18n(KFI_WEIGHT_EXTRALIGHT
);
514 case FC_WEIGHT_LIGHT
:
515 return i18n(KFI_WEIGHT_LIGHT
);
516 case FC_WEIGHT_MEDIUM
:
517 #ifdef KFI_DISPLAY_MEDIUM
518 return i18n(KFI_WEIGHT_MEDIUM
);
520 case FC_WEIGHT_REGULAR
:
521 return emptyNormal
? QString() : i18n(KFI_WEIGHT_REGULAR
);
522 case FC_WEIGHT_DEMIBOLD
:
523 return i18n(KFI_WEIGHT_DEMIBOLD
);
525 return i18n(KFI_WEIGHT_BOLD
);
526 case FC_WEIGHT_EXTRABOLD
:
527 return i18n(KFI_WEIGHT_EXTRABOLD
);
529 return i18n(KFI_WEIGHT_BLACK
);
533 QString
widthStr(int w
, bool emptyNormal
)
537 case KFI_FC_WIDTH_ULTRACONDENSED
:
538 return i18n(KFI_WIDTH_ULTRACONDENSED
);
539 case KFI_FC_WIDTH_EXTRACONDENSED
:
540 return i18n(KFI_WIDTH_EXTRACONDENSED
);
541 case KFI_FC_WIDTH_CONDENSED
:
542 return i18n(KFI_WIDTH_CONDENSED
);
543 case KFI_FC_WIDTH_SEMICONDENSED
:
544 return i18n(KFI_WIDTH_SEMICONDENSED
);
545 case KFI_FC_WIDTH_NORMAL
:
546 return emptyNormal
? QString() : i18n(KFI_WIDTH_NORMAL
);
547 case KFI_FC_WIDTH_SEMIEXPANDED
:
548 return i18n(KFI_WIDTH_SEMIEXPANDED
);
549 case KFI_FC_WIDTH_EXPANDED
:
550 return i18n(KFI_WIDTH_EXPANDED
);
551 case KFI_FC_WIDTH_EXTRAEXPANDED
:
552 return i18n(KFI_WIDTH_EXTRAEXPANDED
);
554 return i18n(KFI_WIDTH_ULTRAEXPANDED
);
558 QString
slantStr(int s
, bool emptyNormal
)
562 case FC_SLANT_OBLIQUE
:
563 #ifdef KFI_DISPLAY_OBLIQUE
564 return i18n(KFI_SLANT_OBLIQUE
);
566 case FC_SLANT_ITALIC
:
567 return i18n(KFI_SLANT_ITALIC
);
569 return emptyNormal
? QString() : i18n(KFI_SLANT_ROMAN
);
573 QString
spacingStr(int s
)
578 return i18n(KFI_SPACING_MONO
);
580 return i18n(KFI_SPACING_CHARCELL
);
582 return i18n(KFI_SPACING_PROPORTIONAL
);
586 bool bitmapsEnabled()
589 // On some systems, such as KUbuntu, fontconfig is configured to ignore all bitmap fonts.
590 // The following check tries to get a list of installed bitmaps, if it an empty list is returned
591 // it is assumed that bitmaps are disabled.
593 static bool enabled(false);
594 static bool checked(false); // Do not keep on checking!
598 FcObjectSet
*os
= FcObjectSetBuild(FC_FAMILY
, (void *)0);
599 FcPattern
*pat
= FcPatternBuild(NULL
, FC_SCALABLE
, FcTypeBool
, FcFalse
, NULL
);
600 FcFontSet
*set
= FcFontList(0, pat
, os
);
602 FcPatternDestroy(pat
);
603 FcObjectSetDestroy(os
);
610 FcFontSetDestroy(set
);