a4d2778ba6c21183834ecf8893fcfd988ed0a587
[profile/ivi/qtbase.git] / src / platformsupport / fontdatabases / fontconfig / qfontconfigdatabase.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qfontconfigdatabase_p.h"
43 #include "qfontenginemultifontconfig_p.h"
44
45 #include <QtCore/QList>
46 #include <QtGui/private/qfont_p.h>
47
48 #include <QtCore/QElapsedTimer>
49
50 #include <QtGui/QPlatformScreen>
51
52 #include <QtGui/private/qfontengine_ft_p.h>
53 #include <QtGui/private/qfontengine_p.h>
54 #include <QtGui/private/qfontengine_qpa_p.h>
55
56 #include <ft2build.h>
57 #include FT_TRUETYPE_TABLES_H
58
59 #include <fontconfig/fontconfig.h>
60 #include FT_FREETYPE_H
61
62 #if FC_VERSION >= 20402
63 #include <fontconfig/fcfreetype.h>
64 #endif
65
66 #define SimplifiedChineseCsbBit 18
67 #define TraditionalChineseCsbBit 20
68 #define JapaneseCsbBit 17
69 #define KoreanCsbBit 21
70
71 QT_BEGIN_NAMESPACE
72
73 static inline bool requiresOpenType(int writingSystem)
74 {
75     return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala)
76             || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko);
77 }
78 static inline bool scriptRequiresOpenType(int script)
79 {
80     return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
81             || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
82 }
83
84 static int getFCWeight(int fc_weight)
85 {
86     int qtweight = QFont::Black;
87     if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2)
88         qtweight = QFont::Light;
89     else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2)
90         qtweight = QFont::Normal;
91     else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2)
92         qtweight = QFont::DemiBold;
93     else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2)
94         qtweight = QFont::Bold;
95
96     return qtweight;
97 }
98
99 static const char *specialLanguages[] = {
100     "en", // Common
101     "el", // Greek
102     "ru", // Cyrillic
103     "hy", // Armenian
104     "he", // Hebrew
105     "ar", // Arabic
106     "syr", // Syriac
107     "div", // Thaana
108     "hi", // Devanagari
109     "bn", // Bengali
110     "pa", // Gurmukhi
111     "gu", // Gujarati
112     "or", // Oriya
113     "ta", // Tamil
114     "te", // Telugu
115     "kn", // Kannada
116     "ml", // Malayalam
117     "si", // Sinhala
118     "th", // Thai
119     "lo", // Lao
120     "bo", // Tibetan
121     "my", // Myanmar
122     "ka", // Georgian
123     "ko", // Hangul
124     "", // Ogham
125     "", // Runic
126     "km", // Khmer
127     "" // N'Ko
128 };
129 enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) };
130
131 static const ushort specialChars[] = {
132     0, // English
133     0, // Greek
134     0, // Cyrillic
135     0, // Armenian
136     0, // Hebrew
137     0, // Arabic
138     0, // Syriac
139     0, // Thaana
140     0, // Devanagari
141     0, // Bengali
142     0, // Gurmukhi
143     0, // Gujarati
144     0, // Oriya
145     0, // Tamil
146     0xc15, // Telugu
147     0xc95, // Kannada
148     0xd15, // Malayalam
149     0xd9a, // Sinhala
150     0, // Thai
151     0, // Lao
152     0, // Tibetan
153     0x1000, // Myanmar
154     0, // Georgian
155     0, // Hangul
156     0x1681, // Ogham
157     0x16a0, // Runic
158     0,  // Khmer
159     0x7ca // N'Ko
160 };
161 enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) };
162
163 // this could become a list of all languages used for each writing
164 // system, instead of using the single most common language.
165 static const char *languageForWritingSystem[] = {
166     0,     // Any
167     "en",  // Latin
168     "el",  // Greek
169     "ru",  // Cyrillic
170     "hy",  // Armenian
171     "he",  // Hebrew
172     "ar",  // Arabic
173     "syr", // Syriac
174     "div", // Thaana
175     "hi",  // Devanagari
176     "bn",  // Bengali
177     "pa",  // Gurmukhi
178     "gu",  // Gujarati
179     "or",  // Oriya
180     "ta",  // Tamil
181     "te",  // Telugu
182     "kn",  // Kannada
183     "ml",  // Malayalam
184     "si",  // Sinhala
185     "th",  // Thai
186     "lo",  // Lao
187     "bo",  // Tibetan
188     "my",  // Myanmar
189     "ka",  // Georgian
190     "km",  // Khmer
191     "zh-cn", // SimplifiedChinese
192     "zh-tw", // TraditionalChinese
193     "ja",  // Japanese
194     "ko",  // Korean
195     "vi",  // Vietnamese
196     0, // Symbol
197     0, // Ogham
198     0, // Runic
199     0 // N'Ko
200 };
201 enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) };
202
203 // Unfortunately FontConfig doesn't know about some languages. We have to test these through the
204 // charset. The lists below contain the systems where we need to do this.
205 static const ushort sampleCharForWritingSystem[] = {
206     0,     // Any
207     0,  // Latin
208     0,  // Greek
209     0,  // Cyrillic
210     0,  // Armenian
211     0,  // Hebrew
212     0,  // Arabic
213     0, // Syriac
214     0, // Thaana
215     0,  // Devanagari
216     0,  // Bengali
217     0,  // Gurmukhi
218     0,  // Gujarati
219     0,  // Oriya
220     0,  // Tamil
221     0xc15,  // Telugu
222     0xc95,  // Kannada
223     0xd15,  // Malayalam
224     0xd9a,  // Sinhala
225     0,  // Thai
226     0,  // Lao
227     0,  // Tibetan
228     0x1000,  // Myanmar
229     0,  // Georgian
230     0,  // Khmer
231     0, // SimplifiedChinese
232     0, // TraditionalChinese
233     0,  // Japanese
234     0,  // Korean
235     0,  // Vietnamese
236     0, // Symbol
237     0x1681, // Ogham
238     0x16a0, // Runic
239     0x7ca // N'Ko
240 };
241 enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) };
242
243 // Newer FontConfig let's us sort out fonts that contain certain glyphs, but no
244 // open type tables for is directly. Do this so we don't pick some strange
245 // pseudo unicode font
246 static const char *openType[] = {
247     0,     // Any
248     0,  // Latin
249     0,  // Greek
250     0,  // Cyrillic
251     0,  // Armenian
252     0,  // Hebrew
253     0,  // Arabic
254     "syrc",  // Syriac
255     "thaa",  // Thaana
256     "deva",  // Devanagari
257     "beng",  // Bengali
258     "guru",  // Gurmukhi
259     "gurj",  // Gujarati
260     "orya",  // Oriya
261     "taml",  // Tamil
262     "telu",  // Telugu
263     "knda",  // Kannada
264     "mlym",  // Malayalam
265     "sinh",  // Sinhala
266     0,  // Thai
267     0,  // Lao
268     "tibt",  // Tibetan
269     "mymr",  // Myanmar
270     0,  // Georgian
271     "khmr",  // Khmer
272     0, // SimplifiedChinese
273     0, // TraditionalChinese
274     0,  // Japanese
275     0,  // Korean
276     0,  // Vietnamese
277     0, // Symbol
278     0, // Ogham
279     0, // Runic
280     "nko " // N'Ko
281 };
282
283 static const char *getFcFamilyForStyleHint(const QFont::StyleHint style)
284 {
285     const char *stylehint = 0;
286     switch (style) {
287     case QFont::SansSerif:
288         stylehint = "sans-serif";
289         break;
290     case QFont::Serif:
291         stylehint = "serif";
292         break;
293     case QFont::TypeWriter:
294         stylehint = "monospace";
295         break;
296     default:
297         break;
298     }
299     return stylehint;
300 }
301
302 void QFontconfigDatabase::populateFontDatabase()
303 {
304     FcFontSet  *fonts;
305
306     QString familyName;
307     FcChar8 *value = 0;
308     int weight_value;
309     int slant_value;
310     int spacing_value;
311     FcChar8 *file_value;
312     int indexValue;
313     FcChar8 *foundry_value;
314     FcBool scalable;
315     FcBool antialias;
316
317     {
318         FcObjectSet *os = FcObjectSetCreate();
319         FcPattern *pattern = FcPatternCreate();
320         const char *properties [] = {
321             FC_FAMILY, FC_WEIGHT, FC_SLANT,
322             FC_SPACING, FC_FILE, FC_INDEX,
323             FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT,
324             FC_WIDTH,
325 #if FC_VERSION >= 20297
326             FC_CAPABILITY,
327 #endif
328             (const char *)0
329         };
330         const char **p = properties;
331         while (*p) {
332             FcObjectSetAdd(os, *p);
333             ++p;
334         }
335         fonts = FcFontList(0, pattern, os);
336         FcObjectSetDestroy(os);
337         FcPatternDestroy(pattern);
338     }
339
340     for (int i = 0; i < fonts->nfont; i++) {
341         if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
342             continue;
343         //         capitalize(value);
344         familyName = QString::fromUtf8((const char *)value);
345         slant_value = FC_SLANT_ROMAN;
346         weight_value = FC_WEIGHT_MEDIUM;
347         spacing_value = FC_PROPORTIONAL;
348         file_value = 0;
349         indexValue = 0;
350         scalable = FcTrue;
351
352
353         if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch)
354             slant_value = FC_SLANT_ROMAN;
355         if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch)
356             weight_value = FC_WEIGHT_MEDIUM;
357         if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch)
358             spacing_value = FC_PROPORTIONAL;
359         if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch)
360             file_value = 0;
361         if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch)
362             indexValue = 0;
363         if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch)
364             scalable = FcTrue;
365         if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
366             foundry_value = 0;
367         if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch)
368             antialias = true;
369
370         QSupportedWritingSystems writingSystems;
371         FcLangSet *langset = 0;
372         FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset);
373         if (res == FcResultMatch) {
374             for (int i = 1; i < LanguageCount; ++i) {
375                 const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i];
376                 if (lang) {
377                     FcLangResult langRes = FcLangSetHasLang(langset, lang);
378                     if (langRes != FcLangDifferentLang)
379                         writingSystems.setSupported(QFontDatabase::WritingSystem(i));
380                 }
381             }
382         } else {
383             // we set Other to supported for symbol fonts. It makes no
384             // sense to merge these with other ones, as they are
385             // special in a way.
386             writingSystems.setSupported(QFontDatabase::Other);
387         }
388
389         FcCharSet *cs = 0;
390         res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs);
391         if (res == FcResultMatch) {
392             // some languages are not supported by FontConfig, we rather check the
393             // charset to detect these
394             for (int i = 1; i < SampleCharCount; ++i) {
395                 if (!sampleCharForWritingSystem[i])
396                     continue;
397                 if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i]))
398                     writingSystems.setSupported(QFontDatabase::WritingSystem(i));
399             }
400         }
401
402 #if FC_VERSION >= 20297
403         for (int j = 1; j < LanguageCount; ++j) {
404             if (writingSystems.supported(QFontDatabase::WritingSystem(j))
405                 && requiresOpenType(j) && openType[j]) {
406                 FcChar8 *cap;
407                 res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap);
408                 if (res != FcResultMatch || !strstr((const char *)cap, openType[j]))
409                     writingSystems.setSupported(QFontDatabase::WritingSystem(j),false);
410             }
411         }
412 #endif
413
414         FontFile *fontFile = new FontFile;
415         fontFile->fileName = QLatin1String((const char *)file_value);
416         fontFile->indexValue = indexValue;
417
418         QFont::Style style = (slant_value == FC_SLANT_ITALIC)
419                          ? QFont::StyleItalic
420                          : ((slant_value == FC_SLANT_OBLIQUE)
421                             ? QFont::StyleOblique
422                             : QFont::StyleNormal);
423         QFont::Weight weight = QFont::Weight(getFCWeight(weight_value));
424
425         double pixel_size = 0;
426         if (!scalable) {
427             int width = 100;
428             FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width);
429             FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size);
430         }
431
432         bool fixedPitch = spacing_value >= FC_MONO;
433         QFont::Stretch stretch = QFont::Unstretched;
434         QPlatformFontDatabase::registerFont(familyName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile);
435 //        qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size;
436     }
437
438     FcFontSetDestroy (fonts);
439
440     struct FcDefaultFont {
441         const char *qtname;
442         const char *rawname;
443         bool fixed;
444     };
445     const FcDefaultFont defaults[] = {
446         { "Serif", "serif", false },
447         { "Sans Serif", "sans-serif", false },
448         { "Monospace", "monospace", true },
449         { 0, 0, false }
450     };
451     const FcDefaultFont *f = defaults;
452     // aliases only make sense for 'common', not for any of the specials
453     QSupportedWritingSystems ws;
454     ws.setSupported(QFontDatabase::Latin);
455
456
457     QString familyQtName = QString::fromLatin1(f->qtname);
458     while (f->qtname) {
459         registerFont(familyQtName,QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,f->fixed,ws,0);
460         registerFont(familyQtName,QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,f->fixed,ws,0);
461         registerFont(familyQtName,QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,f->fixed,ws,0);
462         ++f;
463     }
464
465     //Lighthouse has very lazy population of the font db. We want it to be initialized when
466     //QApplication is constructed, so that the population procedure can do something like this to
467     //set the default font
468 //    const FcDefaultFont *s = defaults;
469 //    QFont font("Sans Serif");
470 //    font.setPointSize(9);
471 //    QApplication::setFont(font);
472 }
473
474 QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine,
475                                                        QUnicodeTables::Script script)
476 {
477     return new QFontEngineMultiFontConfig(fontEngine, script);
478 }
479
480 QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QUnicodeTables::Script script, void *usrPtr)
481 {
482     if (!usrPtr)
483         return 0;
484     QFontDef fontDef = f;
485
486     QFontEngineFT *engine;
487     FontFile *fontfile = static_cast<FontFile *> (usrPtr);
488     QFontEngine::FaceId fid;
489     fid.filename = fontfile->fileName.toLocal8Bit();
490     fid.index = fontfile->indexValue;
491
492     bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
493     engine = new QFontEngineFT(fontDef);
494
495     QFontEngineFT::GlyphFormat format;
496     // try and get the pattern
497     FcPattern *pattern = FcPatternCreate();
498
499     FcValue value;
500     value.type = FcTypeString;
501         QByteArray cs = fontDef.family.toUtf8();
502     value.u.s = (const FcChar8 *)cs.data();
503     FcPatternAdd(pattern,FC_FAMILY,value,true);
504
505     value.u.s = (const FcChar8 *)fid.filename.data();
506     FcPatternAdd(pattern,FC_FILE,value,true);
507
508     value.type = FcTypeInteger;
509     value.u.i = fid.index;
510     FcPatternAdd(pattern,FC_INDEX,value,true);
511
512     FcResult result;
513     FcPattern *match = FcFontMatch(0, pattern, &result);
514     FcCharSet *charset;
515     if (match) {
516         QFontEngineFT::HintStyle default_hint_style;
517         if (f.hintingPreference != QFont::PreferDefaultHinting) {
518             switch (f.hintingPreference) {
519             case QFont::PreferNoHinting:
520                 default_hint_style = QFontEngineFT::HintNone;
521                 break;
522             case QFont::PreferVerticalHinting:
523                 default_hint_style = QFontEngineFT::HintLight;
524                 break;
525             case QFont::PreferFullHinting:
526             default:
527                 default_hint_style = QFontEngineFT::HintFull;
528                 break;
529             }
530         } else {
531             int hint_style = 0;
532             if (FcPatternGetInteger (match, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch)
533                 hint_style = QFontEngineFT::HintFull;
534             switch (hint_style) {
535             case FC_HINT_NONE:
536                 default_hint_style = QFontEngineFT::HintNone;
537                 break;
538             case FC_HINT_SLIGHT:
539                 default_hint_style = QFontEngineFT::HintLight;
540                 break;
541             case FC_HINT_MEDIUM:
542                 default_hint_style = QFontEngineFT::HintMedium;
543                 break;
544             default:
545                 default_hint_style = QFontEngineFT::HintFull;
546                 break;
547             }
548         }
549         engine->setDefaultHintStyle(default_hint_style);
550
551         if (antialias) {
552             QFontEngineFT::SubpixelAntialiasingType subpixelType = QFontEngineFT::Subpixel_None;
553             int subpixel = FC_RGBA_NONE;
554
555             FcPatternGetInteger(match, FC_RGBA, 0, &subpixel);
556             if (subpixel == FC_RGBA_UNKNOWN)
557                 subpixel = FC_RGBA_NONE;
558
559             switch (subpixel) {
560                 case FC_RGBA_NONE: subpixelType = QFontEngineFT::Subpixel_None; break;
561                 case FC_RGBA_RGB: subpixelType = QFontEngineFT::Subpixel_RGB; break;
562                 case FC_RGBA_BGR: subpixelType = QFontEngineFT::Subpixel_BGR; break;
563                 case FC_RGBA_VRGB: subpixelType = QFontEngineFT::Subpixel_VRGB; break;
564                 case FC_RGBA_VBGR: subpixelType = QFontEngineFT::Subpixel_VBGR; break;
565                 default: break;
566             }
567
568             format = subpixelType == QFontEngineFT::Subpixel_None
569                         ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_A32;
570             engine->subpixelType = subpixelType;
571         } else
572             format = QFontEngineFT::Format_Mono;
573
574         FcPatternGetCharSet(match, FC_CHARSET, 0, &charset);
575         FcPatternDestroy(match);
576     } else
577         format = antialias ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono;
578
579     FcPatternDestroy(pattern);
580
581     if (!engine->init(fid,antialias,format)) {
582         delete engine;
583         engine = 0;
584         return engine;
585     }
586     if (engine->invalid()) {
587         delete engine;
588         engine = 0;
589     } else if (scriptRequiresOpenType(script)) {
590         HB_Face hbFace = engine->initializedHarfbuzzFace();
591         if (!hbFace || !hbFace->supported_scripts[script]) {
592             delete engine;
593             engine = 0;
594         }
595     }
596
597     if (engine && engine->freetype && !engine->freetype->charset)
598         engine->freetype->charset = FcCharSetCopy(charset);
599
600     return engine;
601 }
602
603 QStringList QFontconfigDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
604 {
605     QStringList fallbackFamilies;
606     FcPattern *pattern = FcPatternCreate();
607     if (!pattern)
608         return fallbackFamilies;
609
610     FcValue value;
611     value.type = FcTypeString;
612     QByteArray cs = family.toUtf8();
613     value.u.s = (const FcChar8 *)cs.data();
614     FcPatternAdd(pattern,FC_FAMILY,value,true);
615
616     int slant_value = FC_SLANT_ROMAN;
617     if (style == QFont::StyleItalic)
618         slant_value = FC_SLANT_ITALIC;
619     else if (style == QFont::StyleOblique)
620         slant_value = FC_SLANT_OBLIQUE;
621     FcPatternAddInteger(pattern, FC_SLANT, slant_value);
622
623     if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') {
624         Q_ASSERT(script < QUnicodeTables::ScriptCount);
625         FcLangSet *ls = FcLangSetCreate();
626         FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
627         FcPatternAddLangSet(pattern, FC_LANG, ls);
628         FcLangSetDestroy(ls);
629     }
630
631     const char *stylehint = getFcFamilyForStyleHint(styleHint);
632     if (stylehint) {
633         value.u.s = (const FcChar8 *)stylehint;
634         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
635     }
636
637     FcConfigSubstitute(0, pattern, FcMatchPattern);
638     FcDefaultSubstitute(pattern);
639
640     FcResult result = FcResultMatch;
641     FcFontSet *fontSet = FcFontSort(0,pattern,FcFalse,0,&result);
642     FcPatternDestroy(pattern);
643
644     if (fontSet) {
645         if (result == FcResultMatch) {
646             for (int i = 0; i < fontSet->nfont; i++) {
647                 FcChar8 *value = 0;
648                 if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
649                     continue;
650                 //         capitalize(value);
651                 QString familyName = QString::fromUtf8((const char *)value);
652                 if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive) &&
653                     familyName.compare(family, Qt::CaseInsensitive)) {
654                     fallbackFamilies << familyName;
655                 }
656             }
657         }
658         FcFontSetDestroy(fontSet);
659     }
660 //    qDebug() << "fallbackFamilies for:" << family << style << styleHint << script << fallbackFamilies;
661
662     return fallbackFamilies;
663 }
664
665 static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
666 {
667 #if FC_VERSION < 20402
668     Q_UNUSED(data)
669     return FcFreeTypeQuery(file, id, blanks, count);
670 #else
671     if (data.isEmpty())
672         return FcFreeTypeQuery(file, id, blanks, count);
673
674     extern FT_Library qt_getFreetype();
675     FT_Library lib = qt_getFreetype();
676
677     FcPattern *pattern = 0;
678
679     FT_Face face;
680     if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) {
681         *count = face->num_faces;
682
683         pattern = FcFreeTypeQueryFace(face, file, id, blanks);
684
685         FT_Done_Face(face);
686     }
687
688     return pattern;
689 #endif
690 }
691
692 QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
693 {
694     QStringList families;
695     FcFontSet *set = FcConfigGetFonts(0, FcSetApplication);
696     if (!set) {
697         FcConfigAppFontAddFile(0, (const FcChar8 *)":/non-existent");
698         set = FcConfigGetFonts(0, FcSetApplication); // try again
699         if (!set)
700             return families;
701     }
702
703     int id = 0;
704     FcBlanks *blanks = FcConfigGetBlanks(0);
705     int count = 0;
706
707     FcPattern *pattern = 0;
708     do {
709         pattern = queryFont((const FcChar8 *)QFile::encodeName(fileName).constData(),
710                             fontData, id, blanks, &count);
711         if (!pattern)
712             return families;
713
714         FcPatternDel(pattern, FC_FILE);
715         QByteArray cs = fileName.toUtf8();
716         FcPatternAddString(pattern, FC_FILE, (const FcChar8 *) cs.constData());
717
718         FcChar8 *fam = 0;
719         if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) {
720             QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
721             families << family;
722         }
723
724         if (!FcFontSetAdd(set, pattern))
725             return families;
726
727         ++id;
728     } while (pattern && id < count);
729
730     return families;
731 }
732
733 QString QFontconfigDatabase::resolveFontFamilyAlias(const QString &family) const
734 {
735     FcPattern *pattern = FcPatternCreate();
736     if (!pattern)
737         return family;
738
739     if (!family.isEmpty()) {
740         QByteArray cs = family.toUtf8();
741         FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) cs.constData());
742     }
743     FcConfigSubstitute(0, pattern, FcMatchPattern);
744     FcDefaultSubstitute(pattern);
745
746     FcChar8 *familyAfterSubstitution = 0;
747     FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
748     QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
749     FcPatternDestroy(pattern);
750
751     return resolved;
752 }
753
754 QFont QFontconfigDatabase::defaultFont() const
755 {
756     return QFont(resolveFontFamilyAlias(QString()));
757 }
758
759 QT_END_NAMESPACE