Changeset 500 for trunk/src/gui/text


Ignore:
Timestamp:
Feb 2, 2010, 10:46:30 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

gui/text: Implemented QFontDatabase::addApplicationFont()/removeApplicationFont() and friends (closes #89).

Location:
trunk/src/gui/text
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/gui/text/qfontdatabase.cpp

    r318 r500  
    582582        : count(0), families(0), reregisterAppFonts(false)
    583583#if defined(Q_WS_QWS)
    584           , stream(0)
     584        , stream(0)
     585#endif
     586#if defined(Q_WS_PM)
     587        , valid(false)
    585588#endif
    586589    { }
     
    634637    QStringList fallbackFamilies;
    635638#endif
     639
     640
     641
     642
    636643};
    637644
     
    640647    QFontCache::instance()->clear();
    641648    free();
     649
     650
     651
    642652    emit static_cast<QApplication *>(QApplication::instance())->fontDatabaseChanged();
    643653}
  • trunk/src/gui/text/qfontdatabase_pm.cpp

    r423 r500  
    6161QT_BEGIN_NAMESPACE
    6262
     63
     64
    6365struct FaceData
    6466{
     67
    6568    int index;
    6669    QString familyName;
     
    120123typedef QHash<QString, FileData> FontFileHash;
    121124static FontFileHash knownFontFiles;
    122 static bool knownFontFilesInitialized = false;
    123125
    124126static bool lookupFamilyName(FT_Face ftface, QString &familyName)
     
    287289}
    288290
     291
     292
     293
     294
     295
     296
     297
     298
     299
     300
     301
     302
     303
     304
     305
     306
     307
     308
     309
     310
     311
     312
     313
     314
     315
     316
     317
     318
     319
     320
     321
     322
     323
     324
     325
     326
     327
     328
     329
     330
     331
     332
     333
     334
     335
     336
     337
     338
     339
     340
     341
     342
     343
     344
     345
     346
     347
     348
     349
     350
     351
     352
     353
     354
     355
     356
     357
     358
     359
     360
     361
     362
     363
     364
     365
     366
     367
     368
     369
     370
     371
     372
     373
     374
     375
     376
     377
     378
     379
     380
     381
     382
     383
     384
     385
     386
     387
     388
     389
     390
     391
     392
     393
     394
     395
     396
     397
     398
     399
     400
     401
     402
     403
     404
     405
     406
    289407static void populateDatabase(const QString& fam)
    290408{
     
    313431    fontCache.beginGroup(QLatin1String("Qt/Fonts/Cache 1.0"));
    314432
    315     if (!knownFontFilesInitialized) {
    316         // get the initial list of know font files from the cache (necessary to
    317         // detect deleted font files)
    318         knownFontFilesInitialized = true;
     433    if (!db->valid) {
     434        // Obtain the initial list of known font files from the font cache in
     435        // the registry. This list is used as an in-process cache which speeds
     436        // speed up populating by eliminating the need to access the registry
     437        // each time an unknown family is requested. This list is also necessary
     438        // to detect deleted font files.
     439        FD_DEBUG("populateDatabase: INVALID, getting font list from the cache");
     440        db->valid = true;
     441        knownFontFiles.clear();
    319442        QStringList files = fontCache.childGroups();
    320443        foreach(QString file, files) {
     
    333456    QList<QFileInfo> fontFiles;
    334457
     458
    335459    ULONG bufSize = 0;
    336460    BOOL ok = PrfQueryProfileSize(HINI_USERPROFILE, "PM_Fonts", 0, &bufSize);
     
    360484                                file.append(".PFB");
    361485                            }
    362                             QFileInfo fileInfo(QFile::decodeName(file));
    363                             QString fileName = fileInfo.canonicalFilePath().toLower();
    364                             if (!fileName.isEmpty()) { // file may have been deleted
    365                                 fileInfo.setFile(fileName);
    366                                 // check the in-process file name cache
    367                                 FileData &cached = knownFontFiles[fileName];
    368                                 if (cached.fileInfo.filePath().isEmpty() ||
    369                                     cached.fileInfo.lastModified() != fileInfo.lastModified() ||
    370                                     cached.fileInfo.size() != fileInfo.size()) {
    371                                     // no cache entry or outdated, process it
    372                                     cached.fileInfo = fileInfo;
    373                                     cached.seen = true;
    374                                     fontFiles << fileInfo;
    375                                     FD_DEBUG("populateDatabase: NEW/UPDATED font file %s",
    376                                              qPrintable(fileName));
    377                                 } else {
    378                                     // just set the 'seen' flag and skip this font
    379                                     // (it's already in the database)
    380                                     knownFontFiles[fileName].seen = true;
    381                                     FD_DEBUG("populateDatabase: UNCHANGED font file %s",
    382                                              qPrintable(fileName));
    383                                 }
    384                             }
     486                            fontFiles << QFileInfo(QFile::decodeName(file));
    385487                        }
    386488                    }
     
    392494    }
    393495
    394     extern FT_Library qt_getFreetype(); // qfontengine_ft.cpp
     496    // add the application-defined fonts (only file-based)
     497    foreach(const QFontDatabasePrivate::ApplicationFont &font, db->applicationFonts) {
     498        if (!font.fileName.startsWith(QLatin1String(":qmemoryfonts/")))
     499            fontFiles << QFileInfo(font.fileName);
     500    }
     501
     502    // go through each font file and check if we have a valid cahce for it
     503    for (QList<QFileInfo>::iterator it = fontFiles.begin(); it != fontFiles.end();) {
     504        QFileInfo fileInfo = *it;
     505        QString fileName = fileInfo.canonicalFilePath().toLower();
     506        if (!fileName.isEmpty()) { // file may have been deleted
     507            fileInfo.setFile(fileName);
     508            // check the in-process file name cache
     509            FileData &cached = knownFontFiles[fileName];
     510            if (cached.fileInfo.filePath().isEmpty() ||
     511                cached.fileInfo.lastModified() != fileInfo.lastModified() ||
     512                cached.fileInfo.size() != fileInfo.size()) {
     513                // no cache entry or outdated
     514                FD_DEBUG("populateDatabase: NEW/UPDATED font file %s",
     515                         qPrintable(fileName));
     516                cached.fileInfo = fileInfo;
     517                cached.seen = true;
     518                // keep it in the list for further inspection
     519                ++it;
     520                continue;
     521            } else {
     522                // just set the 'seen' flag and skip this font
     523                // (it's already in the database)
     524                FD_DEBUG("populateDatabase: UNCHANGED font file %s",
     525                         qPrintable(fileName));
     526                cached.seen = true;
     527            }
     528        }
     529        // remove from the list, nothing to do with it
     530        it = fontFiles.erase(it);
     531    }
     532
    395533    FT_Library lib = qt_getFreetype();
    396534
    397     // go through each font file and get available faces
     535    QList<FaceData> foundFaces;
     536
     537    // go through each new/outdated font file and get available faces
    398538    foreach(const QFileInfo &fileInfo, fontFiles) {
    399         QString fileKey = fileInfo.absoluteFilePath().toLower();
     539        QString fileKey = fileInfo.FilePath().toLower();
    400540        QByteArray file = QFile::encodeName(fileKey);
    401541
     
    411551            fontCache.value(QLatin1String("Size")).toUInt() != fileInfo.size()) {
    412552            // the cache is outdated or doesn't exist, query the font file
    413 
    414             FT_Long numFaces = 0;
    415             FT_Face face;
    416 
    417             FT_Error rc = FT_New_Face(lib, file, -1, &face);
    418             if (rc == 0) {
    419                 numFaces = face->num_faces;
    420                 FT_Done_Face(face);
    421             } else {
    422                 // invalid/unsupported font file, numFaces is left 0 so that
    423                 // only DateTime and Size will be cached indicating that this
    424                 // file is not recognized
    425             }
    426 
    427             FD_DEBUG("populateDatabase: Font file %s: FT error %d, has %ld faces",
    428                      file.constData(), (int) rc, numFaces);
    429 
    430             // go throuhg each face
    431             for (FT_Long idx = 0; idx < numFaces; ++idx) {
    432                 rc = FT_New_Face(lib, file, idx, &face);
    433                 if (rc != 0)
    434                     continue;
    435 
    436                 FaceData cached;
    437 
    438                 cached.index = idx;
    439 
    440                 if (!lookupFamilyName(face, cached.familyName))
    441                     cached.familyName = QString::fromLocal8Bit(face->family_name);
    442 
    443                 // familyName may contain extra spaces (at least this is true for
    444                 // TNR.PFB that is reported as "Times New Roman ". Trim them.
    445                 cached.familyName = cached.familyName.trimmed();
    446 
    447                 cached.styleKey.style = face->style_flags & FT_STYLE_FLAG_ITALIC ?
    448                     QFont::StyleItalic : QFont::StyleNormal;
    449 
    450                 TT_OS2 *os2_table = 0;
    451                 if (face->face_flags & FT_FACE_FLAG_SFNT) {
    452                     os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
    453                 }
    454                 if (os2_table) {
    455                     // map weight and width values
    456                     if (os2_table->usWeightClass < 400)
    457                         cached.styleKey.weight = QFont::Light;
    458                     else if (os2_table->usWeightClass < 600)
    459                         cached.styleKey.weight = QFont::Normal;
    460                     else if (os2_table->usWeightClass < 700)
    461                         cached.styleKey.weight = QFont::DemiBold;
    462                     else if (os2_table->usWeightClass < 800)
    463                         cached.styleKey.weight = QFont::Bold;
    464                     else
    465                         cached.styleKey.weight = QFont::Black;
    466 
    467                     switch (os2_table->usWidthClass) {
    468                         case 1: cached.styleKey.stretch = QFont::UltraCondensed; break;
    469                         case 2: cached.styleKey.stretch = QFont::ExtraCondensed; break;
    470                         case 3: cached.styleKey.stretch = QFont::Condensed; break;
    471                         case 4: cached.styleKey.stretch = QFont::SemiCondensed; break;
    472                         case 5: cached.styleKey.stretch = QFont::Unstretched; break;
    473                         case 6: cached.styleKey.stretch = QFont::SemiExpanded; break;
    474                         case 7: cached.styleKey.stretch = QFont::Expanded; break;
    475                         case 8: cached.styleKey.stretch = QFont::ExtraExpanded; break;
    476                         case 9: cached.styleKey.stretch = QFont::UltraExpanded; break;
    477                         default: cached.styleKey.stretch = QFont::Unstretched; break;
    478                     }
    479 
    480                     quint32 unicodeRange[4] = {
    481                         os2_table->ulUnicodeRange1, os2_table->ulUnicodeRange2,
    482                         os2_table->ulUnicodeRange3, os2_table->ulUnicodeRange4
    483                     };
    484                     quint32 codePageRange[2] = {
    485                         os2_table->ulCodePageRange1, os2_table->ulCodePageRange2
    486                     };
    487                     cached.systems =
    488                         determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
    489                 } else {
    490                     // we've only got simple weight information and no stretch
    491                     cached.styleKey.weight = face->style_flags & FT_STYLE_FLAG_BOLD ?
    492                         QFont::Bold : QFont::Normal;
    493                     cached.styleKey.stretch = QFont::Unstretched;
    494                 }
    495 
    496                 cached.fixedPitch = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH;
    497 
    498                 cached.smoothScalable = face->face_flags & FT_FACE_FLAG_SCALABLE;
    499 
    500                 // the font may both be scalable and contain fixed size bitmaps
    501                 if (face->face_flags & FT_FACE_FLAG_FIXED_SIZES) {
    502                     for (FT_Int i = 0; i < face->num_fixed_sizes; ++i) {
    503                         cached.pixelSizes << face->available_sizes[i].height;
    504                     }
    505                 }
    506 
    507                 cachedFaces << cached;
    508 
    509                 FT_Done_Face(face);
    510             }
     553            cachedFaces = readFreeTypeFont(lib, file);
    511554
    512555            // store the data into the cache
    513556            fontCache.setValue(QLatin1String("DateTime"), fileInfo.lastModified());
    514557            fontCache.setValue(QLatin1String("Size"), fileInfo.size());
     558
     559
     560
     561
    515562            foreach(FaceData cached, cachedFaces) {
    516563                QByteArray rawData;
     
    525572        } else {
    526573            // take the face data from the cache
    527 
    528574            QStringList faces = fontCache.childGroups();
    529575
     
    534580                bool ok = false;
    535581                FaceData cached;
     582
    536583                cached.index = face.toInt(&ok);
    537584                if (!ok || cached.index < 0) // not a valid index
     
    549596        }
    550597
     598
     599
    551600        fontCache.endGroup();
    552 
    553         // go throuhg each cached face and add it to the database
    554         foreach(FaceData cached, cachedFaces) {
    555 
    556             QtFontFamily *family = privateDb()->family(cached.familyName, true);
    557 
    558             // @todo is it possible that the same family is both fixed and not?
    559             Q_ASSERT(!family->fixedPitch || cached.fixedPitch);
    560             family->fixedPitch = cached.fixedPitch;
    561 
    562             if (cached.systems.isEmpty()) {
    563                 // it was hard or impossible to determine the actual writing system
    564                 // of the font (as in case of OS/2 bitmap and PFB fonts for which it is
    565                 // usually simply reported that they support standard/system codepages).
    566                 // Pretend that we support all writing systems to not miss the one.
    567                 //
    568                 // @todo find a proper way to detect actual supported scripts to make
    569                 // sure these fonts are not matched for scripts they don't support.
    570                 for (int ws = 0; ws < QFontDatabase::WritingSystemsCount; ++ws)
    571                     family->writingSystems[ws] = QtFontFamily::Supported;
    572             } else {
    573                 for (int i = 0; i < cached.systems.count(); ++i)
    574                     family->writingSystems[cached.systems.at(i)] = QtFontFamily::Supported;
    575             }
    576 
    577             QtFontFoundry *foundry = family->foundry(foundryName, true);
    578             QtFontStyle *style = foundry->style(cached.styleKey, true);
    579 
    580             // so far, all recognized fonts are antialiased
    581             style->antialiased = true;
    582 
    583             if (cached.smoothScalable && !style->smoothScalable) {
    584                 // add new scalable style only if it hasn't been already added --
    585                 // the first one of two duplicate (in Qt terms) non-bitmap font
    586                 // styles wins.
    587                 style->smoothScalable = true;
    588                 QtFontSize *size =
    589                     style->pixelSize(SMOOTH_SCALABLE, true);
    590                 size->fileName = file;
    591                 size->fileIndex = cached.index;
    592                 size->systems = cached.systems;
    593             }
    594 
    595             foreach(unsigned short pixelSize, cached.pixelSizes) {
    596                 QtFontSize *size = style->pixelSize(pixelSize, true);
    597                 // the first bitmap style with a given pixel and point size wins
    598                 if (!size->fileName.isEmpty())
    599                     continue;
    600                 size->fileName = file;
    601                 size->fileIndex = cached.index;
    602                 size->systems = cached.systems;
    603             }
     601    }
     602
     603    // get available faces of the application-defined fonts (memory-based)
     604    foreach(const QFontDatabasePrivate::ApplicationFont &font, db->applicationFonts) {
     605        if (font.fileName.startsWith(QLatin1String(":qmemoryfonts/"))) {
     606            QList<FaceData> faces = readFreeTypeFont(lib, font.fileName.toLatin1(),
     607                                                     &font.data);
     608            foundFaces << faces;
     609        }
     610    }
     611
     612    // go throuhg each found face and add it to the database
     613    foreach(const FaceData &face, foundFaces) {
     614
     615        QtFontFamily *family = privateDb()->family(face.familyName, true);
     616
     617        // @todo is it possible that the same family is both fixed and not?
     618        Q_ASSERT(!family->fixedPitch || face.fixedPitch);
     619        family->fixedPitch = face.fixedPitch;
     620
     621        if (face.systems.isEmpty()) {
     622            // it was hard or impossible to determine the actual writing system
     623            // of the font (as in case of OS/2 bitmap and PFB fonts for which it is
     624            // usually simply reported that they support standard/system codepages).
     625            // Pretend that we support all writing systems to not miss the one.
     626            //
     627            // @todo find a proper way to detect actual supported scripts to make
     628            // sure these fonts are not matched for scripts they don't support.
     629            for (int ws = 0; ws < QFontDatabase::WritingSystemsCount; ++ws)
     630                family->writingSystems[ws] = QtFontFamily::Supported;
     631        } else {
     632            for (int i = 0; i < face.systems.count(); ++i)
     633                family->writingSystems[face.systems.at(i)] = QtFontFamily::Supported;
     634        }
     635
     636        QtFontFoundry *foundry = family->foundry(foundryName, true);
     637        QtFontStyle *style = foundry->style(face.styleKey, true);
     638
     639        // so far, all recognized fonts are antialiased
     640        style->antialiased = true;
     641
     642        if (face.smoothScalable && !style->smoothScalable) {
     643            // add new scalable style only if it hasn't been already added --
     644            // the first one of two duplicate (in Qt terms) non-bitmap font
     645            // styles wins.
     646            style->smoothScalable = true;
     647            QtFontSize *size =
     648                style->pixelSize(SMOOTH_SCALABLE, true);
     649            size->fileName = face.file;
     650            size->fileIndex = face.index;
     651            size->systems = face.systems;
     652        }
     653
     654        foreach(unsigned short pixelSize, face.pixelSizes) {
     655            QtFontSize *size = style->pixelSize(pixelSize, true);
     656            // the first bitmap style with a given pixel and point size wins
     657            if (!size->fileName.isEmpty())
     658                continue;
     659            size->fileName = face.file;
     660            size->fileIndex = face.index;
     661            size->systems = face.systems;
    604662        }
    605663    }
     
    683741static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
    684742{
    685     // @todo implement
     743    Q_ASSERT(fnt);
     744    if (!fnt)
     745        return;
     746
     747    QByteArray file =
     748        QFile::encodeName(QDir::current().absoluteFilePath(fnt->fileName));
     749
     750    FT_Library lib = qt_getFreetype();
     751    QList<FaceData> faces = readFreeTypeFont(lib, file, &fnt->data);
     752
     753    QStringList families;
     754
     755    foreach(const FaceData &face, faces)
     756        if (!families.contains(face.familyName))
     757            families << face.familyName;
     758
     759    fnt->families = families;
    686760}
    687761
     
    896970bool QFontDatabase::removeApplicationFont(int handle)
    897971{
    898     // @todo implement
     972    // nothing special to do here; just empty the given ApplicationFont entry
     973
     974    QMutexLocker locker(fontDatabaseMutex());
     975
     976    QFontDatabasePrivate *db = privateDb();
     977    if (handle < 0 || handle >= db->applicationFonts.count())
     978        return false;
     979
     980    db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
     981
     982    db->invalidate();
     983    return true;
     984}
     985
     986bool QFontDatabase::removeAllApplicationFonts()
     987{
     988    // nothing special to do here; just empty all ApplicationFont entries
     989
     990    QMutexLocker locker(fontDatabaseMutex());
     991
     992    QFontDatabasePrivate *db = privateDb();
     993    if (db->applicationFonts.isEmpty())
     994        return false;
     995
     996    db->applicationFonts.clear();
     997    db->invalidate();
     998    return true;
     999}
     1000
     1001bool QFontDatabase::supportsThreadedFontRendering()
     1002{
     1003    // qt_getFreetype() returns a global static FT_Library object but
     1004    // FreeType2 docs say that each thread should use its own FT_Library
     1005    // object. For this reason, we return false here to prevent apps from
     1006    // rendering fonts on threads other than the main GUI thread.
    8991007    return false;
    9001008}
    9011009
    902 bool QFontDatabase::removeAllApplicationFonts()
    903 {
    904     // @todo implement
    905     return false;
    906 }
    907 
    908 bool QFontDatabase::supportsThreadedFontRendering()
    909 {
    910     // @todo implement
    911     return false;
    912 }
    913 
    9141010QT_END_NAMESPACE
Note: See TracChangeset for help on using the changeset viewer.