src/gui/text/qfontdatabase.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 <qdir.h>
00025 #include "qfontdatabase.h"
00026 #include "qdebug.h"
00027 #include "qalgorithms.h"
00028 #include "qapplication.h"
00029 #include "qvarlengtharray.h" // here or earlier - workaround for VC++6
00030 #include "private/qunicodetables_p.h"
00031 #include "qfontengine_p.h"
00032 #include "qopentype_p.h"
00033 
00034 #ifdef Q_WS_X11
00035 #include <locale.h>
00036 #endif
00037 #include <stdlib.h>
00038 #include <limits.h>
00039 
00040 // #define QFONTDATABASE_DEBUG
00041 #ifdef QFONTDATABASE_DEBUG
00042 #  define FD_DEBUG qDebug
00043 #else
00044 #  define FD_DEBUG if (false) qDebug
00045 #endif
00046 
00047 // #define FONT_MATCH_DEBUG
00048 #ifdef FONT_MATCH_DEBUG
00049 #  define FM_DEBUG qDebug
00050 #else
00051 #  define FM_DEBUG if (false) qDebug
00052 #endif
00053 
00054 #if defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
00055 #  define for if(0){}else for
00056 #endif
00057 
00058 
00059 Q_GUI_EXPORT bool qt_enable_test_font = false;
00060 
00061 static int ucstricmp(const QString &as, const QString &bs)
00062 {
00063     const QChar *a = as.unicode();
00064     const QChar *b = bs.unicode();
00065     if (a == b)
00066         return 0;
00067     if (a == 0)
00068         return 1;
00069     if (b == 0)
00070         return -1;
00071     int l=qMin(as.length(),bs.length());
00072     while (l-- && QUnicodeTables::lower(*a) == QUnicodeTables::lower(*b))
00073         a++,b++;
00074     if (l==-1)
00075         return (as.length()-bs.length());
00076     return QUnicodeTables::lower(*a).unicode() - QUnicodeTables::lower(*b).unicode();
00077 }
00078 
00079 static int getFontWeight(const QString &weightString)
00080 {
00081     QString s = weightString.toLower();
00082 
00083     // Test in decreasing order of commonness
00084     if (s == QLatin1String("medium") ||
00085         s == QLatin1String("normal"))
00086         return QFont::Normal;
00087     if (s == QLatin1String("bold"))
00088         return QFont::Bold;
00089     if (s == QLatin1String("demibold") || s == QLatin1String("demi bold"))
00090         return QFont::DemiBold;
00091     if (s == QLatin1String("black"))
00092         return QFont::Black;
00093     if (s == QLatin1String("light"))
00094         return QFont::Light;
00095 
00096     if (s.contains(QLatin1String("bold"))) {
00097         if (s.contains(QLatin1String("demi")))
00098             return (int) QFont::DemiBold;
00099         return (int) QFont::Bold;
00100     }
00101 
00102     if (s.contains(QLatin1String("light")))
00103         return (int) QFont::Light;
00104 
00105     if (s.contains(QLatin1String("black")))
00106         return (int) QFont::Black;
00107 
00108     return (int) QFont::Normal;
00109 }
00110 
00111 struct QtFontEncoding
00112 {
00113     signed int encoding : 16;
00114 
00115     uint xpoint   : 16;
00116     uint xres     : 8;
00117     uint yres     : 8;
00118     uint avgwidth : 16;
00119     uchar pitch   : 8;
00120 };
00121 
00122 struct QtFontSize
00123 {
00124     unsigned short pixelSize;
00125 
00126 #ifdef Q_WS_X11
00127     int count;
00128     QtFontEncoding *encodings;
00129     QtFontEncoding *encodingID(int id, uint xpoint = 0, uint xres = 0,
00130                                 uint yres = 0, uint avgwidth = 0, bool add = false);
00131 #endif // Q_WS_X11
00132 #ifdef Q_WS_QWS
00133     QByteArray fileName;
00134 #endif
00135 };
00136 
00137 
00138 #ifdef Q_WS_X11
00139 QtFontEncoding *QtFontSize::encodingID(int id, uint xpoint, uint xres,
00140                                         uint yres, uint avgwidth, bool add)
00141 {
00142     // we don't match using the xpoint, xres and yres parameters, only the id
00143     for (int i = 0; i < count; ++i) {
00144         if (encodings[i].encoding == id)
00145             return encodings + i;
00146     }
00147 
00148     if (!add) return 0;
00149 
00150     if (!(count % 4))
00151         encodings = (QtFontEncoding *)
00152                     realloc(encodings,
00153                              (((count+4) >> 2) << 2) * sizeof(QtFontEncoding));
00154     encodings[count].encoding = id;
00155     encodings[count].xpoint = xpoint;
00156     encodings[count].xres = xres;
00157     encodings[count].yres = yres;
00158     encodings[count].avgwidth = avgwidth;
00159     encodings[count].pitch = '*';
00160     return encodings + count++;
00161 }
00162 #endif // Q_WS_X11
00163 
00164 struct QtFontStyle
00165 {
00166     struct Key {
00167         Key(const QString &styleString);
00168         Key() : style(QFont::StyleNormal),
00169                 weight(QFont::Normal), stretch(0) { }
00170         Key(const Key &o) : style(o.style),
00171                               weight(o.weight), stretch(o.stretch) { }
00172         uint style : 2;
00173         signed int  weight : 8;
00174         signed int stretch : 12;
00175 
00176         bool operator==(const Key & other) {
00177             return (style == other.style &&
00178                      weight == other.weight &&
00179                      (stretch == 0 || other.stretch == 0 || stretch == other.stretch));
00180         }
00181         bool operator!=(const Key &other) {
00182             return !operator==(other);
00183         }
00184         bool operator <(const Key &o) {
00185             int x = (style << 12) + (weight << 14) + stretch;
00186             int y = (o.style << 12) + (o.weight << 14) + o.stretch;
00187             return (x < y);
00188         }
00189     };
00190 
00191     QtFontStyle(const Key &k)
00192         : key(k), bitmapScalable(false), smoothScalable(false),
00193           count(0), pixelSizes(0)
00194     {
00195 #if defined(Q_WS_X11)
00196         weightName = setwidthName = 0;
00197 #endif // Q_WS_X11
00198     }
00199 
00200     ~QtFontStyle() {
00201 #ifdef Q_WS_X11
00202         delete [] weightName;
00203         delete [] setwidthName;
00204 #endif
00205 #if defined(Q_WS_X11) || defined(Q_WS_QWS)
00206         while (count--) {
00207 #ifdef Q_WS_X11
00208             free(pixelSizes[count].encodings);
00209 #endif
00210 #ifdef Q_WS_QWS
00211             pixelSizes[count].fileName.~QByteArray();
00212 #endif
00213         }
00214 #endif
00215         free(pixelSizes);
00216     }
00217 
00218     Key key;
00219     bool bitmapScalable : 1;
00220     bool smoothScalable : 1;
00221     signed int count    : 30;
00222     QtFontSize *pixelSizes;
00223 
00224 #ifdef Q_WS_X11
00225     const char *weightName;
00226     const char *setwidthName;
00227 #endif // Q_WS_X11
00228 #ifdef Q_WS_QWS
00229     bool antialiased;
00230 #endif
00231 
00232     QtFontSize *pixelSize(unsigned short size, bool = false);
00233 };
00234 
00235 QtFontStyle::Key::Key(const QString &styleString)
00236     : style(QFont::StyleNormal), weight(QFont::Normal), stretch(0)
00237 {
00238     weight = getFontWeight(styleString);
00239 
00240     if (styleString.contains(QLatin1String("Italic")))
00241         style = QFont::StyleItalic;
00242     else if (styleString.contains(QLatin1String("Oblique")))
00243         style = QFont::StyleOblique;
00244 }
00245 
00246 QtFontSize *QtFontStyle::pixelSize(unsigned short size, bool add)
00247 {
00248     for (int i = 0; i < count; i++) {
00249         if (pixelSizes[i].pixelSize == size)
00250             return pixelSizes + i;
00251     }
00252     if (!add)
00253         return 0;
00254 
00255     if (!(count % 8))
00256         pixelSizes = (QtFontSize *)
00257                      realloc(pixelSizes,
00258                               (((count+8) >> 3) << 3) * sizeof(QtFontSize));
00259     pixelSizes[count].pixelSize = size;
00260 #ifdef Q_WS_X11
00261     pixelSizes[count].count = 0;
00262     pixelSizes[count].encodings = 0;
00263 #endif
00264 #ifdef Q_WS_QWS
00265     new (&pixelSizes[count].fileName) QByteArray;
00266 #endif
00267     return pixelSizes + (count++);
00268 }
00269 
00270 struct QtFontFoundry
00271 {
00272     QtFontFoundry(const QString &n) : name(n), count(0), styles(0) {}
00273     ~QtFontFoundry() {
00274         while (count--)
00275             delete styles[count];
00276         free(styles);
00277     }
00278 
00279     QString name;
00280 
00281     int count;
00282     QtFontStyle **styles;
00283     QtFontStyle *style(const QtFontStyle::Key &, bool = false);
00284 };
00285 
00286 QtFontStyle *QtFontFoundry::style(const QtFontStyle::Key &key, bool create)
00287 {
00288     int pos = 0;
00289     if (count) {
00290         int low = 0;
00291         int high = count;
00292         pos = count / 2;
00293         while (high > low) {
00294             if (styles[pos]->key == key)
00295                 return styles[pos];
00296             if (styles[pos]->key < key)
00297                 low = pos + 1;
00298             else
00299                 high = pos;
00300             pos = (high + low) / 2;
00301         };
00302         pos = low;
00303     }
00304     if (!create)
00305         return 0;
00306 
00307 //     qDebug("adding key (weight=%d, style=%d, oblique=%d stretch=%d) at %d", key.weight, key.style, key.oblique, key.stretch, pos);
00308     if (!(count % 8))
00309         styles = (QtFontStyle **)
00310                  realloc(styles, (((count+8) >> 3) << 3) * sizeof(QtFontStyle *));
00311 
00312     memmove(styles + pos + 1, styles + pos, (count-pos)*sizeof(QtFontStyle *));
00313     styles[pos] = new QtFontStyle(key);
00314     count++;
00315     return styles[pos];
00316 }
00317 
00318 
00319 struct QtFontFamily
00320 {
00321     enum WritingSystemStatus {
00322         Unknown         = 0,
00323         Supported       = 1,
00324         UnsupportedFT  = 2,
00325         UnsupportedXLFD = 4,
00326         Unsupported     = UnsupportedFT | UnsupportedXLFD
00327     };
00328 
00329     QtFontFamily(const QString &n)
00330         :
00331 #ifdef Q_WS_X11
00332         fixedPitch(true), ftWritingSystemCheck(false),
00333         xlfdLoaded(false), synthetic(false), symbol_checked(false),
00334 #else
00335         fixedPitch(false),
00336 #endif
00337 #ifdef Q_WS_WIN
00338         writingSystemCheck(false),
00339         loaded(false),
00340 #endif
00341 #if !defined(QWS) && defined(Q_OS_MAC)
00342         fixedPitchComputed(false),
00343 #endif
00344         name(n), count(0), foundries(0) {
00345         memset(writingSystems, 0, sizeof(writingSystems));
00346     }
00347     ~QtFontFamily() {
00348         while (count--)
00349             delete foundries[count];
00350         free(foundries);
00351     }
00352 
00353     bool fixedPitch : 1;
00354 #ifdef Q_WS_X11
00355     bool ftWritingSystemCheck : 1;
00356     bool xlfdLoaded : 1;
00357     bool synthetic : 1;
00358 #endif
00359 #ifdef Q_WS_WIN
00360     bool writingSystemCheck : 1;
00361     bool loaded : 1;
00362 #endif
00363 #if !defined(QWS) && defined(Q_OS_MAC)
00364     bool fixedPitchComputed : 1;
00365 #endif
00366 #ifdef Q_WS_X11
00367     bool symbol_checked;
00368 #endif
00369 
00370     QString name;
00371     QString rawName;
00372 #ifdef Q_WS_X11
00373     QByteArray fontFilename;
00374     int fontFileIndex;
00375 #endif
00376 #ifdef Q_WS_WIN
00377     QString english_name;
00378 #endif
00379     int count;
00380     QtFontFoundry **foundries;
00381 
00382     unsigned char writingSystems[QFontDatabase::WritingSystemsCount];
00383 
00384     QtFontFoundry *foundry(const QString &f, bool = false);
00385 };
00386 
00387 #if !defined(QWS) && defined(Q_OS_MAC)
00388 inline static void qt_mac_get_fixed_pitch(QtFontFamily *f)
00389 {
00390     if(f && !f->fixedPitchComputed) {
00391         QFontMetrics fm(f->name);
00392         f->fixedPitch = fm.width('i') == fm.width('m');
00393         f->fixedPitchComputed = true;
00394     }
00395 }
00396 #endif
00397 
00398 
00399 QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create)
00400 {
00401     if (f.isNull() && count == 1)
00402         return foundries[0];
00403 
00404     for (int i = 0; i < count; i++) {
00405         if (ucstricmp(foundries[i]->name, f) == 0)
00406             return foundries[i];
00407     }
00408     if (!create)
00409         return 0;
00410 
00411     if (!(count % 8))
00412         foundries = (QtFontFoundry **)
00413                     realloc(foundries,
00414                              (((count+8) >> 3) << 3) * sizeof(QtFontFoundry *));
00415 
00416     foundries[count] = new QtFontFoundry(f);
00417     return foundries[count++];
00418 }
00419 
00420 class QFontDatabasePrivate : public QObject
00421 {
00422     Q_OBJECT
00423 public:
00424     QFontDatabasePrivate() : count(0), families(0), reregisterAppFonts(false) { }
00425     ~QFontDatabasePrivate() {
00426         free();
00427     }
00428     QtFontFamily *family(const QString &f, bool = false);
00429     void free() {
00430         while (count--)
00431             delete families[count];
00432         ::free(families);
00433         families = 0;
00434         count = 0;
00435         // don't clear the memory fonts!
00436     }
00437 
00438     int count;
00439     QtFontFamily **families;
00440 
00441     struct ApplicationFont {
00442         QString fileName;
00443         QByteArray data;
00444 #if defined(Q_OS_WIN)
00445         HANDLE handle;
00446         bool memoryFont;
00447 #elif defined(Q_WS_MAC)
00448         ATSFontContainerRef handle;
00449 #endif
00450         QStringList families;
00451     };
00452     QVector<ApplicationFont> applicationFonts;
00453     int addAppFont(const QByteArray &fontData, const QString &fileName);
00454     bool reregisterAppFonts;
00455 
00456     void invalidate();
00457 
00458 Q_SIGNALS:
00459     void fontDatabaseChanged();
00460 };
00461 
00462 void QFontDatabasePrivate::invalidate()
00463 {
00464     if (QFontCache::instance)
00465         QFontCache::instance->clear();
00466     free();
00467     emit fontDatabaseChanged();
00468 }
00469 
00470 QtFontFamily *QFontDatabasePrivate::family(const QString &f, bool create)
00471 {
00472     int low = 0;
00473     int high = count;
00474     int pos = count / 2;
00475     int res = 1;
00476     if (count) {
00477         while ((res = ucstricmp(families[pos]->name, f)) && pos != low) {
00478             if (res > 0)
00479                 high = pos;
00480             else
00481                 low = pos;
00482             pos = (high + low) / 2;
00483         };
00484         if (!res)
00485             return families[pos];
00486     }
00487     if (!create)
00488         return 0;
00489 
00490     if (res < 0)
00491         pos++;
00492 
00493     // qDebug("adding family %s at %d total=%d", f.latin1(), pos, count);
00494     if (!(count % 8))
00495         families = (QtFontFamily **)
00496                    realloc(families,
00497                             (((count+8) >> 3) << 3) * sizeof(QtFontFamily *));
00498 
00499     memmove(families + pos + 1, families + pos, (count-pos)*sizeof(QtFontFamily *));
00500     families[pos] = new QtFontFamily(f);
00501     count++;
00502     return families[pos];
00503 }
00504 
00505 
00506 static const int scriptForWritingSystem[] = {
00507     QUnicodeTables::Common, // Any
00508     QUnicodeTables::Latin, // Latin
00509     QUnicodeTables::Greek, // Greek
00510     QUnicodeTables::Cyrillic, // Cyrillic
00511     QUnicodeTables::Armenian, // Armenian
00512     QUnicodeTables::Hebrew, // Hebrew
00513     QUnicodeTables::Arabic, // Arabic
00514     QUnicodeTables::Syriac, // Syriac
00515     QUnicodeTables::Thaana, // Thaana
00516     QUnicodeTables::Devanagari, // Devanagari
00517     QUnicodeTables::Bengali, // Bengali
00518     QUnicodeTables::Gurmukhi, // Gurmukhi
00519     QUnicodeTables::Gujarati, // Gujarati
00520     QUnicodeTables::Oriya, // Oriya
00521     QUnicodeTables::Tamil, // Tamil
00522     QUnicodeTables::Telugu, // Telugu
00523     QUnicodeTables::Kannada, // Kannada
00524     QUnicodeTables::Malayalam, // Malayalam
00525     QUnicodeTables::Sinhala, // Sinhala
00526     QUnicodeTables::Thai, // Thai
00527     QUnicodeTables::Lao, // Lao
00528     QUnicodeTables::Tibetan, // Tibetan
00529     QUnicodeTables::Myanmar, // Myanmar
00530     QUnicodeTables::Georgian, // Georgian
00531     QUnicodeTables::Khmer, // Khmer
00532     QUnicodeTables::Common, // SimplifiedChinese
00533     QUnicodeTables::Common, // TraditionalChinese
00534     QUnicodeTables::Common, // Japanese
00535     QUnicodeTables::Hangul, // Korean
00536     QUnicodeTables::Common, // Vietnamese
00537     QUnicodeTables::Common, // Yi
00538     QUnicodeTables::Common, // Tagalog
00539     QUnicodeTables::Common, // Hanunoo
00540     QUnicodeTables::Common, // Buhid
00541     QUnicodeTables::Common, // Tagbanwa
00542     QUnicodeTables::Common, // Limbu
00543     QUnicodeTables::Common, // TaiLe
00544     QUnicodeTables::Common, // Braille
00545     QUnicodeTables::Common, // Symbol
00546     QUnicodeTables::Ogham,  // Ogham
00547     QUnicodeTables::Runic // Runic
00548 };
00549 
00550 
00551 #if defined Q_WS_QWS || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG))
00552 static inline bool requiresOpenType(int writingSystem)
00553 {
00554     return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala)
00555             || writingSystem == QFontDatabase::Khmer);
00556 }
00557 static inline bool scriptRequiresOpenType(int script)
00558 {
00559     return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
00560             || script == QUnicodeTables::Khmer);
00561 }
00562 #endif
00563 
00564 
00574 static void parseFontName(const QString &name, QString &foundry, QString &family)
00575 {
00576     int i = name.indexOf(QLatin1Char('['));
00577     int li = name.lastIndexOf(QLatin1Char(']'));
00578     if (i >= 0 && li >= 0 && i < li) {
00579         foundry = name.mid(i + 1, li - i - 1);
00580         if (i > 0 && name[i - 1] == QLatin1Char(' '))
00581             i--;
00582         family = name.left(i);
00583     } else {
00584         foundry.clear();
00585         family = name;
00586     }
00587 
00588     // capitalize the family/foundry names
00589     bool space = true;
00590     QChar *s = family.data();
00591     int len = family.length();
00592     while(len--) {
00593         if (space) *s = s->toUpper();
00594         space = s->isSpace();
00595         ++s;
00596     }
00597 
00598     space = true;
00599     s = foundry.data();
00600     len = foundry.length();
00601     while(len--) {
00602         if (space) *s = s->toUpper();
00603         space = s->isSpace();
00604         ++s;
00605     }
00606 }
00607 
00608 
00609 struct QtFontDesc
00610 {
00611     inline QtFontDesc() : family(0), foundry(0), style(0), size(0), encoding(0) {}
00612     QtFontFamily *family;
00613     QtFontFoundry *foundry;
00614     QtFontStyle *style;
00615     QtFontSize *size;
00616     QtFontEncoding *encoding;
00617 };
00618 
00619 #if !defined(Q_WS_MAC)
00620 static void match(int script, const QFontDef &request,
00621                   const QString &family_name, const QString &foundry_name, int force_encoding_id,
00622                   QtFontDesc *desc);
00623 
00624 static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef)
00625 {
00626     fontDef->family = desc.family->name;
00627     if (! desc.foundry->name.isEmpty()) {
00628         fontDef->family += QString::fromLatin1(" [");
00629         fontDef->family += desc.foundry->name;
00630         fontDef->family += QString::fromLatin1("]");
00631     }
00632 
00633     if (desc.style->smoothScalable)
00634         fontDef->pixelSize = request.pixelSize;
00635     else if ((desc.style->bitmapScalable && (request.styleStrategy & QFont::PreferMatch)))
00636         fontDef->pixelSize = request.pixelSize;
00637     else
00638         fontDef->pixelSize = desc.size->pixelSize;
00639 
00640     fontDef->styleHint     = request.styleHint;
00641     fontDef->styleStrategy = request.styleStrategy;
00642 
00643     fontDef->weight        = desc.style->key.weight;
00644     fontDef->style         = desc.style->key.style;
00645     fontDef->fixedPitch    = desc.family->fixedPitch;
00646     fontDef->stretch       = desc.style->key.stretch;
00647     fontDef->ignorePitch   = false;
00648 }
00649 #endif
00650 
00651 #if defined(Q_WS_X11) || defined(Q_WS_WIN)
00652 static void getEngineData(const QFontPrivate *d, const QFontCache::Key &key)
00653 {
00654     // look for the requested font in the engine data cache
00655     d->engineData = QFontCache::instance->findEngineData(key);
00656     if (!d->engineData) {
00657         // create a new one
00658         d->engineData = new QFontEngineData;
00659         QFontCache::instance->insertEngineData(key, d->engineData);
00660     } else {
00661         d->engineData->ref.ref();
00662     }
00663 }
00664 
00665 static QStringList familyList(const QFontDef &req)
00666 {
00667     // list of families to try
00668     QStringList family_list;
00669     if (req.family.isEmpty())
00670         return family_list;
00671 
00672     QStringList list = req.family.split(QLatin1Char(','));
00673     for (int i = 0; i < list.size(); ++i) {
00674         QString str = list.at(i).trimmed();
00675         if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
00676             || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
00677             str = str.mid(1, str.length() - 2);
00678         family_list << str;
00679     }
00680 
00681     // append the substitute list for each family in family_list
00682     QStringList subs_list;
00683     QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd();
00684     for (; it != end; ++it)
00685         subs_list += QFont::substitutes(*it);
00686 //         qDebug() << "adding substs: " << subs_list;
00687 
00688     family_list += subs_list;
00689 
00690     return family_list;
00691 }
00692 #endif
00693 
00694 Q_GLOBAL_STATIC(QFontDatabasePrivate, privateDb);
00695 
00696 // used in qfontcombobox.cpp
00697 QObject *qt_fontdatabase_private()
00698 {
00699     return privateDb();
00700 }
00701 
00702 #define SMOOTH_SCALABLE 0xffff
00703 
00704 #if defined(Q_WS_X11)
00705 #  include "qfontdatabase_x11.cpp"
00706 #elif defined(Q_WS_MAC)
00707 #  include "qfontdatabase_mac.cpp"
00708 #elif defined(Q_WS_WIN)
00709 #  include "qfontdatabase_win.cpp"
00710 #elif defined(Q_WS_QWS)
00711 #  include "qfontdatabase_qws.cpp"
00712 #endif
00713 
00714 static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey)
00715 {
00716     int best = 0;
00717     int dist = 0xffff;
00718 
00719     for ( int i = 0; i < foundry->count; i++ ) {
00720   QtFontStyle *style = foundry->styles[i];
00721 
00722   int d = qAbs( styleKey.weight - style->key.weight );
00723 
00724   if ( styleKey.stretch != 0 && style->key.stretch != 0 ) {
00725       d += qAbs( styleKey.stretch - style->key.stretch );
00726   }
00727 
00728         if (styleKey.style != style->key.style) {
00729             if (styleKey.style != QFont::StyleNormal && style->key.style != QFont::StyleNormal)
00730                 // one is italic, the other oblique
00731                 d += 0x0001;
00732             else
00733                 d += 0x1000;
00734         }
00735 
00736   if ( d < dist ) {
00737       best = i;
00738       dist = d;
00739   }
00740     }
00741 
00742     FM_DEBUG( "          best style has distance 0x%x", dist );
00743     return foundry->styles[best];
00744 }
00745 
00746 #if defined(Q_WS_X11)
00747 static QtFontEncoding *findEncoding(int script, int styleStrategy,
00748                                     QtFontSize *size, int force_encoding_id)
00749 {
00750     QtFontEncoding *encoding = 0;
00751 
00752     if (force_encoding_id >= 0) {
00753         encoding = size->encodingID(force_encoding_id);
00754         if (!encoding)
00755             FM_DEBUG("            required encoding_id not available");
00756         return encoding;
00757     }
00758 
00759     if (styleStrategy & (QFont::OpenGLCompatible | QFont::PreferBitmap)) {
00760         FM_DEBUG("            PreferBitmap and/or OpenGL set, skipping Freetype");
00761     } else {
00762         encoding = size->encodingID(-1); // -1 == prefer Freetype
00763         if (encoding)
00764             return encoding;
00765     }
00766 
00767     // FT not available, find an XLFD font, trying the default encoding first
00768     encoding = size->encodingID(QFontPrivate::defaultEncodingID);
00769     if (encoding) {
00770         // does it support the requested script?
00771         bool supportsScript = false;
00772         for (int ws = 1; !supportsScript && ws < QFontDatabase::WritingSystemsCount; ++ws) {
00773             if (scriptForWritingSystem[ws] != script)
00774                 continue;
00775             supportsScript = writingSystems_for_xlfd_encoding[encoding->encoding][ws];
00776         }
00777         if (!supportsScript)
00778             encoding = 0;
00779     }
00780     // find the first encoding that supports the requested script
00781     for (int ws = 1; !encoding && ws < QFontDatabase::WritingSystemsCount; ++ws) {
00782         if (scriptForWritingSystem[ws] != script)
00783             continue;
00784         for (int x = 0; !encoding && x < size->count; ++x) {
00785             const int enc = size->encodings[x].encoding;
00786             if (writingSystems_for_xlfd_encoding[enc][ws])
00787                 encoding = size->encodings + x;
00788         }
00789     }
00790 
00791     return encoding;
00792 }
00793 #endif // Q_WS_X11
00794 
00795 #if !defined(Q_WS_MAC)
00796 static
00797 unsigned int bestFoundry(int script, unsigned int score, int styleStrategy,
00798                          const QtFontFamily *family, const QString &foundry_name,
00799                          QtFontStyle::Key styleKey, int pixelSize, char pitch,
00800                          QtFontDesc *desc, int force_encoding_id)
00801 {
00802     Q_UNUSED(force_encoding_id);
00803     Q_UNUSED(script);
00804     Q_UNUSED(pitch);
00805 
00806     desc->foundry = 0;
00807     desc->style = 0;
00808     desc->size = 0;
00809     desc->encoding = 0;
00810 
00811 
00812     FM_DEBUG("  REMARK: looking for best foundry for family '%s' [%d]", family->name.toLatin1().constData(), family->count);
00813 
00814     for (int x = 0; x < family->count; ++x) {
00815         QtFontFoundry *foundry = family->foundries[x];
00816         if (!foundry_name.isEmpty() &&
00817             ucstricmp(foundry->name, foundry_name) != 0)
00818             continue;
00819 
00820         FM_DEBUG("          looking for matching style in foundry '%s' %d",
00821                  foundry->name.isEmpty() ? "-- none --" : foundry->name.toLatin1().constData(), foundry->count);
00822 
00823         QtFontStyle *style = bestStyle(foundry, styleKey);
00824 
00825         if (!style->smoothScalable && (styleStrategy & QFont::ForceOutline)) {
00826             FM_DEBUG("            ForceOutline set, but not smoothly scalable");
00827             continue;
00828         }
00829 
00830         int px = -1;
00831         QtFontSize *size = 0;
00832 
00833         // 1. see if we have an exact matching size
00834         if (!(styleStrategy & QFont::ForceOutline)) {
00835             size = style->pixelSize(pixelSize);
00836       if (size) {
00837                 FM_DEBUG("          found exact size match (%d pixels)", size->pixelSize);
00838                 px = size->pixelSize;
00839             }
00840         }
00841 
00842         // 2. see if we have a smoothly scalable font
00843         if (!size && style->smoothScalable && ! (styleStrategy & QFont::PreferBitmap)) {
00844             size = style->pixelSize(SMOOTH_SCALABLE);
00845       if (size) {
00846                 FM_DEBUG("          found smoothly scalable font (%d pixels)", pixelSize);
00847                 px = pixelSize;
00848             }
00849         }
00850 
00851         // 3. see if we have a bitmap scalable font
00852         if (!size && style->bitmapScalable && (styleStrategy & QFont::PreferMatch)) {
00853             size = style->pixelSize(0);
00854             if (size) {
00855                 FM_DEBUG("          found bitmap scalable font (%d pixels)", pixelSize);
00856                 px = pixelSize;
00857             }
00858         }
00859 
00860 #ifdef Q_WS_X11
00861         QtFontEncoding *encoding = 0;
00862 #endif
00863 
00864         // 4. find closest size match
00865         if (! size) {
00866             unsigned int distance = ~0u;
00867             for (int x = 0; x < style->count; ++x) {
00868 #ifdef Q_WS_X11
00869                 encoding =
00870                     findEncoding(script, styleStrategy, style->pixelSizes + x, force_encoding_id);
00871                 if (!encoding) {
00872                     FM_DEBUG("          size %3d does not support the script we want",
00873                              style->pixelSizes[x].pixelSize);
00874                     continue;
00875                 }
00876 #endif
00877 
00878                 unsigned int d;
00879                 if (style->pixelSizes[x].pixelSize < pixelSize) {
00880                     // penalize sizes that are smaller than the
00881                     // requested size, due to truncation from floating
00882                     // point to integer conversions
00883                     d = pixelSize - style->pixelSizes[x].pixelSize + 1;
00884                 } else {
00885                     d = style->pixelSizes[x].pixelSize - pixelSize;
00886                 }
00887 
00888                 if (d < distance) {
00889                     distance = d;
00890                     size = style->pixelSizes + x;
00891         FM_DEBUG("          best size so far: %3d (%d)", size->pixelSize, pixelSize);
00892                 }
00893             }
00894 
00895             if (!size) {
00896                 FM_DEBUG("          no size supports the script we want");
00897                 continue;
00898             }
00899 
00900             if (style->bitmapScalable && ! (styleStrategy & QFont::PreferQuality) &&
00901                 (distance * 10 / pixelSize) >= 2) {
00902                 // the closest size is not close enough, go ahead and
00903                 // use a bitmap scaled font
00904                 size = style->pixelSize(0);
00905                 px = pixelSize;
00906             } else {
00907                 px = size->pixelSize;
00908             }
00909         }
00910 
00911 #ifdef Q_WS_X11
00912         if (size) {
00913             encoding = findEncoding(script, styleStrategy, size, force_encoding_id);
00914             if (!encoding) size = 0;
00915         }
00916         if (! encoding) {
00917             FM_DEBUG("          foundry doesn't support the script we want");
00918             continue;
00919         }
00920 #endif // Q_WS_X11
00921 
00922         unsigned int this_score = 0x0000;
00923         enum {
00924             PitchMismatch       = 0x4000,
00925             StyleMismatch       = 0x2000,
00926             BitmapScaledPenalty = 0x1000,
00927             EncodingMismatch    = 0x0002,
00928             XLFDPenalty         = 0x0001
00929         };
00930 #ifdef Q_WS_X11
00931         if (encoding->encoding != -1) {
00932             this_score += XLFDPenalty;
00933             if (encoding->encoding != QFontPrivate::defaultEncodingID)
00934                 this_score += EncodingMismatch;
00935         }
00936         if (pitch != '*') {
00937             if (!(pitch == 'm' && encoding->pitch == 'c') && pitch != encoding->pitch)
00938                 this_score += PitchMismatch;
00939         }
00940 #else
00941         if (pitch != '*') {
00942 #if !defined(QWS) && defined(Q_OS_MAC)
00943             qt_mac_get_fixed_pitch(const_cast<QtFontFamily*>(family));
00944 #endif
00945             if ((pitch == 'm' && !family->fixedPitch)
00946                 || (pitch == 'p' && family->fixedPitch))
00947                 this_score += PitchMismatch;
00948         }
00949 #endif
00950         if (styleKey != style->key)
00951             this_score += StyleMismatch;
00952         if (!style->smoothScalable && px != size->pixelSize) // bitmap scaled
00953             this_score += BitmapScaledPenalty;
00954         if (px != pixelSize) // close, but not exact, size match
00955             this_score += qAbs(px - pixelSize);
00956 
00957         if (this_score < score) {
00958             FM_DEBUG("          found a match: score %x best score so far %x",
00959                      this_score, score);
00960 
00961             score = this_score;
00962             desc->foundry = foundry;
00963             desc->style = style;
00964             desc->size = size;
00965 #ifdef Q_WS_X11
00966             desc->encoding = encoding;
00967 #endif // Q_WS_X11
00968         } else {
00969             FM_DEBUG("          score %x no better than best %x", this_score, score);
00970         }
00971     }
00972 
00973     return score;
00974 }
00975 #endif
00976 
00977 #if !defined(Q_WS_MAC)
00978 
00983 static void match(int script, const QFontDef &request,
00984                   const QString &family_name, const QString &foundry_name, int force_encoding_id,
00985                   QtFontDesc *desc)
00986 {
00987     Q_UNUSED(force_encoding_id);
00988 
00989     QtFontStyle::Key styleKey;
00990     styleKey.style = request.style;
00991     styleKey.weight = request.weight;
00992     styleKey.stretch = request.stretch;
00993     char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
00994 
00995     FM_DEBUG("QFontDatabase::match\n"
00996              "  request:\n"
00997              "    family: %s [%s], script: %d\n"
00998              "    weight: %d, style: %d\n"
00999              "    stretch: %d\n"
01000              "    pixelSize: %d\n"
01001              "    pitch: %c",
01002              family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
01003              foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
01004              script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
01005 #if defined(FONT_MATCH_DEBUG) && defined(Q_WS_X11)
01006     if (force_encoding_id >= 0) {
01007         FM_DEBUG("    required encoding: %d", force_encoding_id);
01008     }
01009 #endif
01010 
01011     desc->family = 0;
01012     desc->foundry = 0;
01013     desc->style = 0;
01014     desc->size = 0;
01015     desc->encoding = 0;
01016 
01017     unsigned int score = ~0u;
01018 
01019     ::load(family_name, script);
01020 
01021     QFontDatabasePrivate *db = privateDb();
01022     for (int x = 0; x < db->count; ++x) {
01023         QtFontDesc test;
01024         test.family = db->families[x];
01025 
01026         if (!family_name.isEmpty()
01027             && ucstricmp(test.family->name, family_name) != 0
01028 #ifdef Q_WS_WIN
01029             && ucstricmp(test.family->english_name, family_name) != 0
01030 #endif
01031             )
01032             continue;
01033 
01034         if (family_name.isEmpty())
01035             ::load(test.family->name, script);
01036 
01037         uint score_adjust = 0;
01038 
01039         bool supported = (script == QUnicodeTables::Common);
01040         for (int ws = 1; !supported && ws < QFontDatabase::WritingSystemsCount; ++ws) {
01041             if (scriptForWritingSystem[ws] != script)
01042                 continue;
01043             if (test.family->writingSystems[ws] & QtFontFamily::Supported)
01044                 supported = true;
01045         }
01046         if (!supported) {
01047             // family not supported in the script we want
01048             continue;
01049         }
01050 
01051         // as we know the script is supported, we can be sure
01052         // to find a matching font here.
01053         unsigned int newscore =
01054             bestFoundry(script, score, request.styleStrategy,
01055                         test.family, foundry_name, styleKey, request.pixelSize, pitch,
01056                         &test, force_encoding_id);
01057         if (test.foundry == 0) {
01058             // the specific foundry was not found, so look for
01059             // any foundry matching our requirements
01060             newscore = bestFoundry(script, score, request.styleStrategy, test.family,
01061                                    QString(), styleKey, request.pixelSize,
01062                                    pitch, &test, force_encoding_id);
01063         }
01064         newscore += score_adjust;
01065 
01066         if (newscore < score) {
01067             score = newscore;
01068             *desc = test;
01069         }
01070         if (newscore < 10) // xlfd instead of FT... just accept it
01071             break;
01072     }
01073 }
01074 #endif
01075 
01076 
01077 #if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC)
01078 
01081 QFontEngine *
01082 QFontDatabase::findFont(int script, const QFontPrivate *fp,
01083                         const QFontDef &request, int
01084 #ifdef Q_WS_X11
01085                         force_encoding_id
01086 #endif
01087     )
01088 {
01089 #ifndef Q_WS_X11
01090     const int force_encoding_id = -1;
01091 #endif
01092 
01093     if (!privateDb()->count)
01094         initializeDb();
01095 
01096     QFontEngine *fe = 0;
01097     if (fp) {
01098         if (fp->rawMode) {
01099             fe = loadEngine(script, fp, request, 0, 0, 0
01100 #ifdef Q_WS_X11
01101                             , 0, 0, false
01102 #endif
01103 #ifdef Q_WS_QWS
01104                             , 0
01105 #endif
01106                 );
01107 
01108             // if we fail to load the rawmode font, use a 12pixel box engine instead
01109             if (! fe) fe = new QFontEngineBox(12);
01110             return fe;
01111         }
01112 
01113         QFontCache::Key key(request, script
01114 #if defined(Q_WS_X11)
01115                             , fp->screen
01116 #endif
01117             );
01118         fe = QFontCache::instance->findEngine(key);
01119         if (fe)
01120             return fe;
01121     }
01122 
01123     QString family_name, foundry_name;
01124     QtFontStyle::Key styleKey;
01125     styleKey.style = request.style;
01126     styleKey.weight = request.weight;
01127     styleKey.stretch = request.stretch;
01128     char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
01129 
01130     parseFontName(request.family, foundry_name, family_name);
01131 
01132     FM_DEBUG("QFontDatabase::findFont\n"
01133              "  request:\n"
01134              "    family: %s [%s], script: %d\n"
01135              "    weight: %d, style: %d\n"
01136              "    stretch: %d\n"
01137              "    pixelSize: %d\n"
01138              "    pitch: %c",
01139              family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
01140              foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
01141              script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
01142 #if defined(FONT_MATCH_DEBUG) && defined(Q_WS_X11)
01143     if (force_encoding_id >= 0) {
01144         FM_DEBUG("    required encoding: %d", force_encoding_id);
01145     }
01146 #endif
01147 
01148     if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
01149         fe = new QTestFontEngine(request.pixelSize);
01150         fe->fontDef = request;
01151     }
01152 
01153     if (!fe)
01154     {
01155         QtFontDesc desc;
01156         match(script, request, family_name, foundry_name, force_encoding_id, &desc);
01157 
01158         if (desc.family != 0 && desc.foundry != 0 && desc.style != 0
01159 #ifdef Q_WS_X11
01160             && desc.size != 0 && desc.encoding != 0
01161 #endif
01162             ) {
01163             FM_DEBUG("  BEST:\n"
01164                      "    family: %s [%s]\n"
01165                      "    weight: %d, style: %d\n"
01166                      "    stretch: %d\n"
01167                      "    pixelSize: %d\n"
01168                      "    pitch: %c\n"
01169                      "    encoding: %d\n",
01170                      desc.family->name.toLatin1().constData(),
01171                      desc.foundry->name.isEmpty() ? "-- none --" : desc.foundry->name.toLatin1().constData(),
01172                      desc.style->key.weight, desc.style->key.style,
01173                      desc.style->key.stretch, desc.size ? desc.size->pixelSize : 0xffff,
01174 #ifdef Q_WS_X11
01175                      desc.encoding->pitch, desc.encoding->encoding
01176 #else
01177                      'p', 0
01178 #endif
01179                 );
01180 
01181             fe = loadEngine(script, fp, request, desc.family, desc.foundry, desc.style
01182 #ifdef Q_WS_X11
01183                             , desc.size, desc.encoding, (force_encoding_id >= 0)
01184 #endif
01185 #ifdef Q_WS_QWS
01186                             , desc.size
01187 #endif
01188                 );
01189         } else {
01190             FM_DEBUG("  NO MATCH FOUND\n");
01191         }
01192         if (fe)
01193             initFontDef(desc, request, &fe->fontDef);
01194     }
01195 
01196     if (fe) {
01197         if (fp) {
01198             QFontDef def = request;
01199             if (def.family.isEmpty()) {
01200                 def.family = fp->request.family;
01201                 def.family = def.family.left(def.family.indexOf(','));
01202             }
01203             QFontCache::Key key(def, script
01204 #if defined(Q_WS_X11)
01205                                 , fp->screen
01206 #endif
01207                 );
01208             QFontCache::instance->insertEngine(key, fe);
01209         }
01210 
01211 #if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)
01212         if (scriptRequiresOpenType(script)) {
01213             QOpenType *ot = fe->openType();
01214             if (!ot || !ot->supportsScript(script)) {
01215                 FM_DEBUG("  OpenType support missing for script");
01216                 fe = 0;
01217             }
01218         }
01219 #endif
01220     }
01221 
01222     if (!fe) {
01223         if (!request.family.isEmpty())
01224             return 0;
01225 
01226         FM_DEBUG("returning box engine");
01227 
01228         fe = new QFontEngineBox(request.pixelSize);
01229 
01230         if (fp) {
01231             QFontCache::Key key(request, script
01232 #if defined(Q_WS_X11)
01233                                 , fp->screen
01234 #endif
01235                 );
01236             QFontCache::instance->insertEngine(key, fe);
01237         }
01238     }
01239 
01240     if (fp) {
01241 #if defined(Q_WS_X11)
01242         fe->fontDef.pointSize = qt_pointSize(fe->fontDef.pixelSize, fp->dpi);
01243 #elif defined(Q_WS_WIN)
01244         fe->fontDef.pointSize = qreal(fe->fontDef.pixelSize) * 72.0
01245                                 / GetDeviceCaps(shared_dc,LOGPIXELSY);
01246 #elif defined(Q_WS_MAC)
01247         fe->fontDef.pointSize = qt_mac_pointsize(fe->fontDef, fp->dpi);
01248 #else
01249         fe->fontDef.pointSize = qreal(fe->fontDef.pixelSize); //####int(double(fe->fontDef.pixelSize) * 72.0 / 96.0);
01250 #endif
01251     } else {
01252         fe->fontDef.pointSize = request.pointSize;
01253     }
01254 
01255     return fe;
01256 }
01257 #endif
01258 
01259 static QString styleString(int weight, QFont::Style style)
01260 {
01261     QString result;
01262     if (weight >= QFont::Black)
01263         result = QLatin1String("Black");
01264     else if (weight >= QFont::Bold)
01265         result = QLatin1String("Bold");
01266     else if (weight >= QFont::DemiBold)
01267         result = QLatin1String("Demi Bold");
01268     else if (weight < QFont::Normal)
01269         result = QLatin1String("Light");
01270 
01271     if (style == QFont::StyleItalic)
01272         result += QLatin1String(" Italic");
01273     else if (style == QFont::StyleOblique)
01274         result += QLatin1String(" Oblique");
01275 
01276     if (result.isEmpty())
01277         result = QLatin1String("Normal");
01278 
01279     return result.simplified();
01280 }
01281 
01287 QString QFontDatabase::styleString(const QFont &font)
01288 {
01289     return ::styleString(font.weight(), font.style());
01290 }
01291 
01297 QString QFontDatabase::styleString(const QFontInfo &fontInfo)
01298 {
01299     return ::styleString(fontInfo.weight(), fontInfo.style());
01300 }
01301 
01302 
01359 QFontDatabase::QFontDatabase()
01360 {
01361     createDatabase();
01362 
01363     d = privateDb();
01364 }
01365 
01414 QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems() const
01415 {
01416     ::load();
01417 #ifdef Q_WS_X11
01418     ::checkSymbolFonts();
01419 #endif
01420 
01421     QList<WritingSystem> list;
01422     for (int i = 0; i < d->count; ++i) {
01423         QtFontFamily *family = d->families[i];
01424         if (family->count == 0)
01425             continue;
01426         for (int x = Latin; x < WritingSystemsCount; ++x) {
01427             const WritingSystem writingSystem = WritingSystem(x);
01428             if (!(family->writingSystems[writingSystem] & QtFontFamily::Supported))
01429                 continue;
01430             if (!list.contains(writingSystem))
01431                 list.append(writingSystem);
01432         }
01433     }
01434     qSort(list);
01435     return list;
01436 }
01437 
01438 
01445 QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems(const QString &family) const
01446 {
01447     QString familyName, foundryName;
01448     parseFontName(family, foundryName, familyName);
01449 
01450     ::load();
01451 #ifdef Q_WS_X11
01452     ::checkSymbolFonts(familyName);
01453 #endif
01454 
01455     QList<WritingSystem> list;
01456     QtFontFamily *f = d->family(familyName);
01457     if (!f || f->count == 0)
01458         return list;
01459 
01460     for (int x = Latin; x < WritingSystemsCount; ++x) {
01461         const WritingSystem writingSystem = WritingSystem(x);
01462         if (f->writingSystems[writingSystem] & QtFontFamily::Supported)
01463             list.append(writingSystem);
01464     }
01465     return list;
01466 }
01467 
01468 
01479 QStringList QFontDatabase::families(WritingSystem writingSystem) const
01480 {
01481     ::load();
01482 #ifdef Q_WS_X11
01483     if (writingSystem != Any)
01484         ::checkSymbolFonts();
01485 #endif
01486 
01487     QStringList flist;
01488     for (int i = 0; i < d->count; i++) {
01489         QtFontFamily *f = d->families[i];
01490         if (f->count == 0)
01491             continue;
01492         if (writingSystem != Any && (f->writingSystems[writingSystem] != QtFontFamily::Supported))
01493             continue;
01494         if (f->count == 1) {
01495             flist.append(f->name);
01496         } else {
01497             for (int j = 0; j < f->count; j++) {
01498                 QString str = f->name;
01499                 QString foundry = f->foundries[j]->name;
01500                 if (!foundry.isEmpty()) {
01501                     str += QLatin1String(" [");
01502                     str += foundry;
01503                     str += QLatin1String("]");
01504                 }
01505                 flist.append(str);
01506             }
01507         }
01508     }
01509     return flist;
01510 }
01511 
01519 QStringList QFontDatabase::styles(const QString &family) const
01520 {
01521     QString familyName, foundryName;
01522     parseFontName(family, foundryName, familyName);
01523 
01524     ::load(familyName);
01525 
01526     QStringList l;
01527     QtFontFamily *f = d->family(familyName);
01528     if (!f)
01529         return l;
01530 
01531     QtFontFoundry allStyles(foundryName);
01532     for (int j = 0; j < f->count; j++) {
01533         QtFontFoundry *foundry = f->foundries[j];
01534         if (foundryName.isEmpty() || ucstricmp(foundry->name, foundryName) == 0) {
01535             for (int k = 0; k < foundry->count; k++) {
01536                 QtFontStyle::Key ke(foundry->styles[k]->key);
01537                 ke.stretch = 0;
01538                 allStyles.style(ke, true);
01539             }
01540         }
01541     }
01542 
01543     for (int i = 0; i < allStyles.count; i++)
01544         l.append(::styleString(allStyles.styles[i]->key.weight, (QFont::Style)allStyles.styles[i]->key.style));
01545     return l;
01546 }
01547 
01553 bool QFontDatabase::isFixedPitch(const QString &family,
01554                                  const QString &style) const
01555 {
01556     Q_UNUSED(style);
01557 
01558     QString familyName, foundryName;
01559     parseFontName(family, foundryName, familyName);
01560 
01561     ::load(familyName);
01562 
01563     QtFontFamily *f = d->family(familyName);
01564 #if !defined(QWS) && defined(Q_OS_MAC)
01565     qt_mac_get_fixed_pitch(f);
01566 #endif
01567     return (f && f->fixedPitch);
01568 }
01569 
01580 bool QFontDatabase::isBitmapScalable(const QString &family,
01581                                       const QString &style) const
01582 {
01583     bool bitmapScalable = false;
01584     QString familyName, foundryName;
01585     parseFontName(family, foundryName, familyName);
01586 
01587     ::load(familyName);
01588 
01589     QtFontStyle::Key styleKey(style);
01590 
01591     QtFontFamily *f = d->family(familyName);
01592     if (!f) return bitmapScalable;
01593 
01594     for (int j = 0; j < f->count; j++) {
01595         QtFontFoundry *foundry = f->foundries[j];
01596         if (foundryName.isEmpty() || ucstricmp(foundry->name, foundryName) == 0) {
01597             for (int k = 0; k < foundry->count; k++)
01598                 if ((style.isEmpty() || foundry->styles[k]->key == styleKey)
01599                     && foundry->styles[k]->bitmapScalable && !foundry->styles[k]->smoothScalable) {
01600                     bitmapScalable = true;
01601                     goto end;
01602                 }
01603         }
01604     }
01605  end:
01606     return bitmapScalable;
01607 }
01608 
01609 
01618 bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &style) const
01619 {
01620     bool smoothScalable = false;
01621     QString familyName, foundryName;
01622     parseFontName(family, foundryName, familyName);
01623 
01624     ::load(familyName);
01625 
01626     QtFontStyle::Key styleKey(style);
01627 
01628     QtFontFamily *f = d->family(familyName);
01629     if (!f) return smoothScalable;
01630 
01631     for (int j = 0; j < f->count; j++) {
01632         QtFontFoundry *foundry = f->foundries[j];
01633         if (foundryName.isEmpty() || ucstricmp(foundry->name, foundryName) == 0) {
01634             for (int k = 0; k < foundry->count; k++)
01635                 if ((style.isEmpty() || foundry->styles[k]->key == styleKey) && foundry->styles[k]->smoothScalable) {
01636                     smoothScalable = true;
01637                     goto end;
01638                 }
01639         }
01640     }
01641  end:
01642     return smoothScalable;
01643 }
01644 
01651 bool  QFontDatabase::isScalable(const QString &family,
01652                                  const QString &style) const
01653 {
01654     if (isSmoothlyScalable(family, style))
01655         return true;
01656 
01657     return isBitmapScalable(family, style);
01658 }
01659 
01660 
01667 QList<int> QFontDatabase::pointSizes(const QString &family,
01668                                            const QString &style)
01669 {
01670 #if defined(Q_WS_WIN)
01671     // windows and macosx are always smoothly scalable
01672     Q_UNUSED(family);
01673     Q_UNUSED(style);
01674     return standardSizes();
01675 #else
01676     bool smoothScalable = false;
01677     QString familyName, foundryName;
01678     parseFontName(family, foundryName, familyName);
01679 
01680     ::load(familyName);
01681 
01682     QtFontStyle::Key styleKey(style);
01683 
01684     QList<int> sizes;
01685 
01686     QtFontFamily *fam = d->family(familyName);
01687     if (!fam) return sizes;
01688 
01689 
01690 #ifdef Q_WS_X11
01691     int dpi = QX11Info::appDpiY();
01692 #else
01693     const int dpi = 72; // embedded
01694 #endif
01695 
01696     for (int j = 0; j < fam->count; j++) {
01697         QtFontFoundry *foundry = fam->foundries[j];
01698         if (foundryName.isEmpty() || ucstricmp(foundry->name, foundryName) == 0) {
01699             QtFontStyle *style = foundry->style(styleKey);
01700             if (!style) continue;
01701 
01702             if (style->smoothScalable) {
01703                 smoothScalable = true;
01704                 goto end;
01705             }
01706             for (int l = 0; l < style->count; l++) {
01707                 const QtFontSize *size = style->pixelSizes + l;
01708 
01709                 if (size->pixelSize != 0 && size->pixelSize != USHRT_MAX) {
01710                     const uint pointSize = qRound(size->pixelSize * dpi / 72.);
01711                     if (! sizes.contains(pointSize))
01712                         sizes.append(pointSize);
01713                 }
01714             }
01715         }
01716     }
01717  end:
01718     if (smoothScalable)
01719         return standardSizes();
01720 
01721     qSort(sizes);
01722     return sizes;
01723 #endif
01724 }
01725 
01732 QFont QFontDatabase::font(const QString &family, const QString &style,
01733                            int pointSize) const
01734 {
01735     QString familyName, foundryName;
01736     parseFontName(family, foundryName, familyName);
01737 
01738     ::load(familyName);
01739 
01740     QtFontFoundry allStyles(foundryName);
01741     QtFontFamily *f = d->family(familyName);
01742     if (!f) return QApplication::font();
01743 
01744     for (int j = 0; j < f->count; j++) {
01745         QtFontFoundry *foundry = f->foundries[j];
01746         if (foundryName.isEmpty() || ucstricmp(foundry->name, foundryName) == 0) {
01747             for (int k = 0; k < foundry->count; k++)
01748                 allStyles.style(foundry->styles[k]->key, true);
01749         }
01750     }
01751 
01752     QtFontStyle::Key styleKey(style);
01753     QtFontStyle *s = bestStyle(&allStyles, styleKey);
01754 
01755     if (!s) // no styles found?
01756         return QApplication::font();
01757     QFont fnt(family, pointSize, s->key.weight);
01758     fnt.setStyle((QFont::Style)s->key.style);
01759     return fnt;
01760 }
01761 
01762 
01771 QList<int> QFontDatabase::smoothSizes(const QString &family,
01772                                             const QString &style)
01773 {
01774 #ifdef Q_WS_WIN
01775     Q_UNUSED(family);
01776     Q_UNUSED(style);
01777     return QFontDatabase::standardSizes();
01778 #else
01779     bool smoothScalable = false;
01780     QString familyName, foundryName;
01781     parseFontName(family, foundryName, familyName);
01782 
01783     ::load(familyName);
01784 
01785     QtFontStyle::Key styleKey(style);
01786 
01787     QList<int> sizes;
01788 
01789     QtFontFamily *fam = d->family(familyName);
01790     if (!fam)
01791         return sizes;
01792 
01793 #ifdef Q_WS_X11
01794     int dpi = QX11Info::appDpiY();
01795 #else
01796     const int dpi = 72; // embedded
01797 #endif
01798     for (int j = 0; j < fam->count; j++) {
01799         QtFontFoundry *foundry = fam->foundries[j];
01800         if (foundryName.isEmpty() ||
01801              ucstricmp(foundry->name, foundryName) == 0) {
01802             QtFontStyle *style = foundry->style(styleKey);
01803             if (!style) continue;
01804 
01805             if (style->smoothScalable) {
01806                 smoothScalable = true;
01807                 goto end;
01808             }
01809             for (int l = 0; l < style->count; l++) {
01810                 const QtFontSize *size = style->pixelSizes + l;
01811 
01812                 if (size->pixelSize != 0 && size->pixelSize != USHRT_MAX) {
01813                     const uint pointSize = qRound(size->pixelSize * dpi / 72.);
01814                     if (! sizes.contains(pointSize))
01815                         sizes.append(pointSize);
01816                 }
01817             }
01818         }
01819     }
01820  end:
01821     if (smoothScalable)
01822         return QFontDatabase::standardSizes();
01823 
01824     qSort(sizes);
01825     return sizes;
01826 #endif
01827 }
01828 
01829 
01835 QList<int> QFontDatabase::standardSizes()
01836 {
01837     QList<int> ret;
01838     static const unsigned short standard[] =
01839         { 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72, 0 };
01840     const unsigned short *sizes = standard;
01841     while (*sizes) ret << *sizes++;
01842     return ret;
01843 }
01844 
01845 
01852 bool QFontDatabase::italic(const QString &family, const QString &style) const
01853 {
01854     QString familyName, foundryName;
01855     parseFontName(family, foundryName, familyName);
01856 
01857     ::load(familyName);
01858 
01859     QtFontFoundry allStyles(foundryName);
01860     QtFontFamily *f = d->family(familyName);
01861     if (!f) return false;
01862 
01863     for (int j = 0; j < f->count; j++) {
01864         QtFontFoundry *foundry = f->foundries[j];
01865         if (foundryName.isEmpty() || ucstricmp(foundry->name, foundryName) == 0) {
01866             for (int k = 0; k < foundry->count; k++)
01867                 allStyles.style(foundry->styles[k]->key, true);
01868         }
01869     }
01870 
01871     QtFontStyle::Key styleKey(style);
01872     QtFontStyle *s = allStyles.style(styleKey);
01873     return s && s->key.style == QFont::StyleItalic;
01874 }
01875 
01876 
01883 bool QFontDatabase::bold(const QString &family,
01884                           const QString &style) const
01885 {
01886     QString familyName, foundryName;
01887     parseFontName(family, foundryName, familyName);
01888 
01889     ::load(familyName);
01890 
01891     QtFontFoundry allStyles(foundryName);
01892     QtFontFamily *f = d->family(familyName);
01893     if (!f) return false;
01894 
01895     for (int j = 0; j < f->count; j++) {
01896         QtFontFoundry *foundry = f->foundries[j];
01897         if (foundryName.isEmpty() ||
01898              ucstricmp(foundry->name, foundryName) == 0) {
01899             for (int k = 0; k < foundry->count; k++)
01900                 allStyles.style(foundry->styles[k]->key, true);
01901         }
01902     }
01903 
01904     QtFontStyle::Key styleKey(style);
01905     QtFontStyle *s = allStyles.style(styleKey);
01906     return s && s->key.weight >= QFont::Bold;
01907 }
01908 
01909 
01917 int QFontDatabase::weight(const QString &family,
01918                            const QString &style) const
01919 {
01920     QString familyName, foundryName;
01921     parseFontName(family, foundryName, familyName);
01922 
01923     ::load(familyName);
01924 
01925     QtFontFoundry allStyles(foundryName);
01926     QtFontFamily *f = d->family(familyName);
01927     if (!f) return -1;
01928 
01929     for (int j = 0; j < f->count; j++) {
01930         QtFontFoundry *foundry = f->foundries[j];
01931         if (foundryName.isEmpty() ||
01932              ucstricmp(foundry->name, foundryName) == 0) {
01933             for (int k = 0; k < foundry->count; k++)
01934                 allStyles.style(foundry->styles[k]->key, true);
01935         }
01936     }
01937 
01938     QtFontStyle::Key styleKey(style);
01939     QtFontStyle *s = allStyles.style(styleKey);
01940     return s ? s->key.weight : -1;
01941 }
01942 
01943 
01948 QString QFontDatabase::writingSystemName(WritingSystem writingSystem)
01949 {
01950     const char *name = 0;
01951     switch (writingSystem) {
01952     case Any:
01953         name = "Any";
01954         break;
01955     case Latin:
01956         name = "Latin";
01957         break;
01958     case Greek:
01959         name = "Greek";
01960         break;
01961     case Cyrillic:
01962         name = "Cyrillic";
01963         break;
01964     case Armenian:
01965         name = "Armenian";
01966         break;
01967     case Hebrew:
01968         name = "Hebrew";
01969         break;
01970     case Arabic:
01971         name = "Arabic";
01972         break;
01973     case Syriac:
01974         name = "Syriac";
01975         break;
01976     case Thaana:
01977         name = "Thaana";
01978         break;
01979     case Devanagari:
01980         name = "Devanagari";
01981         break;
01982     case Bengali:
01983         name = "Bengali";
01984         break;
01985     case Gurmukhi:
01986         name = "Gurmukhi";
01987         break;
01988     case Gujarati:
01989         name = "Gujarati";
01990         break;
01991     case Oriya:
01992         name = "Oriya";
01993         break;
01994     case Tamil:
01995         name = "Tamil";
01996         break;
01997     case Telugu:
01998         name = "Telugu";
01999         break;
02000     case Kannada:
02001         name = "Kannada";
02002         break;
02003     case Malayalam:
02004         name = "Malayalam";
02005         break;
02006     case Sinhala:
02007         name = "Sinhala";
02008         break;
02009     case Thai:
02010         name = "Thai";
02011         break;
02012     case Lao:
02013         name = "Lao";
02014         break;
02015     case Tibetan:
02016         name = "Tibetan";
02017         break;
02018     case Myanmar:
02019         name = "Myanmar";
02020         break;
02021     case Georgian:
02022         name = "Georgian";
02023         break;
02024     case Khmer:
02025         name = "Khmer";
02026         break;
02027     case SimplifiedChinese:
02028         name = "Simplified Chinese";
02029         break;
02030     case TraditionalChinese:
02031         name = "Traditional Chinese";
02032         break;
02033     case Japanese:
02034         name = "Japanese";
02035         break;
02036     case Korean:
02037         name = "Korean";
02038         break;
02039     case Vietnamese:
02040         name = "Vietnamese";
02041         break;
02042     case Symbol:
02043         name = "Symbol";
02044         break;
02045     case Ogham:
02046         name = "Ogham";
02047         break;
02048     case Runic:
02049         name = "Runic";
02050         break;
02051     default:
02052         Q_ASSERT_X(false, "QFontDatabase::writingSystemName", "invalid 'writingSystem' parameter");
02053         break;
02054     }
02055     return qApp ? qApp->translate("QFont", name) : QString::fromLatin1(name);
02056 }
02057 
02058 
02062 QString QFontDatabase::writingSystemSample(WritingSystem writingSystem)
02063 {
02064     QString sample;
02065     switch (writingSystem) {
02066     case Any:
02067     case Symbol:
02068         // show only ascii characters
02069         sample += QLatin1String("AaBbzZ");
02070         break;
02071     case Latin:
02072         // This is cheating... we only show latin-1 characters so that we don't
02073         // end up loading lots of fonts - at least on X11...
02074         sample = QLatin1String("Aa");
02075         sample += QChar(0x00C3);
02076         sample += QChar(0x00E1);
02077         sample += QLatin1String("Zz");
02078         break;
02079     case Greek:
02080         sample += QChar(0x0393);
02081         sample += QChar(0x03B1);
02082         sample += QChar(0x03A9);
02083         sample += QChar(0x03C9);
02084         break;
02085     case Cyrillic:
02086         sample += QChar(0x0414);
02087         sample += QChar(0x0434);
02088         sample += QChar(0x0436);
02089         sample += QChar(0x0402);
02090         break;
02091     case Armenian:
02092         sample += QChar(0x053f);
02093         sample += QChar(0x054f);
02094         sample += QChar(0x056f);
02095         sample += QChar(0x057f);
02096         break;
02097     case Hebrew:
02098         sample += QChar(0x05D0);
02099         sample += QChar(0x05D1);
02100         sample += QChar(0x05D2);
02101         sample += QChar(0x05D3);
02102         break;
02103     case Arabic:
02104         sample += QChar(0x0628);
02105         sample += QChar(0x0629);
02106         sample += QChar(0x062A);
02107         sample += QChar(0x063A);
02108         break;
02109     case Syriac:
02110         sample += QChar(0x0715);
02111         sample += QChar(0x0725);
02112         sample += QChar(0x0716);
02113         sample += QChar(0x0726);
02114         break;
02115     case Thaana:
02116         sample += QChar(0x0784);
02117         sample += QChar(0x0794);
02118         sample += QChar(0x078c);
02119         sample += QChar(0x078d);
02120         break;
02121     case Devanagari:
02122         sample += QChar(0x0905);
02123         sample += QChar(0x0915);
02124         sample += QChar(0x0925);
02125         sample += QChar(0x0935);
02126         break;
02127     case Bengali:
02128         sample += QChar(0x0986);
02129         sample += QChar(0x0996);
02130         sample += QChar(0x09a6);
02131         sample += QChar(0x09b6);
02132         break;
02133     case Gurmukhi:
02134         sample += QChar(0x0a05);
02135         sample += QChar(0x0a15);
02136         sample += QChar(0x0a25);
02137         sample += QChar(0x0a35);
02138         break;
02139     case Gujarati:
02140         sample += QChar(0x0a85);
02141         sample += QChar(0x0a95);
02142         sample += QChar(0x0aa5);
02143         sample += QChar(0x0ab5);
02144         break;
02145     case Oriya:
02146         sample += QChar(0x0b06);
02147         sample += QChar(0x0b16);
02148         sample += QChar(0x0b2b);
02149         sample += QChar(0x0b36);
02150         break;
02151     case Tamil:
02152         sample += QChar(0x0b89);
02153         sample += QChar(0x0b99);
02154         sample += QChar(0x0ba9);
02155         sample += QChar(0x0bb9);
02156         break;
02157     case Telugu:
02158         sample += QChar(0x0c05);
02159         sample += QChar(0x0c15);
02160         sample += QChar(0x0c25);
02161         sample += QChar(0x0c35);
02162         break;
02163     case Kannada:
02164         sample += QChar(0x0c85);
02165         sample += QChar(0x0c95);
02166         sample += QChar(0x0ca5);
02167         sample += QChar(0x0cb5);
02168         break;
02169     case Malayalam:
02170         sample += QChar(0x0d05);
02171         sample += QChar(0x0d15);
02172         sample += QChar(0x0d25);
02173         sample += QChar(0x0d35);
02174         break;
02175     case Sinhala:
02176         sample += QChar(0x0d90);
02177         sample += QChar(0x0da0);
02178         sample += QChar(0x0db0);
02179         sample += QChar(0x0dc0);
02180         break;
02181     case Thai:
02182         sample += QChar(0x0e02);
02183         sample += QChar(0x0e12);
02184         sample += QChar(0x0e22);
02185         sample += QChar(0x0e32);
02186         break;
02187     case Lao:
02188         sample += QChar(0x0e8d);
02189         sample += QChar(0x0e9d);
02190         sample += QChar(0x0ead);
02191         sample += QChar(0x0ebd);
02192         break;
02193     case Tibetan:
02194         sample += QChar(0x0f00);
02195         sample += QChar(0x0f01);
02196         sample += QChar(0x0f02);
02197         sample += QChar(0x0f03);
02198         break;
02199     case Myanmar:
02200         sample += QChar(0x1000);
02201         sample += QChar(0x1001);
02202         sample += QChar(0x1002);
02203         sample += QChar(0x1003);
02204         break;
02205     case Georgian:
02206         sample += QChar(0x10a0);
02207         sample += QChar(0x10b0);
02208         sample += QChar(0x10c0);
02209         sample += QChar(0x10d0);
02210         break;
02211     case Khmer:
02212         sample += QChar(0x1780);
02213         sample += QChar(0x1790);
02214         sample += QChar(0x17b0);
02215         sample += QChar(0x17c0);
02216         break;
02217     case SimplifiedChinese:
02218         sample += QChar(0x4e2d);
02219         sample += QChar(0x6587);
02220         sample += QChar(0x8303);
02221         sample += QChar(0x4f8b);
02222         break;
02223     case TraditionalChinese:
02224         sample += QChar(0x4e2d);
02225         sample += QChar(0x6587);
02226         sample += QChar(0x7bc4);
02227         sample += QChar(0x4f8b);
02228         break;
02229     case Japanese:
02230         sample += QChar(0x3050);
02231         sample += QChar(0x3060);
02232         sample += QChar(0x30b0);
02233         sample += QChar(0x30c0);
02234         break;
02235     case Korean:
02236         sample += QChar(0xac00);
02237         sample += QChar(0xac11);
02238         sample += QChar(0xac1a);
02239         sample += QChar(0xac2f);
02240         break;
02241     case Vietnamese:
02242         break;
02243     case Ogham:
02244         sample += QChar(0x1681);
02245         sample += QChar(0x1682);
02246         sample += QChar(0x1683);
02247         sample += QChar(0x1684);
02248         break;
02249     case Runic:
02250         sample += QChar(0x16a0);
02251         sample += QChar(0x16a1);
02252         sample += QChar(0x16a2);
02253         sample += QChar(0x16a3);
02254         break;
02255     default:
02256         break;
02257     }
02258     return sample;
02259 }
02260 
02261 
02262 void QFontDatabase::parseFontName(const QString &name, QString &foundry, QString &family)
02263 {
02264     ::parseFontName(name, foundry, family);
02265 }
02266 
02267 void QFontDatabase::createDatabase()
02268 { initializeDb(); }
02269 
02270 int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString &fileName)
02271 {
02272     QFontDatabasePrivate::ApplicationFont font;
02273     font.data = fontData;
02274     font.fileName = fileName;
02275 
02276     int i;
02277     for (i = 0; i < applicationFonts.count(); ++i)
02278         if (applicationFonts.at(i).families.isEmpty())
02279             break;
02280     if (i >= applicationFonts.count()) {
02281         applicationFonts.append(ApplicationFont());
02282         i = applicationFonts.count() - 1;
02283     }
02284 
02285     if (font.fileName.isEmpty() && !fontData.isEmpty())
02286         font.fileName = QString::fromLatin1(":qmemoryfonts/") + QString::number(i);
02287 
02288     registerFont(&font);
02289     if (font.families.isEmpty())
02290         return -1;
02291 
02292     applicationFonts[i] = font;
02293 
02294     invalidate();
02295     return i;
02296 }
02297 
02315 int QFontDatabase::addApplicationFont(const QString &fileName)
02316 {
02317     QByteArray data;
02318     QFile f(fileName);
02319     if (!(f.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
02320         if (!f.open(QIODevice::ReadOnly))
02321             return -1;
02322         data = f.readAll();
02323     }
02324     return privateDb()->addAppFont(data, fileName);
02325 }
02326 
02344 int QFontDatabase::addApplicationFontFromData(const QByteArray &fontData)
02345 {
02346     return privateDb()->addAppFont(fontData, QString() /* fileName */);
02347 }
02348 
02357 QStringList QFontDatabase::applicationFontFamilies(int id)
02358 {
02359     return privateDb()->applicationFonts.value(id).families;
02360 }
02361 
02387 #include "qfontdatabase.moc"

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