src/gui/text/qfontdatabase_x11.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include <qplatformdefs.h>
00025 
00026 #include <qdatetime.h>
00027 #include <qdebug.h>
00028 #include <qpaintdevice.h>
00029 
00030 #include <private/qt_x11_p.h>
00031 #include "qx11info_x11.h"
00032 #include <qdebug.h>
00033 #include <qfile.h>
00034 #include <qtemporaryfile.h>
00035 #include <qabstractfileengine.h>
00036 
00037 #include <ctype.h>
00038 #include <stdlib.h>
00039 
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #include <fcntl.h>
00043 #include <sys/mman.h>
00044 
00045 #ifndef QT_NO_FONTCONFIG
00046 #include <ft2build.h>
00047 #include FT_FREETYPE_H
00048 #endif
00049 
00050 // from qfont_x11.cpp
00051 extern double qt_pointSize(double pixelSize, int dpi);
00052 extern double qt_pixelSize(double pointSize, int dpi);
00053 
00054 static inline void capitalize (char *s)
00055 {
00056     bool space = true;
00057     while(*s) {
00058         if (space)
00059             *s = toupper(*s);
00060         space = (*s == ' ');
00061         ++s;
00062     }
00063 }
00064 
00065 
00066 /*
00067   To regenerate the writingSystems_for_xlfd_encoding table, run
00068   'util/unicode/x11/makeencodings' and paste the generated
00069   'encodings.c' here.
00070 */
00071 // ----- begin of generated code -----
00072 
00073 #define make_tag( c1, c2, c3, c4 )                              \
00074     ((((unsigned int)c1)<<24) | (((unsigned int)c2)<<16) |      \
00075      (((unsigned int)c3)<<8) | ((unsigned int)c4))
00076 
00077 struct XlfdEncoding {
00078     const char *name;
00079     int id;
00080     int mib;
00081     unsigned int hash1;
00082     unsigned int hash2;
00083 };
00084 
00085 static const XlfdEncoding xlfd_encoding[] = {
00086     { "iso8859-1", 0, 4, make_tag('i','s','o','8'), make_tag('5','9','-','1') },
00087     { "iso8859-2", 1, 5, make_tag('i','s','o','8'), make_tag('5','9','-','2') },
00088     { "iso8859-3", 2, 6, make_tag('i','s','o','8'), make_tag('5','9','-','3') },
00089     { "iso8859-4", 3, 7, make_tag('i','s','o','8'), make_tag('5','9','-','4') },
00090     { "iso8859-9", 4, 12, make_tag('i','s','o','8'), make_tag('5','9','-','9') },
00091     { "iso8859-10", 5, 13, make_tag('i','s','o','8'), make_tag('9','-','1','0') },
00092     { "iso8859-13", 6, 109, make_tag('i','s','o','8'), make_tag('9','-','1','3') },
00093     { "iso8859-14", 7, 110, make_tag('i','s','o','8'), make_tag('9','-','1','4') },
00094     { "iso8859-15", 8, 111, make_tag('i','s','o','8'), make_tag('9','-','1','5') },
00095     { "hp-roman8", 9, 2004, make_tag('h','p','-','r'), make_tag('m','a','n','8') },
00096     { "iso8859-5", 10, 8, make_tag('i','s','o','8'), make_tag('5','9','-','5') },
00097     { "*-cp1251", 11, 2251, 0, make_tag('1','2','5','1') },
00098     { "koi8-ru", 12, 2084, make_tag('k','o','i','8'), make_tag('8','-','r','u') },
00099     { "koi8-u", 13, 2088, make_tag('k','o','i','8'), make_tag('i','8','-','u') },
00100     { "koi8-r", 14, 2084, make_tag('k','o','i','8'), make_tag('i','8','-','r') },
00101     { "iso8859-7", 15, 10, make_tag('i','s','o','8'), make_tag('5','9','-','7') },
00102     { "iso8859-8", 16, 85, make_tag('i','s','o','8'), make_tag('5','9','-','8') },
00103     { "gb18030-0", 17, -114, make_tag('g','b','1','8'), make_tag('3','0','-','0') },
00104     { "gb18030.2000-0", 18, -113, make_tag('g','b','1','8'), make_tag('0','0','-','0') },
00105     { "gbk-0", 19, -113, make_tag('g','b','k','-'), make_tag('b','k','-','0') },
00106     { "gb2312.*-0", 20, 57, make_tag('g','b','2','3'), 0 },
00107     { "jisx0201*-0", 21, 15, make_tag('j','i','s','x'), 0 },
00108     { "jisx0208*-0", 22, 63, make_tag('j','i','s','x'), 0 },
00109     { "ksc5601*-*", 23, 36, make_tag('k','s','c','5'), 0 },
00110     { "big5hkscs-0", 24, -2101, make_tag('b','i','g','5'), make_tag('c','s','-','0') },
00111     { "hkscs-1", 25, -2101, make_tag('h','k','s','c'), make_tag('c','s','-','1') },
00112     { "big5*-*", 26, -2026, make_tag('b','i','g','5'), 0 },
00113     { "tscii-*", 27, 2028, make_tag('t','s','c','i'), 0 },
00114     { "tis620*-*", 28, 2259, make_tag('t','i','s','6'), 0 },
00115     { "iso8859-11", 29, 2259, make_tag('i','s','o','8'), make_tag('9','-','1','1') },
00116     { "mulelao-1", 30, -4242, make_tag('m','u','l','e'), make_tag('a','o','-','1') },
00117     { "ethiopic-unicode", 31, 0, make_tag('e','t','h','i'), make_tag('c','o','d','e') },
00118     { "iso10646-1", 32, 0, make_tag('i','s','o','1'), make_tag('4','6','-','1') },
00119     { "unicode-*", 33, 0, make_tag('u','n','i','c'), 0 },
00120     { "*-symbol", 34, 0, 0, make_tag('m','b','o','l') },
00121     { "*-fontspecific", 35, 0, 0, make_tag('i','f','i','c') },
00122     { "fontspecific-*", 36, 0, make_tag('f','o','n','t'), 0 },
00123     { 0, 0, 0, 0, 0 }
00124 };
00125 
00126 static const char writingSystems_for_xlfd_encoding[sizeof(xlfd_encoding)][QFontDatabase::WritingSystemsCount] = {
00127     // iso8859-1
00128     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00129       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00130       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00131       0 },
00132     // iso8859-2
00133     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00134       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00135       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00136       0 },
00137     // iso8859-3
00138     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00139       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00140       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00141       0 },
00142     // iso8859-4
00143     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00144       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00145       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00146       0 },
00147     // iso8859-9
00148     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00149       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00150       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00151       0 },
00152     // iso8859-10
00153     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00154       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00155       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00156       0 },
00157     // iso8859-13
00158     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00159       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00160       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00161       0 },
00162     // iso8859-14
00163     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00164       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00165       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00166       0 },
00167     // iso8859-15
00168     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00169       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00170       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00171       0 },
00172     // hp-roman8
00173     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00174       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00175       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00176       0 },
00177     // iso8859-5
00178     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
00179       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00180       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00181       0 },
00182     // *-cp1251
00183     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
00184       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00185       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00186       0 },
00187     // koi8-ru
00188     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
00189       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00190       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00191       0 },
00192     // koi8-u
00193     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
00194       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00195       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00196       0 },
00197     // koi8-r
00198     { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
00199       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00200       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00201       0 },
00202     // iso8859-7
00203     { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
00204       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00205       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00206       0 },
00207     // iso8859-8
00208     { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
00209       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00210       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00211       0 },
00212     // gb18030-0
00213     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00214       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00215       0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
00216       0 },
00217     // gb18030.2000-0
00218     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00219       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00220       0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
00221       0 },
00222     // gbk-0
00223     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00224       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00225       0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
00226       0 },
00227     // gb2312.*-0
00228     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00229       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00230       0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
00231       0 },
00232     // jisx0201*-0
00233     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00234       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00235       0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
00236       0 },
00237     // jisx0208*-0
00238     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00239       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00240       0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
00241       0 },
00242     // ksc5601*-*
00243     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00244       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00245       0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
00246       0 },
00247     // big5hkscs-0
00248     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00249       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00250       0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
00251       0 },
00252     // hkscs-1
00253     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00254       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00255       0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
00256       0 },
00257     // big5*-*
00258     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00259       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00260       0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
00261       0 },
00262     // tscii-*
00263     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00264       0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
00265       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00266       0 },
00267     // tis620*-*
00268     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00269       0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
00270       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00271       0 },
00272     // iso8859-11
00273     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00274       0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
00275       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00276       0 },
00277     // mulelao-1
00278     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00279       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00280       1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00281       0 },
00282     // ethiopic-unicode
00283     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00284       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00285       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00286       0 },
00287     // iso10646-1
00288     { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
00289       0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
00290       1, 1, 0, 1, 0, 1, 1, 0, 0, 0,
00291       0 },
00292     // unicode-*
00293     { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0,
00294       0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
00295       1, 1, 0, 1, 0, 1, 1, 0, 0, 0,
00296       0 },
00297     // *-symbol
00298     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00299       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00300       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00301       1 },
00302     // *-fontspecific
00303     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00304       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00305       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00306       1 },
00307     // fontspecific-*
00308     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00309       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00310       0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00311       1 }
00312 
00313 };
00314 
00315 // ----- end of generated code -----
00316 
00317 
00318 const int numEncodings = sizeof(xlfd_encoding) / sizeof(XlfdEncoding) - 1;
00319 
00320 int qt_xlfd_encoding_id(const char *encoding)
00321 {
00322     // qDebug("looking for encoding id for '%s'", encoding);
00323     int len = strlen(encoding);
00324     if (len < 4)
00325         return -1;
00326     unsigned int hash1 = make_tag(encoding[0], encoding[1], encoding[2], encoding[3]);
00327     const char *ch = encoding + len - 4;
00328     unsigned int hash2 = make_tag(ch[0], ch[1], ch[2], ch[3]);
00329 
00330     const XlfdEncoding *enc = xlfd_encoding;
00331     for (; enc->name; ++enc) {
00332         if ((enc->hash1 && enc->hash1 != hash1) ||
00333             (enc->hash2 && enc->hash2 != hash2))
00334             continue;
00335         // hashes match, do a compare if strings match
00336         // the enc->name can contain '*'s we have to interpret correctly
00337         const char *n = enc->name;
00338         const char *e = encoding;
00339         while (1) {
00340             // qDebug("bol: *e='%c', *n='%c'", *e, *n);
00341             if (*e == '\0') {
00342                 if (*n)
00343                     break;
00344                 // qDebug("found encoding id %d", enc->id);
00345                 return enc->id;
00346             }
00347             if (*e == *n) {
00348                 ++e;
00349                 ++n;
00350                 continue;
00351             }
00352             if (*n != '*')
00353                 break;
00354             ++n;
00355             // qDebug("skip: *e='%c', *n='%c'", *e, *n);
00356             while (*e && *e != *n)
00357                 ++e;
00358         }
00359     }
00360     // qDebug("couldn't find encoding %s", encoding);
00361     return -1;
00362 }
00363 
00364 int qt_mib_for_xlfd_encoding(const char *encoding)
00365 {
00366     int id = qt_xlfd_encoding_id(encoding);
00367     if (id != -1) return xlfd_encoding[id].mib;
00368     return 0;
00369 };
00370 
00371 int qt_encoding_id_for_mib(int mib)
00372 {
00373     const XlfdEncoding *enc = xlfd_encoding;
00374     for (; enc->name; ++enc) {
00375         if (enc->mib == mib)
00376             return enc->id;
00377     }
00378     return -1;
00379 }
00380 
00381 static const char * xlfd_for_id(int id)
00382 {
00383     // special case: -1 returns the "*-*" encoding, allowing us to do full
00384     // database population in a single X server round trip.
00385     if (id < 0 || id > numEncodings)
00386         return "*-*";
00387     return xlfd_encoding[id].name;
00388 }
00389 
00390 enum XLFDFieldNames {
00391     Foundry,
00392     Family,
00393     Weight,
00394     Slant,
00395     Width,
00396     AddStyle,
00397     PixelSize,
00398     PointSize,
00399     ResolutionX,
00400     ResolutionY,
00401     Spacing,
00402     AverageWidth,
00403     CharsetRegistry,
00404     CharsetEncoding,
00405     NFontFields
00406 };
00407 
00408 // Splits an X font name into fields separated by '-'
00409 static bool parseXFontName(char *fontName, char **tokens)
00410 {
00411     if (! fontName || fontName[0] == '0' || fontName[0] != '-') {
00412         tokens[0] = 0;
00413         return false;
00414     }
00415 
00416     int          i;
00417     ++fontName;
00418     for (i = 0; i < NFontFields && fontName && fontName[0]; ++i) {
00419         tokens[i] = fontName;
00420         for (;; ++fontName) {
00421             if (*fontName == '-')
00422                 break;
00423             if (! *fontName) {
00424                 fontName = 0;
00425                 break;
00426             }
00427         }
00428 
00429         if (fontName) *fontName++ = '\0';
00430     }
00431 
00432     if (i < NFontFields) {
00433         for (int j = i ; j < NFontFields; ++j)
00434             tokens[j] = 0;
00435         return false;
00436     }
00437 
00438     return true;
00439 }
00440 
00441 static inline bool isZero(char *x)
00442 {
00443     return (x[0] == '0' && x[1] == 0);
00444 }
00445 
00446 static inline bool isScalable(char **tokens)
00447 {
00448     return (isZero(tokens[PixelSize]) &&
00449             isZero(tokens[PointSize]) &&
00450             isZero(tokens[AverageWidth]));
00451 }
00452 
00453 static inline bool isSmoothlyScalable(char **tokens)
00454 {
00455     return (isZero(tokens[ResolutionX]) &&
00456             isZero(tokens[ResolutionY]));
00457 }
00458 
00459 static inline bool isFixedPitch(char **tokens)
00460 {
00461     return (tokens[Spacing][0] == 'm' ||
00462             tokens[Spacing][0] == 'c' ||
00463             tokens[Spacing][0] == 'M' ||
00464             tokens[Spacing][0] == 'C');
00465 }
00466 
00467 /*
00468   Fills in a font definition (QFontDef) from an XLFD (X Logical Font
00469   Description).
00470 
00471   Returns true if the the given xlfd is valid.
00472 */
00473 bool qt_fillFontDef(const QByteArray &xlfd, QFontDef *fd, int dpi)
00474 {
00475     char *tokens[NFontFields];
00476     QByteArray buffer = xlfd;
00477     if (! parseXFontName(buffer.data(), tokens))
00478         return false;
00479 
00480     capitalize(tokens[Family]);
00481     capitalize(tokens[Foundry]);
00482 
00483     fd->family = QString::fromLatin1(tokens[Family]);
00484     QString foundry = QString::fromLatin1(tokens[Foundry]);
00485     if (! foundry.isEmpty() && foundry != QString::fromLatin1("*"))
00486         fd->family +=
00487             QString::fromLatin1(" [") + foundry + QString::fromLatin1("]");
00488 
00489     if (qstrlen(tokens[AddStyle]) > 0)
00490         fd->addStyle = QString::fromLatin1(tokens[AddStyle]);
00491     else
00492         fd->addStyle.clear();
00493 
00494     fd->pointSize = atoi(tokens[PointSize])/10.;
00495     fd->styleHint = QFont::AnyStyle;        // ### any until we match families
00496 
00497     char slant = tolower((uchar) tokens[Slant][0]);
00498     fd->style = (slant == 'o' ? QFont::StyleOblique : (slant == 'i' ? QFont::StyleItalic : QFont::StyleNormal));
00499     char fixed = tolower((uchar) tokens[Spacing][0]);
00500     fd->fixedPitch = (fixed == 'm' || fixed == 'c');
00501     fd->weight = getFontWeight(QLatin1String(tokens[Weight]));
00502 
00503     int r = atoi(tokens[ResolutionY]);
00504     fd->pixelSize = atoi(tokens[PixelSize]);
00505     // not "0" or "*", or required DPI
00506     if (r && fd->pixelSize && r != dpi) {
00507         // calculate actual pointsize for display DPI
00508         fd->pointSize = qt_pointSize(fd->pixelSize, dpi);
00509     } else if (fd->pixelSize == 0 && fd->pointSize) {
00510         // calculate pixel size from pointsize/dpi
00511         fd->pixelSize = qRound(qt_pixelSize(fd->pointSize, dpi));
00512     }
00513 
00514     return true;
00515 }
00516 
00517 /*
00518   Fills in a font definition (QFontDef) from the font properties in an
00519   XFontStruct.
00520 
00521   Returns true if the QFontDef could be filled with properties from
00522   the XFontStruct.
00523 */
00524 static bool qt_fillFontDef(XFontStruct *fs, QFontDef *fd, int dpi)
00525 {
00526     unsigned long value;
00527     if (!fs || !XGetFontProperty(fs, XA_FONT, &value))
00528         return false;
00529 
00530     char *n = XGetAtomName(QX11Info::display(), value);
00531     QByteArray xlfd(n);
00532     if (n)
00533         XFree(n);
00534     return qt_fillFontDef(xlfd.toLower(), fd, dpi);
00535 }
00536 
00537 
00538 static QtFontStyle::Key getStyle(char ** tokens)
00539 {
00540     QtFontStyle::Key key;
00541 
00542     char slant0 = tolower((uchar) tokens[Slant][0]);
00543 
00544     if (slant0 == 'r') {
00545         if (tokens[Slant][1]) {
00546             char slant1 = tolower((uchar) tokens[Slant][1]);
00547 
00548             if (slant1 == 'o')
00549                 key.style = QFont::StyleOblique;
00550             else if (slant1 == 'i')
00551                 key.style = QFont::StyleItalic;
00552         }
00553     } else if (slant0 == 'o')
00554         key.style = QFont::StyleOblique;
00555     else if (slant0 == 'i')
00556         key.style = QFont::StyleItalic;
00557 
00558     key.weight = getFontWeight(QLatin1String(tokens[Weight]));
00559 
00560     if (qstrcmp(tokens[Width], "normal") == 0) {
00561         key.stretch = 100;
00562     } else if (qstrcmp(tokens[Width], "semi condensed") == 0 ||
00563                qstrcmp(tokens[Width], "semicondensed") == 0) {
00564         key.stretch = 90;
00565     } else if (qstrcmp(tokens[Width], "condensed") == 0) {
00566         key.stretch = 80;
00567     } else if (qstrcmp(tokens[Width], "narrow") == 0) {
00568         key.stretch = 60;
00569     }
00570 
00571     return key;
00572 }
00573 
00574 
00575 static bool xlfdsFullyLoaded = false;
00576 static unsigned char encodingLoaded[numEncodings];
00577 
00578 static void loadXlfds(const char *reqFamily, int encoding_id)
00579 {
00580     QFontDatabasePrivate *db = privateDb();
00581     QtFontFamily *fontFamily = reqFamily ? db->family(QLatin1String(reqFamily)) : 0;
00582 
00583     // make sure we don't load twice
00584     if ((encoding_id == -1 && xlfdsFullyLoaded)
00585         || (encoding_id != -1 && encodingLoaded[encoding_id]))
00586         return;
00587     if (fontFamily && fontFamily->xlfdLoaded)
00588         return;
00589 
00590     int fontCount;
00591     // force the X server to give us XLFDs
00592     QByteArray xlfd_pattern("-*-");
00593     xlfd_pattern += (reqFamily && reqFamily[0] != '\0') ? reqFamily : "*";
00594     xlfd_pattern += "-*-*-*-*-*-*-*-*-*-*-";
00595     xlfd_pattern += xlfd_for_id(encoding_id);
00596 
00597     char **fontList = XListFonts(QX11Info::display(),
00598                                  xlfd_pattern,
00599                                  0xffff, &fontCount);
00600     // qDebug("requesting xlfd='%s', got %d fonts", xlfd_pattern.data(), fontCount);
00601 
00602 
00603     char *tokens[NFontFields];
00604 
00605     for(int i = 0 ; i < fontCount ; i++) {
00606         if (! parseXFontName(fontList[i], tokens))
00607             continue;
00608 
00609         // get the encoding_id for this xlfd.  we need to do this
00610         // here, since we can pass -1 to this function to do full
00611         // database population
00612         *(tokens[CharsetEncoding] - 1) = '-';
00613         int encoding_id = qt_xlfd_encoding_id(tokens[CharsetRegistry]);
00614         if (encoding_id == -1)
00615             continue;
00616 
00617         char *familyName = tokens[Family];
00618         capitalize(familyName);
00619         char *foundryName = tokens[Foundry];
00620         capitalize(foundryName);
00621         QtFontStyle::Key styleKey = getStyle(tokens);
00622 
00623         bool smooth_scalable = false;
00624         bool bitmap_scalable = false;
00625         if (isScalable(tokens)) {
00626             if (isSmoothlyScalable(tokens))
00627                 smooth_scalable = true;
00628             else
00629                 bitmap_scalable = true;
00630         }
00631         uint pixelSize = atoi(tokens[PixelSize]);
00632         uint xpointSize = atoi(tokens[PointSize]);
00633         uint xres = atoi(tokens[ResolutionX]);
00634         uint yres = atoi(tokens[ResolutionY]);
00635         uint avgwidth = atoi(tokens[AverageWidth]);
00636         bool fixedPitch = isFixedPitch(tokens);
00637 
00638         if (avgwidth == 0 && pixelSize != 0) {
00639             /*
00640               Ignore bitmap scalable fonts that are automatically
00641               generated by some X servers.  We know they are bitmap
00642               scalable because even though they have a specified pixel
00643               size, the average width is zero.
00644             */
00645             continue;
00646         }
00647 
00648         QtFontFamily *family = fontFamily ? fontFamily : db->family(QLatin1String(familyName), true);
00649         family->fontFileIndex = -1;
00650         family->symbol_checked = true;
00651         QtFontFoundry *foundry = family->foundry(QLatin1String(foundryName), true);
00652         QtFontStyle *style = foundry->style(styleKey, true);
00653 
00654         delete [] style->weightName;
00655         style->weightName = qstrdup(tokens[Weight]);
00656         delete [] style->setwidthName;
00657         style->setwidthName = qstrdup(tokens[Width]);
00658 
00659         if (smooth_scalable) {
00660             style->smoothScalable = true;
00661             style->bitmapScalable = false;
00662             pixelSize = SMOOTH_SCALABLE;
00663         }
00664         if (!style->smoothScalable && bitmap_scalable)
00665             style->bitmapScalable = true;
00666         if (!fixedPitch)
00667             family->fixedPitch = false;
00668 
00669         QtFontSize *size = style->pixelSize(pixelSize, true);
00670         QtFontEncoding *enc =
00671             size->encodingID(encoding_id, xpointSize, xres, yres, avgwidth, true);
00672         enc->pitch = *tokens[Spacing];
00673         if (!enc->pitch) enc->pitch = '*';
00674 
00675         for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
00676             if (writingSystems_for_xlfd_encoding[encoding_id][i])
00677                 family->writingSystems[i] = QtFontFamily::Supported;
00678         }
00679     }
00680     if (!reqFamily) {
00681         // mark encoding as loaded
00682         if (encoding_id == -1)
00683             xlfdsFullyLoaded = true;
00684         else
00685             encodingLoaded[encoding_id] = true;
00686     }
00687 
00688     XFreeFontNames(fontList);
00689 }
00690 
00691 
00692 #ifndef QT_NO_FONTCONFIG
00693 
00694 #ifndef FC_WIDTH
00695 #define FC_WIDTH "width"
00696 #endif
00697 
00698 static int getFCWeight(int fc_weight)
00699 {
00700     int qtweight = QFont::Black;
00701     if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2)
00702         qtweight = QFont::Light;
00703     else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2)
00704         qtweight = QFont::Normal;
00705     else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2)
00706         qtweight = QFont::DemiBold;
00707     else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2)
00708         qtweight = QFont::Bold;
00709 
00710     return qtweight;
00711 }
00712 
00713 QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &request)
00714 {
00715     QFontDef fontDef;
00716 
00717     FcChar8 *value = 0;
00718     if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) == FcResultMatch) {
00719         fontDef.family = QString::fromUtf8(reinterpret_cast<const char *>(value));
00720         fontDef.family.replace(QLatin1Char('-'), QLatin1Char(' '));
00721         fontDef.family.remove(QLatin1Char('/'));
00722     }
00723 
00724     double dpi;
00725     if (FcPatternGetDouble(pattern, FC_DPI, 0, &dpi) != FcResultMatch)
00726         dpi = QX11Info::appDpiY();
00727 
00728     double size;
00729     if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
00730         fontDef.pixelSize = qRound(size);
00731     else
00732         fontDef.pixelSize = 12;
00733 
00734     fontDef.pointSize = qt_pointSize(fontDef.pixelSize, qRound(dpi));
00735 
00736     /* ###
00737        fontDef.styleStrategy
00738        fontDef.styleHint
00739     */
00740 
00741     int weight;
00742     if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight) != FcResultMatch)
00743         weight = FC_WEIGHT_MEDIUM;
00744     fontDef.weight = getFCWeight(weight);
00745 
00746     int slant;
00747     if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant) != FcResultMatch)
00748         slant = FC_SLANT_ROMAN;
00749     fontDef.style = (slant == FC_SLANT_ITALIC)
00750                     ? QFont::StyleItalic
00751                     : ((slant == FC_SLANT_OBLIQUE)
00752                        ? QFont::StyleOblique
00753                        : QFont::StyleNormal);
00754 
00755 
00756     FcBool scalable;
00757     if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch)
00758         scalable = false;
00759     if (scalable) {
00760         fontDef.stretch = request.stretch;
00761         fontDef.style = request.style;
00762     } else {
00763         int width;
00764         if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width) == FcResultMatch)
00765             fontDef.stretch = width;
00766         else
00767             fontDef.stretch = 100;
00768     }
00769 
00770     int spacing;
00771     if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing) == FcResultMatch) {
00772         fontDef.fixedPitch = (spacing >= FC_MONO);
00773         fontDef.ignorePitch = false;
00774     } else {
00775         fontDef.ignorePitch = true;
00776     }
00777 
00778     return fontDef;
00779 }
00780 
00781 static const char *specialLanguages[] = {
00782     "en", // Common
00783     "el", // Greek
00784     "ru", // Cyrillic
00785     "hy", // Armenian
00786     "he", // Hebrew
00787     "ar", // Arabic
00788     "syr", // Syriac
00789     "div", // Thaana
00790     "hi", // Devanagari
00791     "bn", // Bengali
00792     "pa", // Gurmukhi
00793     "gu", // Gujarati
00794     "or", // Oriya
00795     "ta", // Tamil
00796     "te", // Telugu
00797     "kn", // Kannada
00798     "ml", // Malayalam
00799     "si", // Sinhala
00800     "th", // Thai
00801     "lo", // Lao
00802     "bo", // Tibetan
00803     "my", // Myanmar
00804     "ka", // Georgian
00805     "ko", // Hangul
00806     "", // Ogham
00807     "", // Runic
00808     "km" // Khmer
00809 };
00810 enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) };
00811 
00812 static ushort specialChars[] = {
00813     0, // English
00814     0, // Greek
00815     0, // Cyrillic
00816     0, // Armenian
00817     0, // Hebrew
00818     0, // Arabic
00819     0, // Syriac
00820     0, // Thaana
00821     0, // Devanagari
00822     0, // Bengali
00823     0, // Gurmukhi
00824     0, // Gujarati
00825     0, // Oriya
00826     0, // Tamil
00827     0xc15, // Telugu
00828     0xc95, // Kannada
00829     0xd15, // Malayalam
00830     0xd9a, // Sinhala
00831     0, // Thai
00832     0, // Lao
00833     0, // Tibetan
00834     0x1000, // Myanmar
00835     0, // Georgian
00836     0, // Hangul
00837     0x1681, // Ogham
00838     0x16a0, // Runic
00839     0  // Khmer
00840 };
00841 enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) };
00842 
00843 // this could become a list of all languages used for each writing
00844 // system, instead of using the single most common language.
00845 static const char *languageForWritingSystem[] = {
00846     0,     // Any
00847     "en",  // Latin
00848     "el",  // Greek
00849     "ru",  // Cyrillic
00850     "hy",  // Armenian
00851     "he",  // Hebrew
00852     "ar",  // Arabic
00853     "syr", // Syriac
00854     "div", // Thaana
00855     "hi",  // Devanagari
00856     "bn",  // Bengali
00857     "pa",  // Gurmukhi
00858     "gu",  // Gujarati
00859     "or",  // Oriya
00860     "ta",  // Tamil
00861     "te",  // Telugu
00862     "kn",  // Kannada
00863     "ml",  // Malayalam
00864     "si",  // Sinhala
00865     "th",  // Thai
00866     "lo",  // Lao
00867     "bo",  // Tibetan
00868     "my",  // Myanmar
00869     "ka",  // Georgian
00870     "km",  // Khmer
00871     "zh-cn", // SimplifiedChinese
00872     "zh-tw", // TraditionalChinese
00873     "ja",  // Japanese
00874     "ko",  // Korean
00875     "vi",  // Vietnamese
00876     0, // Symbol
00877     0, // Ogham
00878     0 // Runic
00879 };
00880 enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) };
00881 
00882 // Unfortunately FontConfig doesn't know about some languages. We have to test these through the
00883 // charset. The lists below contain the systems where we need to do this.
00884 static const ushort sampleCharForWritingSystem[] = {
00885     0,     // Any
00886     0,  // Latin
00887     0,  // Greek
00888     0,  // Cyrillic
00889     0,  // Armenian
00890     0,  // Hebrew
00891     0,  // Arabic
00892     0, // Syriac
00893     0, // Thaana
00894     0,  // Devanagari
00895     0,  // Bengali
00896     0,  // Gurmukhi
00897     0,  // Gujarati
00898     0,  // Oriya
00899     0,  // Tamil
00900     0xc15,  // Telugu
00901     0xc95,  // Kannada
00902     0xd15,  // Malayalam
00903     0xd9a,  // Sinhala
00904     0,  // Thai
00905     0,  // Lao
00906     0,  // Tibetan
00907     0x1000,  // Myanmar
00908     0,  // Georgian
00909     0,  // Khmer
00910     0, // SimplifiedChinese
00911     0, // TraditionalChinese
00912     0,  // Japanese
00913     0,  // Korean
00914     0,  // Vietnamese
00915     0, // Symbol
00916     0x1681, // Ogham
00917     0x16a0 // Runic
00918 };
00919 enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) };
00920 
00921 // Newer FontConfig let's us sort out fonts that contain certain glyphs, but no
00922 // open type tables for is directly. Do this so we don't pick some strange
00923 // pseudo unicode font
00924 static const char *openType[] = {
00925     0,     // Any
00926     0,  // Latin
00927     0,  // Greek
00928     0,  // Cyrillic
00929     0,  // Armenian
00930     0,  // Hebrew
00931     0,  // Arabic
00932     "syrc",  // Syriac
00933     "thaa",  // Thaana
00934     "deva",  // Devanagari
00935     "beng",  // Bengali
00936     "guru",  // Gurmukhi
00937     "gurj",  // Gujarati
00938     "orya",  // Oriya
00939     "taml",  // Tamil
00940     "telu",  // Telugu
00941     "knda",  // Kannada
00942     "mlym",  // Malayalam
00943     "sinh",  // Sinhala
00944     0,  // Thai
00945     0,  // Lao
00946     "tibt",  // Tibetan
00947     "mymr",  // Myanmar
00948     0,  // Georgian
00949     "khmr",  // Khmer
00950     0, // SimplifiedChinese
00951     0, // TraditionalChinese
00952     0,  // Japanese
00953     0,  // Korean
00954     0,  // Vietnamese
00955     0, // Symbol
00956     0, // Ogham
00957     0 // Runic
00958 };
00959 enum { OpenTypeCount = sizeof(openType) / sizeof(const char *) };
00960 
00961 
00962 static void loadFontConfig()
00963 {
00964     Q_ASSERT_X(X11, "QFontDatabase",
00965                "A QApplication object needs to be constructed before FontConfig is used.");
00966     if (!X11->has_fontconfig)
00967         return;
00968 
00969     Q_ASSERT_X(int(QUnicodeTables::ScriptCount) == SpecialLanguageCount,
00970                "QFontDatabase", "New scripts have been added.");
00971     Q_ASSERT_X(int(QUnicodeTables::ScriptCount) == SpecialCharCount,
00972                "QFontDatabase", "New scripts have been added.");
00973     Q_ASSERT_X(int(QFontDatabase::WritingSystemsCount) == LanguageCount,
00974                "QFontDatabase", "New writing systems have been added.");
00975     Q_ASSERT_X(int(QFontDatabase::WritingSystemsCount) == SampleCharCount,
00976                "QFontDatabase", "New writing systems have been added.");
00977     Q_ASSERT_X(int(QFontDatabase::WritingSystemsCount) == OpenTypeCount,
00978                "QFontDatabase", "New writing systems have been added.");
00979 
00980     QFontDatabasePrivate *db = privateDb();
00981     FcFontSet  *fonts;
00982 
00983     QString familyName;
00984     QString rawName;
00985     FcChar8 *value = 0;
00986     int weight_value;
00987     int slant_value;
00988     int spacing_value;
00989     FcChar8 *file_value;
00990     int index_value;
00991     FcChar8 *foundry_value;
00992     FcBool scalable;
00993 
00994     {
00995         FcObjectSet *os = FcObjectSetCreate();
00996         FcPattern *pattern = FcPatternCreate();
00997         const char *properties [] = {
00998             FC_FAMILY, FC_WEIGHT, FC_SLANT,
00999             FC_SPACING, FC_FILE, FC_INDEX,
01000             FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT,
01001             FC_WIDTH,
01002 #if FC_VERSION >= 20297
01003             FC_CAPABILITY,
01004 #endif
01005             (const char *)0
01006         };
01007         const char **p = properties;
01008         while (*p) {
01009             FcObjectSetAdd(os, *p);
01010             ++p;
01011         }
01012         fonts = FcFontList(0, pattern, os);
01013         FcObjectSetDestroy(os);
01014         FcPatternDestroy(pattern);
01015     }
01016 
01017     for (int i = 0; i < fonts->nfont; i++) {
01018         if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch)
01019             continue;
01020         //         capitalize(value);
01021         rawName = familyName = QString::fromUtf8((const char *)value);
01022         familyName.replace(QLatin1Char('-'), QLatin1Char(' '));
01023         familyName.remove(QLatin1Char('/'));
01024         slant_value = FC_SLANT_ROMAN;
01025         weight_value = FC_WEIGHT_MEDIUM;
01026         spacing_value = FC_PROPORTIONAL;
01027   file_value = 0;
01028   index_value = 0;
01029   scalable = FcTrue;
01030 
01031         if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch)
01032       slant_value = FC_SLANT_ROMAN;
01033         if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch)
01034       weight_value = FC_WEIGHT_MEDIUM;
01035         if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch)
01036       spacing_value = FC_PROPORTIONAL;
01037         if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch)
01038       file_value = 0;
01039         if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &index_value) != FcResultMatch)
01040       index_value = 0;
01041         if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch)
01042       scalable = FcTrue;
01043         if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
01044       foundry_value = 0;
01045         QtFontFamily *family = db->family(familyName, true);
01046         family->rawName = rawName;
01047 
01048         FcLangSet *langset = 0;
01049         FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset);
01050         if (res == FcResultMatch) {
01051             for (int i = 1; i < LanguageCount; ++i) {
01052                 const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i];
01053                 if (!lang) {
01054                     family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
01055                 } else {
01056                     FcLangResult langRes = FcLangSetHasLang(langset, lang);
01057                     if (langRes != FcLangDifferentLang)
01058                         family->writingSystems[i] = QtFontFamily::Supported;
01059                     else
01060                         family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
01061                 }
01062             }
01063             family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
01064             family->ftWritingSystemCheck = true;
01065         } else {
01066             // we set Other to supported for symbol fonts. It makes no
01067             // sense to merge these with other ones, as they are
01068             // special in a way.
01069             for (int i = 1; i < LanguageCount; ++i)
01070                 family->writingSystems[i] |= QtFontFamily::UnsupportedFT;
01071             family->writingSystems[QFontDatabase::Other] = QtFontFamily::Supported;
01072         }
01073 
01074         FcCharSet *cs = 0;
01075         res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs);
01076         if (res == FcResultMatch) {
01077             // some languages are not supported by FontConfig, we rather check the
01078             // charset to detect these
01079             for (int i = 1; i < SampleCharCount; ++i) {
01080                 if (!sampleCharForWritingSystem[i])
01081                     continue;
01082                 if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i]))
01083                     family->writingSystems[i] = QtFontFamily::Supported;
01084             }
01085         }
01086 
01087 #if FC_VERSION >= 20297
01088         for (int j = 1; j < LanguageCount; ++j) {
01089             if (family->writingSystems[j] == QtFontFamily::Supported && requiresOpenType(j) && openType[j]) {
01090                 FcChar8 *cap;
01091                 res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap);
01092                 if (res != FcResultMatch || !strstr((const char *)cap, openType[j]))
01093                     family->writingSystems[j] = QtFontFamily::UnsupportedFT;
01094             }
01095         }
01096 #endif
01097 
01098         QByteArray file((const char *)file_value);
01099         family->fontFilename = file;
01100         family->fontFileIndex = index_value;
01101 
01102         QtFontStyle::Key styleKey;
01103         styleKey.style = (slant_value == FC_SLANT_ITALIC)
01104                          ? QFont::StyleItalic
01105                          : ((slant_value == FC_SLANT_OBLIQUE)
01106                             ? QFont::StyleOblique
01107                             : QFont::StyleNormal);
01108         styleKey.weight = getFCWeight(weight_value);
01109         if (!scalable) {
01110             int width = 100;
01111             FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width);
01112             styleKey.stretch = width;
01113         }
01114 
01115         QtFontFoundry *foundry
01116             = family->foundry(foundry_value ? QString::fromUtf8((const char *)foundry_value) : QString(), true);
01117         QtFontStyle *style = foundry->style(styleKey, true);
01118 
01119         if (spacing_value < FC_MONO)
01120             family->fixedPitch = false;
01121 
01122         QtFontSize *size;
01123         if (scalable) {
01124             style->smoothScalable = true;
01125             size = style->pixelSize(SMOOTH_SCALABLE, true);
01126         } else {
01127             double pixel_size = 0;
01128             FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size);
01129             size = style->pixelSize((int)pixel_size, true);
01130         }
01131         QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
01132         enc->pitch = (spacing_value >= FC_CHARCELL ? 'c' :
01133                       (spacing_value >= FC_MONO ? 'm' : 'p'));
01134     }
01135 
01136     FcFontSetDestroy (fonts);
01137 
01138     struct FcDefaultFont {
01139         const char *qtname;
01140         const char *rawname;
01141         bool fixed;
01142     };
01143     const FcDefaultFont defaults[] = {
01144         { "Serif", "serif", false },
01145         { "Sans Serif", "sans-serif", false },
01146         { "Monospace", "monospace", true },
01147         { 0, 0, false }
01148     };
01149     const FcDefaultFont *f = defaults;
01150     while (f->qtname) {
01151         QtFontFamily *family = db->family(QLatin1String(f->qtname), true);
01152         family->fixedPitch = f->fixed;
01153         family->rawName = QLatin1String(f->rawname);
01154         family->synthetic = true;
01155         QtFontFoundry *foundry = family->foundry(QString(), true);
01156 
01157         // aliases only make sense for 'common', not for any of the specials
01158         for (int i = 1; i < LanguageCount; ++i) {
01159             if (requiresOpenType(i))
01160                 family->writingSystems[i] = QtFontFamily::UnsupportedFT;
01161             else
01162                 family->writingSystems[i] = QtFontFamily::Supported;
01163         }
01164         family->writingSystems[QFontDatabase::Other] = QtFontFamily::UnsupportedFT;
01165 
01166         QtFontStyle::Key styleKey;
01167         for (int i = 0; i < 4; ++i) {
01168             styleKey.style = (i%2) ? QFont::StyleNormal : QFont::StyleItalic;
01169             styleKey.weight = (i > 1) ? QFont::Bold : QFont::Normal;
01170             QtFontStyle *style = foundry->style(styleKey, true);
01171             style->smoothScalable = true;
01172             QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE, true);
01173             QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
01174             enc->pitch = (f->fixed ? 'm' : 'p');
01175         }
01176         ++f;
01177     }
01178 }
01179 #endif // QT_NO_FONTCONFIG
01180 
01181 static void initializeDb();
01182 
01183 static void load(const QString &family = QString(), int script = -1)
01184 {
01185     if (X11->has_fontconfig) {
01186         initializeDb();
01187         return;
01188     }
01189 
01190 #ifdef QFONTDATABASE_DEBUG
01191     QTime t;
01192     t.start();
01193 #endif
01194 
01195     if (family.isNull() && script == -1) {
01196         loadXlfds(0, -1);
01197     } else {
01198         if (family.isNull()) {
01199             // load all families in all writing systems that match \a script
01200             for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) {
01201                 if (scriptForWritingSystem[ws] != script)
01202                     continue;
01203                 for (int i = 0; i < numEncodings; ++i) {
01204                     if (writingSystems_for_xlfd_encoding[i][ws])
01205                         loadXlfds(0, i);
01206                 }
01207             }
01208         } else {
01209             QtFontFamily *f = privateDb()->family(family);
01210             // could reduce this further with some more magic:
01211             // would need to remember the encodings loaded for the family.
01212             if (!f || !f->xlfdLoaded)
01213                 loadXlfds(family.toLatin1(), -1);
01214         }
01215     }
01216 
01217 #ifdef QFONTDATABASE_DEBUG
01218     FD_DEBUG("QFontDatabase: load(%s, %d) took %d ms",
01219              family.toLatin1().constData(), script, t.elapsed());
01220 #endif
01221 }
01222 
01223 static void checkSymbolFont(QtFontFamily *family)
01224 {
01225     if (!family || family->symbol_checked || family->fontFilename.isEmpty())
01226         return;
01227 //     qDebug() << "checking " << family->rawName;
01228     family->symbol_checked = true;
01229 
01230     extern FT_Library qt_getFreetype();
01231     FT_Library library = qt_getFreetype();
01232 
01233     FT_Face face;
01234     FT_Error err = FT_New_Face(library, family->fontFilename, family->fontFileIndex, &face);
01235     if (err != FT_Err_Ok) {
01236         qWarning("checkSymbolFonts: Couldn't open face %s (%s/%d)",
01237                  qPrintable(family->rawName), family->fontFilename.data(), family->fontFileIndex);
01238         return;
01239     }
01240     for (int i = 0; i < face->num_charmaps; ++i) {
01241         FT_CharMap cm = face->charmaps[i];
01242         if (cm->encoding == ft_encoding_adobe_custom
01243             || cm->encoding == ft_encoding_symbol) {
01244             for (int x = QFontDatabase::Latin; x < QFontDatabase::Other; ++x)
01245                 family->writingSystems[x] = QtFontFamily::Unsupported;
01246             family->writingSystems[QFontDatabase::Other] = QtFontFamily::Supported;
01247             break;
01248         }
01249     }
01250 
01251     FT_Done_Face(face);
01252 }
01253 
01254 static void checkSymbolFonts(const QString &family = QString())
01255 {
01256 #ifndef QT_NO_FONTCONFIG
01257     QFontDatabasePrivate *d = privateDb();
01258 
01259     if (family.isEmpty()) {
01260         for (int i = 0; i < d->count; ++i)
01261             checkSymbolFont(d->families[i]);
01262     } else {
01263         checkSymbolFont(d->family(family));
01264     }
01265 #endif
01266 }
01267 
01268 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
01269 
01270 static void initializeDb()
01271 {
01272     QFontDatabasePrivate *db = privateDb();
01273     if (!db || db->count)
01274         return;
01275 
01276     QTime t;
01277     t.start();
01278 
01279 #ifndef QT_NO_FONTCONFIG
01280     if (db->reregisterAppFonts) {
01281         db->reregisterAppFonts = false;
01282         for (int i = 0; i < db->applicationFonts.count(); ++i)
01283             if (!db->applicationFonts.at(i).families.isEmpty()) {
01284                 registerFont(&db->applicationFonts[i]);
01285             }
01286     }
01287 
01288     loadFontConfig();
01289     FD_DEBUG("QFontDatabase: loaded FontConfig: %d ms", t.elapsed());
01290 #endif
01291 
01292     t.start();
01293 
01294 #ifndef QT_NO_FONTCONFIG
01295     for (int i = 0; i < db->count; i++) {
01296         for (int j = 0; j < db->families[i]->count; ++j) {        // each foundry
01297             QtFontFoundry *foundry = db->families[i]->foundries[j];
01298             for (int k = 0; k < foundry->count; ++k) {
01299                 QtFontStyle *style = foundry->styles[k];
01300                 if (style->key.style != QFont::StyleNormal) continue;
01301 
01302                 QtFontSize *size = style->pixelSize(SMOOTH_SCALABLE);
01303                 if (! size) continue; // should not happen
01304                 QtFontEncoding *enc = size->encodingID(-1, 0, 0, 0, 0, true);
01305                 if (! enc) continue; // should not happen either
01306 
01307                 QtFontStyle::Key key = style->key;
01308 
01309                 // does this style have an italic equivalent?
01310                 key.style = QFont::StyleItalic;
01311                 QtFontStyle *equiv = foundry->style(key);
01312                 if (equiv) continue;
01313 
01314                 // does this style have an oblique equivalent?
01315                 key.style = QFont::StyleOblique;
01316                 equiv = foundry->style(key);
01317                 if (equiv) continue;
01318 
01319                 // let's fake one...
01320                 equiv = foundry->style(key, true);
01321                 equiv->smoothScalable = true;
01322 
01323                 QtFontSize *equiv_size = equiv->pixelSize(SMOOTH_SCALABLE, true);
01324                 QtFontEncoding *equiv_enc = equiv_size->encodingID(-1, 0, 0, 0, 0, true);
01325 
01326                 // keep the same pitch
01327                 equiv_enc->pitch = enc->pitch;
01328             }
01329         }
01330     }
01331 #endif
01332 
01333 
01334 #ifdef QFONTDATABASE_DEBUG
01335 #ifndef QT_NO_FONTCONFIG
01336     if (!X11->has_fontconfig)
01337 #endif
01338         // load everything at startup in debug mode.
01339         loadXlfds(0, -1);
01340 
01341     // print the database
01342     for (int f = 0; f < db->count; f++) {
01343         QtFontFamily *family = db->families[f];
01344         FD_DEBUG("'%s' %s  fixed=%s", family->name.latin1(), (family->fixedPitch ? "fixed" : ""),
01345                  (family->fixedPitch ? "yes" : "no"));
01346         for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
01347             QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
01348             FD_DEBUG("\t%s: %s", QFontDatabase::writingSystemName(ws).toLatin1().constData(),
01349                      ((family->writingSystems[i] & QtFontFamily::Supported) ? "Supported" :
01350                       (family->writingSystems[i] & QtFontFamily::Unsupported) == QtFontFamily::Unsupported ?
01351                       "Unsupported" : "Unknown"));
01352         }
01353 
01354         for (int fd = 0; fd < family->count; fd++) {
01355             QtFontFoundry *foundry = family->foundries[fd];
01356             FD_DEBUG("\t\t'%s'", foundry->name.latin1());
01357             for (int s = 0; s < foundry->count; s++) {
01358                 QtFontStyle *style = foundry->styles[s];
01359                 FD_DEBUG("\t\t\tstyle: style=%d weight=%d (%s)\n"
01360                          "\t\t\tstretch=%d (%s)",
01361                          style->key.style, style->key.weight,
01362                          style->weightName, style->key.stretch,
01363                          style->setwidthName ? style->setwidthName : "nil");
01364                 if (style->smoothScalable)
01365                     FD_DEBUG("\t\t\t\tsmooth scalable");
01366                 else if (style->bitmapScalable)
01367                     FD_DEBUG("\t\t\t\tbitmap scalable");
01368                 if (style->pixelSizes) {
01369                     qDebug("\t\t\t\t%d pixel sizes", style->count);
01370                     for (int z = 0; z < style->count; ++z) {
01371                         QtFontSize *size = style->pixelSizes + z;
01372                         for (int e = 0; e < size->count; ++e) {
01373                             FD_DEBUG("\t\t\t\t  size %5d pitch %c encoding %s",
01374                                      size->pixelSize,
01375                                      size->encodings[e].pitch,
01376                                      xlfd_for_id(size->encodings[e].encoding));
01377                         }
01378                     }
01379                 }
01380             }
01381         }
01382     }
01383 #endif // QFONTDATABASE_DEBUG
01384 }
01385 
01386 
01387 // --------------------------------------------------------------------------------------
01388 // font loader
01389 // --------------------------------------------------------------------------------------
01390 
01391 static const char *styleHint(const QFontDef &request)
01392 {
01393     const char *stylehint = 0;
01394     switch (request.styleHint) {
01395     case QFont::SansSerif:
01396         stylehint = "sans-serif";
01397         break;
01398     case QFont::Serif:
01399         stylehint = "serif";
01400         break;
01401     case QFont::TypeWriter:
01402         stylehint = "monospace";
01403         break;
01404     default:
01405         if (request.fixedPitch)
01406             stylehint = "monospace";
01407         break;
01408     }
01409     return stylehint;
01410 }
01411 
01412 #ifndef QT_NO_FONTCONFIG
01413 
01414 void qt_addPatternProps(FcPattern *pattern, int screen, int script, const QFontDef &request)
01415 {
01416     int weight_value = FC_WEIGHT_BLACK;
01417     if (request.weight == 0)
01418         weight_value = FC_WEIGHT_MEDIUM;
01419     else if (request.weight < (QFont::Light + QFont::Normal) / 2)
01420         weight_value = FC_WEIGHT_LIGHT;
01421     else if (request.weight < (QFont::Normal + QFont::DemiBold) / 2)
01422         weight_value = FC_WEIGHT_MEDIUM;
01423     else if (request.weight < (QFont::DemiBold + QFont::Bold) / 2)
01424         weight_value = FC_WEIGHT_DEMIBOLD;
01425     else if (request.weight < (QFont::Bold + QFont::Black) / 2)
01426         weight_value = FC_WEIGHT_BOLD;
01427     FcPatternAddInteger(pattern, FC_WEIGHT, weight_value);
01428 
01429     int slant_value = FC_SLANT_ROMAN;
01430     if (request.style == QFont::StyleItalic)
01431         slant_value = FC_SLANT_ITALIC;
01432     else if (request.style == QFont::StyleOblique)
01433         slant_value = FC_SLANT_OBLIQUE;
01434     FcPatternAddInteger(pattern, FC_SLANT, slant_value);
01435 
01436     double size_value = request.pixelSize;
01437     FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size_value);
01438 
01439     int stretch = request.stretch;
01440     if (!stretch)
01441         stretch = 100;
01442     FcPatternAddInteger(pattern, FC_WIDTH, stretch);
01443 
01444     if (QX11Info::appDepth(screen) <= 8) {
01445         // can't do antialiasing on 8bpp
01446         FcPatternAddBool(pattern, FC_ANTIALIAS, false);
01447     } else if (request.styleStrategy & (QFont::PreferAntialias|QFont::NoAntialias)) {
01448         FcPatternAddBool(pattern, FC_ANTIALIAS,
01449                          !(request.styleStrategy & QFont::NoAntialias));
01450     }
01451 
01452     if (script != QUnicodeTables::Common) {
01453         Q_ASSERT(script < QUnicodeTables::ScriptCount);
01454         FcLangSet *ls = FcLangSetCreate();
01455         FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]);
01456         FcPatternAddLangSet(pattern, FC_LANG, ls);
01457         FcLangSetDestroy(ls);
01458     }
01459 }
01460 
01461 static bool preferScalable(const QFontDef &request)
01462 {
01463     return request.styleStrategy & (QFont::PreferOutline|QFont::ForceOutline|QFont::PreferQuality|QFont::PreferAntialias);
01464 }
01465 
01466 
01467 static FcPattern *getFcPattern(const QFontPrivate *fp, int script, const QFontDef &request)
01468 {
01469     if (!X11->has_fontconfig)
01470         return 0;
01471 
01472     FcPattern *pattern = FcPatternCreate();
01473     if (!pattern)
01474         return 0;
01475 
01476     FcValue value;
01477     value.type = FcTypeString;
01478 
01479     QtFontDesc desc;
01480     QStringList families_and_foundries = familyList(request);
01481     for (int i = 0; i < families_and_foundries.size(); ++i) {
01482         QString family, foundry;
01483         parseFontName(families_and_foundries.at(i), foundry, family);
01484         if (!family.isEmpty()) {
01485             QByteArray cs = family.toUtf8();
01486             value.u.s = (const FcChar8 *)cs.data();
01487             FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
01488         }
01489         if (i == 0) {
01490             ::match(script, request, family, foundry, -1, &desc);
01491             if (!foundry.isEmpty()) {
01492                 QByteArray cs = foundry.toUtf8();
01493                 value.u.s = (const FcChar8 *)cs.data();
01494                 FcPatternAddWeak(pattern, FC_FOUNDRY, value, FcTrue);
01495             }
01496         }
01497     }
01498 
01499     const char *stylehint = styleHint(request);
01500     if (stylehint) {
01501         value.u.s = (const FcChar8 *)stylehint;
01502         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
01503     }
01504 
01505     if (!request.ignorePitch) {
01506         char pitch_value = FC_PROPORTIONAL;
01507         if (request.fixedPitch || (desc.family && desc.family->fixedPitch))
01508             pitch_value = FC_MONO;
01509         FcPatternAddInteger(pattern, FC_SPACING, pitch_value);
01510     }
01511     FcPatternAddBool(pattern, FC_OUTLINE, !(request.styleStrategy & QFont::PreferBitmap));
01512     if (::preferScalable(request) || (desc.style && desc.style->smoothScalable))
01513         FcPatternAddBool(pattern, FC_SCALABLE, true);
01514 
01515     qt_addPatternProps(pattern, fp->screen, script, request);
01516 
01517     FcDefaultSubstitute(pattern);
01518     FcConfigSubstitute(0, pattern, FcMatchPattern);
01519     FcConfigSubstitute(0, pattern, FcMatchFont);
01520 
01521     // these should only get added to the pattern _after_ substitution
01522     // append the default fallback font for the specified script
01523     extern QString qt_fallback_font_family(int);
01524     QString fallback = qt_fallback_font_family(script);
01525     if (!fallback.isEmpty()) {
01526         QByteArray cs = fallback.toUtf8();
01527         value.u.s = (const FcChar8 *)cs.data();
01528         FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
01529     }
01530 
01531     // add the default family
01532     QString defaultFamily = QApplication::font().family();
01533     QByteArray cs = defaultFamily.toUtf8();
01534     value.u.s = (const FcChar8 *)cs.data();
01535     FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
01536 
01537     // add QFont::defaultFamily() to the list, for compatibility with
01538     // previous versions
01539     defaultFamily = QApplication::font().defaultFamily();
01540     cs = defaultFamily.toUtf8();
01541     value.u.s = (const FcChar8 *)cs.data();
01542     FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue);
01543 
01544     return pattern;
01545 }
01546 
01547 
01548 static void FcFontSetRemove(FcFontSet *fs, int at)
01549 {
01550     Q_ASSERT(at < fs->nfont);
01551     FcPatternDestroy(fs->fonts[at]);
01552     int len = (--fs->nfont - at) * sizeof(FcPattern *);;
01553     if (len > 0)
01554         memmove(fs->fonts + at, fs->fonts + at + 1, len);
01555 }
01556 
01557 static QFontEngine *tryPatternLoad(FcPattern *p, int screen,
01558                                    const QFontDef &request, int script)
01559 {
01560 #ifdef FONT_MATCH_DEBUG
01561     FcChar8 *fam;
01562     FcPatternGetString(p, FC_FAMILY, 0, &fam);
01563     FM_DEBUG("==== trying %s\n", fam);
01564 #endif
01565     FM_DEBUG("passes charset test\n");
01566     FcPattern *pattern = FcPatternDuplicate(p);
01567     // add properties back in as the font selected from the
01568     // list doesn't contain them.
01569     qt_addPatternProps(pattern, screen, script, request);
01570 
01571     FcConfigSubstitute(0, pattern, FcMatchPattern);
01572     FcDefaultSubstitute(pattern);
01573     FcResult res;
01574     FcPattern *match = FcFontMatch(0, pattern, &res);
01575     QFontEngineFT *engine = 0;
01576 
01577     if (script != QUnicodeTables::Common) {
01578         // skip font if it doesn't support the language we want
01579         if (specialChars[script]) {
01580             // need to check the charset, as the langset doesn't work for these scripts
01581             FcCharSet *cs;
01582             if (FcPatternGetCharSet(match, FC_CHARSET, 0, &cs) != FcResultMatch)
01583                 goto done;
01584             if (!FcCharSetHasChar(cs, specialChars[script]))
01585                 goto done;
01586         } else {
01587             FcLangSet *langSet = 0;
01588             if (FcPatternGetLangSet(match, FC_LANG, 0, &langSet) != FcResultMatch)
01589                 goto done;
01590             if (FcLangSetHasLang(langSet, (const FcChar8*)specialLanguages[script]) != FcLangEqual)
01591                 goto done;
01592         }
01593     }
01594 
01595     // enforce non-antialiasing if requested. the ft font engine looks at this property.
01596     if (request.styleStrategy & QFont::NoAntialias) {
01597         FcPatternDel(match, FC_ANTIALIAS);
01598         FcPatternAddBool(match, FC_ANTIALIAS, false);
01599     }
01600 
01601     engine = new QFontEngineFT(match, qt_FcPatternToQFontDef(match, request), screen);
01602     if (engine->invalid()) {
01603         FM_DEBUG("   --> invalid!\n");
01604         delete engine;
01605         engine = 0;
01606     } else if (scriptRequiresOpenType(script)) {
01607         QOpenType *ot = engine->openType();
01608         if (!ot || !ot->supportsScript(script)) {
01609             FM_DEBUG("  OpenType support missing for script\n");
01610             delete engine;
01611             engine = 0;
01612         }
01613     }
01614 done:
01615     FcPatternDestroy(pattern);
01616     return engine;
01617 }
01618 
01619 FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request)
01620 {
01621     FcResult result;
01622     FcFontSet *fs = FcFontSort(0, pattern, FcTrue, 0, &result);
01623 #ifdef FONT_MATCH_DEBUG
01624     FM_DEBUG("first font in fontset:\n");
01625     FcPatternPrint(fs->fonts[0]);
01626 #endif
01627 
01628     FcBool forceScalable = request.styleStrategy & QFont::ForceOutline;
01629 
01630     // remove fonts if they are not scalable (and should be)
01631     if (forceScalable) {
01632         for (int i = 0; i < fs->nfont; ++i) {
01633             FcPattern *font = fs->fonts[i];
01634             FcResult res;
01635             FcBool scalable;
01636             res = FcPatternGetBool(font, FC_SCALABLE, 0, &scalable);
01637             if (res != FcResultMatch || !scalable) {
01638                 FcFontSetRemove(fs, i);
01639 #ifdef FONT_MATCH_DEBUG
01640                 FM_DEBUG("removing pattern:");
01641                 FcPatternPrint(font);
01642 #endif
01643                 --i; // go back one
01644             }
01645         }
01646     }
01647 
01648     FM_DEBUG("final pattern contains %d fonts\n", fs->nfont);
01649 
01650     return fs;
01651 }
01652 
01653 static QFontEngine *loadFc(const QFontPrivate *fp, int script, const QFontDef &request)
01654 {
01655     FM_DEBUG("===================== loadFc: script=%d family='%s'\n", script, request.family.toLatin1().data());
01656     FcPattern *pattern = getFcPattern(fp, script, request);
01657 
01658 #ifdef FONT_MATCH_DEBUG
01659     FM_DEBUG("\n\nfinal FcPattern contains:\n");
01660     FcPatternPrint(pattern);
01661 #endif
01662 
01663     QFontEngine *fe = 0;
01664     fe = tryPatternLoad(pattern, fp->screen, request, script);
01665     if (!fe) {
01666         FcFontSet *fs = qt_fontSetForPattern(pattern, request);
01667 
01668         for (int i = 0; !fe && i < fs->nfont; ++i)
01669             fe = tryPatternLoad(fs->fonts[i], fp->screen, request, script);
01670         FcFontSetDestroy(fs);
01671         FM_DEBUG("engine for script %d is %s\n", script, fe ? fe->fontDef.family.toLatin1().data(): "(null)");
01672     }
01673     if (fe
01674         && script == QUnicodeTables::Common
01675         && !(request.styleStrategy & QFont::NoFontMerging) && !fe->symbol) {
01676         fe = new QFontEngineMultiFT(fe, pattern, fp->screen, request);
01677     } else {
01678         FcPatternDestroy(pattern);
01679     }
01680     return fe;
01681 }
01682 #endif // QT_NO_FONTCONFIG
01683 
01684 static QFontEngine *loadRaw(const QFontPrivate *fp, const QFontDef &request)
01685 {
01686     Q_ASSERT(fp && fp->rawMode);
01687 
01688     QByteArray xlfd = request.family.toLatin1();
01689     FM_DEBUG("Loading XLFD (rawmode) '%s'", xlfd.data());
01690 
01691     QFontEngine *fe;
01692     XFontStruct *xfs;
01693     if (!(xfs = XLoadQueryFont(QX11Info::display(), xlfd.data())))
01694         if (!(xfs = XLoadQueryFont(QX11Info::display(), "fixed")))
01695             return 0;
01696 
01697     fe = new QFontEngineXLFD(xfs, xlfd, 0);
01698     if (! qt_fillFontDef(xfs, &fe->fontDef, fp->dpi) &&
01699         ! qt_fillFontDef(xlfd, &fe->fontDef, fp->dpi))
01700         fe->fontDef = QFontDef();
01701     return fe;
01702 }
01703 
01704 QFontEngine *QFontDatabase::loadXlfd(int screen, int script, const QFontDef &request, int force_encoding_id)
01705 {
01706     QtFontDesc desc;
01707     FM_DEBUG() << "---> loadXlfd: request is" << request.family;
01708     QStringList families_and_foundries = ::familyList(request);
01709     const char *stylehint = styleHint(request);
01710     if (stylehint)
01711         families_and_foundries << QString::fromLatin1(stylehint);
01712     families_and_foundries << QString();
01713     FM_DEBUG() << "loadXlfd: list is" << families_and_foundries;
01714     for (int i = 0; i < families_and_foundries.size(); ++i) {
01715         QString family, foundry;
01716         ::parseFontName(families_and_foundries.at(i), foundry, family);
01717         FM_DEBUG("loadXlfd: >>>>>>>>>>>>>>trying to match '%s' encoding=%d", family.toLatin1().data(), force_encoding_id);
01718         ::match(script, request, family, foundry, force_encoding_id, &desc);
01719         if (desc.family)
01720             break;
01721     }
01722 
01723     QFontEngine *fe = 0;
01724     if (force_encoding_id != -1
01725         || (request.styleStrategy & QFont::NoFontMerging)
01726         || (desc.family && desc.family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
01727         if (desc.family) {
01728             int px = desc.size->pixelSize;
01729             if (desc.style->smoothScalable && px == SMOOTH_SCALABLE)
01730                 px = request.pixelSize;
01731             else if (desc.style->bitmapScalable && px == 0)
01732                 px = request.pixelSize;
01733 
01734             QByteArray xlfd("-");
01735             xlfd += desc.foundry->name.isEmpty() ? QByteArray("*") : desc.foundry->name.toLatin1();
01736             xlfd += "-";
01737             xlfd += desc.family->name.isEmpty() ? QByteArray("*") : desc.family->name.toLatin1();
01738             xlfd += "-";
01739             xlfd += desc.style->weightName ? desc.style->weightName : "*";
01740             xlfd += "-";
01741             xlfd += (desc.style->key.style == QFont::StyleItalic
01742                      ? "i"
01743                      : (desc.style->key.style == QFont::StyleOblique ? "o" : "r"));
01744             xlfd += "-";
01745             xlfd += desc.style->setwidthName ? desc.style->setwidthName : "*";
01746             // ### handle add-style
01747             xlfd += "-*-";
01748             xlfd += QByteArray::number(px);
01749             xlfd += "-";
01750             xlfd += QByteArray::number(desc.encoding->xpoint);
01751             xlfd += "-";
01752             xlfd += QByteArray::number(desc.encoding->xres);
01753             xlfd += "-";
01754             xlfd += QByteArray::number(desc.encoding->yres);
01755             xlfd += "-";
01756             xlfd += desc.encoding->pitch;
01757             xlfd += "-";
01758             xlfd += QByteArray::number(desc.encoding->avgwidth);
01759             xlfd += "-";
01760             xlfd += xlfd_for_id(desc.encoding->encoding);
01761 
01762             FM_DEBUG("    using XLFD: %s\n", xlfd.data());
01763 
01764             const int mib = xlfd_encoding[desc.encoding->encoding].mib;
01765             XFontStruct *xfs;
01766             if ((xfs = XLoadQueryFont(QX11Info::display(), xlfd))) {
01767                 fe = new QFontEngineXLFD(xfs, xlfd, mib);
01768                 const int dpi = QX11Info::appDpiY();
01769                 if (!qt_fillFontDef(xfs, &fe->fontDef, dpi)
01770                     && !qt_fillFontDef(xlfd, &fe->fontDef, dpi)) {
01771                     initFontDef(desc, request, &fe->fontDef);
01772                 }
01773             }
01774         }
01775         if (!fe) {
01776             fe = new QFontEngineBox(request.pixelSize);
01777             fe->fontDef = QFontDef();
01778         }
01779     } else {
01780         QList<int> encodings;
01781         if (desc.encoding)
01782             encodings.append(int(desc.encoding->encoding));
01783 
01784         if (desc.size) {
01785             // append all other encodings for the matched font
01786             for (int i = 0; i < desc.size->count; ++i) {
01787                 QtFontEncoding *e = desc.size->encodings + i;
01788                 if (e == desc.encoding)
01789                     continue;
01790                 encodings.append(int(e->encoding));
01791             }
01792         }
01793         // fill in the missing encodings
01794         const XlfdEncoding *enc = xlfd_encoding;
01795         for (; enc->name; ++enc) {
01796             if (!encodings.contains(enc->id))
01797                 encodings.append(enc->id);
01798         }
01799 
01800 #if defined(FONT_MATCH_DEBUG)
01801         FM_DEBUG("    using MultiXLFD, encodings:");
01802         for (int i = 0; i < encodings.size(); ++i) {
01803             const int id = encodings.at(i);
01804             FM_DEBUG("      %2d: %s", xlfd_encoding[id].id, xlfd_encoding[id].name);
01805         }
01806 #endif
01807 
01808         fe = new QFontEngineMultiXLFD(request, encodings, screen);
01809     }
01810     return fe;
01811 }
01812 
01817 void QFontDatabase::load(const QFontPrivate *d, int script)
01818 {
01819     Q_ASSERT(script >= 0 && script < QUnicodeTables::ScriptCount);
01820 
01821     if (!privateDb()->count)
01822         initializeDb();
01823 
01824     // normalize the request to get better caching
01825     QFontDef req = d->request;
01826     if (req.pixelSize <= 0)
01827         req.pixelSize = qRound(qt_pixelSize(req.pointSize, d->dpi));
01828     req.pointSize = 0;
01829     if (req.weight == 0)
01830         req.weight = QFont::Normal;
01831     if (req.stretch == 0)
01832         req.stretch = 100;
01833 
01834     QFontCache::Key key(req, d->rawMode ? QUnicodeTables::Common : script, d->screen);
01835     if (!d->engineData)
01836         getEngineData(d, key);
01837 
01838     // the cached engineData could have already loaded the engine we want
01839     if (d->engineData->engines[script])
01840         return;
01841 
01842     // set it to the actual pointsize, so QFontInfo will do the right thing
01843     req.pointSize = qt_pointSize(req.pixelSize, d->dpi);
01844 
01845     QFontEngine *fe = QFontCache::instance->findEngine(key);
01846 
01847     if (!fe) {
01848         if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) {
01849             fe = new QTestFontEngine(req.pixelSize);
01850             fe->fontDef = req;
01851         } else if (d->rawMode) {
01852             fe = loadRaw(d, req);
01853 #ifndef QT_NO_FONTCONFIG
01854         } else if (X11->has_fontconfig) {
01855             fe = loadFc(d, script, req);
01856 #endif
01857         } else {
01858             fe = loadXlfd(d->screen, script, req);
01859         }
01860         if (!fe) {
01861             fe = new QFontEngineBox(req.pixelSize);
01862             fe->fontDef = QFontDef();
01863         }
01864     }
01865     if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
01866         for (int i = 0; i < QUnicodeTables::ScriptCount; ++i) {
01867             if (!d->engineData->engines[i]) {
01868                 d->engineData->engines[i] = fe;
01869                 fe->ref.ref();
01870             }
01871         }
01872     } else {
01873         d->engineData->engines[script] = fe;
01874         fe->ref.ref();
01875     }
01876     QFontCache::instance->insertEngine(key, fe);
01877 }
01878 
01879 // used from qfontengine_x11.cpp
01880 QByteArray qt_fontdata_from_index(int index)
01881 {
01882     return privateDb()->applicationFonts.value(index).data;
01883 }
01884 
01885 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
01886 {
01887 #if defined(QT_NO_FONTCONFIG)
01888     return;
01889 #else
01890     if (!X11->has_fontconfig)
01891         return;
01892 
01893     FcConfig *config = FcConfigGetCurrent();
01894     if (!config)
01895         return;
01896 
01897     FcFontSet *set = FcConfigGetFonts(config, FcSetApplication);
01898     if (!set) {
01899         FcConfigAppFontAddFile(config, (const FcChar8 *)":/non-existant");
01900         set = FcConfigGetFonts(config, FcSetApplication); // try again
01901         if (!set)
01902             return;
01903     }
01904 
01905     QString fileNameForQuery = fnt->fileName;
01906     QTemporaryFile tmp;
01907 
01908     if (!fnt->data.isEmpty()) {
01909         if (!tmp.open())
01910             return;
01911         tmp.write(fnt->data);
01912         tmp.flush();
01913         fileNameForQuery = tmp.fileName();
01914     }
01915 
01916     int id = 0;
01917     FcBlanks *blanks = FcConfigGetBlanks(0);
01918     int count = 0;
01919 
01920     QStringList families;
01921 
01922     FcPattern *pattern = 0;
01923     do {
01924         pattern = FcFreeTypeQuery((const FcChar8 *)QFile::encodeName(fileNameForQuery).constData(),
01925                                   id, blanks, &count);
01926         if (!pattern)
01927             return;
01928 
01929         FcPatternDel(pattern, FC_FILE);
01930         FcPatternAddString(pattern, FC_FILE, (const FcChar8 *)fnt->fileName.toUtf8().constData());
01931 
01932         FcChar8 *fam = 0;
01933         if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) {
01934             QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
01935             family.replace(QLatin1Char('-'), QLatin1Char(' '));
01936             family.remove(QLatin1Char('/'));
01937             families << family;
01938         }
01939 
01940         if (!FcFontSetAdd(set, pattern))
01941             return;
01942 
01943         ++id;
01944     } while (pattern && id < count);
01945 
01946     fnt->families = families;
01947 #endif
01948 }
01949 
01950 bool QFontDatabase::removeApplicationFont(int handle)
01951 {
01952 #if defined(QT_NO_FONTCONFIG)
01953     return false;
01954 #else
01955     QFontDatabasePrivate *db = privateDb();
01956     if (handle < 0 || handle >= db->applicationFonts.count())
01957         return false;
01958 
01959     FcConfigAppFontClear(0);
01960 
01961     db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
01962 
01963     db->reregisterAppFonts = true;
01964     db->invalidate();
01965     return true;
01966 #endif
01967 }
01968 
01969 bool QFontDatabase::removeAllApplicationFonts()
01970 {
01971 #if defined(QT_NO_FONTCONFIG)
01972     return false;
01973 #else
01974     QFontDatabasePrivate *db = privateDb();
01975     if (db->applicationFonts.isEmpty())
01976         return false;
01977 
01978     FcConfigAppFontClear(0);
01979     db->applicationFonts.clear();
01980     db->invalidate();
01981     return true;
01982 #endif
01983 }
01984 

Generated on Thu Mar 15 11:55:55 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1