Fix for fontconfig 2.9 behavior change
[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     while (f->qtname) {
457         QString familyQtName = QString::fromLatin1(f->qtname);
458         registerFont(familyQtName,QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,f->fixed,ws,0);
459         registerFont(familyQtName,QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,f->fixed,ws,0);
460         registerFont(familyQtName,QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,f->fixed,ws,0);
461         ++f;
462     }
463
464     //Lighthouse has very lazy population of the font db. We want it to be initialized when
465     //QApplication is constructed, so that the population procedure can do something like this to
466     //set the default font
467 //    const FcDefaultFont *s = defaults;
468 //    QFont font("Sans Serif");
469 //    font.setPointSize(9);
470 //    QApplication::setFont(font);
471 }
472
473 QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine,
474                                                        QUnicodeTables::Script script)
475 {
476     return new QFontEngineMultiFontConfig(fontEngine, script);
477 }
478
479 QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QUnicodeTables::Script script, void *usrPtr)
480 {
481     if (!usrPtr)
482         return 0;
483     QFontDef fontDef = f;
484
485     QFontEngineFT *engine;
486     FontFile *fontfile = static_cast<FontFile *> (usrPtr);
487     QFontEngine::FaceId fid;
488     fid.filename = fontfile->fileName.toLocal8Bit();
489     fid.index = fontfile->indexValue;
490
491     bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
492     engine = new QFontEngineFT(fontDef);
493
494     QFontEngineFT::GlyphFormat format;
495     // try and get the pattern
496     FcPattern *pattern = FcPatternCreate();
497
498     FcValue value;
499     value.type = FcTypeString;
500         QByteArray cs = fontDef.family.toUtf8();
501     value.u.s = (const FcChar8 *)cs.data();
502     FcPatternAdd(pattern,FC_FAMILY,value,true);
503
504     value.u.s = (const FcChar8 *)fid.filename.data();
505     FcPatternAdd(pattern,FC_FILE,value,true);
506
507     value.type = FcTypeInteger;
508     value.u.i = fid.index;
509     FcPatternAdd(pattern,FC_INDEX,value,true);
510
511     FcResult result;
512     FcPattern *match = FcFontMatch(0, pattern, &result);
513     FcCharSet *charset;
514     if (match) {
515         QFontEngineFT::HintStyle default_hint_style;
516         if (f.hintingPreference != QFont::PreferDefaultHinting) {
517             switch (f.hintingPreference) {
518             case QFont::PreferNoHinting:
519                 default_hint_style = QFontEngineFT::HintNone;
520                 break;
521             case QFont::PreferVerticalHinting:
522                 default_hint_style = QFontEngineFT::HintLight;
523                 break;
524             case QFont::PreferFullHinting:
525             default:
526                 default_hint_style = QFontEngineFT::HintFull;
527                 break;
528             }
529         } else {
530             int hint_style = 0;
531             if (FcPatternGetInteger (match, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch)
532                 hint_style = QFontEngineFT::HintFull;
533             switch (hint_style) {
534             case FC_HINT_NONE:
535                 default_hint_style = QFontEngineFT::HintNone;
536                 break;
537             case FC_HINT_SLIGHT:
538                 default_hint_style = QFontEngineFT::HintLight;
539                 break;
540             case FC_HINT_MEDIUM:
541                 default_hint_style = QFontEngineFT::HintMedium;
542                 break;
543             default:
544                 default_hint_style = QFontEngineFT::HintFull;
545                 break;
546             }
547         }
548         engine->setDefaultHintStyle(default_hint_style);
549
550         if (antialias) {
551             QFontEngineFT::SubpixelAntialiasingType subpixelType = QFontEngineFT::Subpixel_None;
552             int subpixel = FC_RGBA_NONE;
553
554             FcPatternGetInteger(match, FC_RGBA, 0, &subpixel);
555             if (subpixel == FC_RGBA_UNKNOWN)
556                 subpixel = FC_RGBA_NONE;
557
558             switch (subpixel) {
559                 case FC_RGBA_NONE: subpixelType = QFontEngineFT::Subpixel_None; break;
560                 case FC_RGBA_RGB: subpixelType = QFontEngineFT::Subpixel_RGB; break;
561                 case FC_RGBA_BGR: subpixelType = QFontEngineFT::Subpixel_BGR; break;
562                 case FC_RGBA_VRGB: subpixelType = QFontEngineFT::Subpixel_VRGB; break;
563                 case FC_RGBA_VBGR: subpixelType = QFontEngineFT::Subpixel_VBGR; break;
564                 default: break;
565             }
566
567             format = subpixelType == QFontEngineFT::Subpixel_None
568                         ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_A32;
569             engine->subpixelType = subpixelType;
570         } else
571             format = QFontEngineFT::Format_Mono;
572
573         FcPatternGetCharSet(match, FC_CHARSET, 0, &charset);
574         FcPatternDestroy(match);
575     } else
576         format = antialias ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono;
577
578     FcPatternDestroy(pattern);
579
580     if (!engine->init(fid,antialias,format)) {
581         delete engine;
582         engine = 0;
583         return engine;
584     }
585     if (engine->invalid()) {
586         delete engine;
587         engine = 0;
588     } else if (scriptRequiresOpenType(script)) {
589         HB_Face hbFace = engine->initializedHarfbuzzFace();
590         if (!hbFace || !hbFace->supported_scripts[script]) {
591             delete engine;
592             engine = 0;
593         }
594     }
595
596     if (engine && engine->freetype && !engine->freetype->charset)
597         engine->freetype->charset = FcCharSetCopy(charset);
598
599     return engine;
600 }
601
602 QStringList QFontconfigDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
603 {
604     QStringList fallbackFamilies;
605     FcPattern *pattern = FcPatternCreate();
606     if (!pattern)
607         return fallbackFamilies;
608
609     FcValue value;
610     value.type = FcTypeString;
611     QByteArray cs = family.toUtf8();
612     value.u.s = (const FcChar8 *)cs.data();
613     FcPatternAdd(pattern,FC_FAMILY,value,true);
614
615     int slant_value = FC_SLANT_ROMAN;
616     if (style == QFont::StyleItalic)
617         slant_value = FC_SLANT_ITALIC;
618     else if (style == QFont::StyleOblique)
619         slant_value = FC_SLANT_OBLIQUE;
620     FcPatternAddInteger(pattern, FC_SLANT, slant_value);
621
622     if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') {
623         Q_ASSERT(script < QUnicodeTables::ScriptCount);
624         FcLangSet *ls = FcLangSetCreate();
625         FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
626         FcPatternAddLangSet(pattern, FC_LANG, ls);
627         FcLangSetDestroy(ls);
628     }
629
630     const char *stylehint = getFcFamilyForStyleHint(styleHint);
631     if (stylehint) {
632         value.u.s = (const FcChar8 *)stylehint;
633         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
634     }
635
636     FcConfigSubstitute(0, pattern, FcMatchPattern);
637     FcDefaultSubstitute(pattern);
638
639     FcResult result = FcResultMatch;
640     FcFontSet *fontSet = FcFontSort(0,pattern,FcFalse,0,&result);
641     FcPatternDestroy(pattern);
642
643     if (fontSet) {
644         for (int i = 0; i < fontSet->nfont; i++) {
645             FcChar8 *value = 0;
646             if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
647                 continue;
648             //         capitalize(value);
649             QString familyName = QString::fromUtf8((const char *)value);
650             if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive) &&
651                 familyName.compare(family, Qt::CaseInsensitive)) {
652                 fallbackFamilies << familyName;
653             }
654         }
655         FcFontSetDestroy(fontSet);
656     }
657 //    qDebug() << "fallbackFamilies for:" << family << style << styleHint << script << fallbackFamilies;
658
659     return fallbackFamilies;
660 }
661
662 static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
663 {
664 #if FC_VERSION < 20402
665     Q_UNUSED(data)
666     return FcFreeTypeQuery(file, id, blanks, count);
667 #else
668     if (data.isEmpty())
669         return FcFreeTypeQuery(file, id, blanks, count);
670
671     FT_Library lib = qt_getFreetype();
672
673     FcPattern *pattern = 0;
674
675     FT_Face face;
676     if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) {
677         *count = face->num_faces;
678
679         pattern = FcFreeTypeQueryFace(face, file, id, blanks);
680
681         FT_Done_Face(face);
682     }
683
684     return pattern;
685 #endif
686 }
687
688 QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
689 {
690     QStringList families;
691     FcFontSet *set = FcConfigGetFonts(0, FcSetApplication);
692     if (!set) {
693         FcConfigAppFontAddFile(0, (const FcChar8 *)":/non-existent");
694         set = FcConfigGetFonts(0, FcSetApplication); // try again
695         if (!set)
696             return families;
697     }
698
699     int id = 0;
700     FcBlanks *blanks = FcConfigGetBlanks(0);
701     int count = 0;
702
703     FcPattern *pattern = 0;
704     do {
705         pattern = queryFont((const FcChar8 *)QFile::encodeName(fileName).constData(),
706                             fontData, id, blanks, &count);
707         if (!pattern)
708             return families;
709
710         FcPatternDel(pattern, FC_FILE);
711         QByteArray cs = fileName.toUtf8();
712         FcPatternAddString(pattern, FC_FILE, (const FcChar8 *) cs.constData());
713
714         FcChar8 *fam = 0;
715         if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) {
716             QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
717             families << family;
718         }
719
720         if (!FcFontSetAdd(set, pattern))
721             return families;
722
723         ++id;
724     } while (pattern && id < count);
725
726     return families;
727 }
728
729 QString QFontconfigDatabase::resolveFontFamilyAlias(const QString &family) const
730 {
731     FcPattern *pattern = FcPatternCreate();
732     if (!pattern)
733         return family;
734
735     if (!family.isEmpty()) {
736         QByteArray cs = family.toUtf8();
737         FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) cs.constData());
738     }
739     FcConfigSubstitute(0, pattern, FcMatchPattern);
740     FcDefaultSubstitute(pattern);
741
742     FcChar8 *familyAfterSubstitution = 0;
743     FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution);
744     QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution);
745     FcPatternDestroy(pattern);
746
747     return resolved;
748 }
749
750 QFont QFontconfigDatabase::defaultFont() const
751 {
752     return QFont(resolveFontFamilyAlias(QString()));
753 }
754
755 QT_END_NAMESPACE