- Timestamp:
- Feb 2, 2010, 10:46:30 PM (15 years ago)
- Location:
- trunk/src/gui/text
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gui/text/qfontdatabase.cpp
r318 r500 582 582 : count(0), families(0), reregisterAppFonts(false) 583 583 #if defined(Q_WS_QWS) 584 , stream(0) 584 , stream(0) 585 #endif 586 #if defined(Q_WS_PM) 587 , valid(false) 585 588 #endif 586 589 { } … … 634 637 QStringList fallbackFamilies; 635 638 #endif 639 640 #if defined(Q_WS_PM) 641 bool valid; 642 #endif 636 643 }; 637 644 … … 640 647 QFontCache::instance()->clear(); 641 648 free(); 649 #if defined(Q_WS_PM) 650 valid = false; 651 #endif 642 652 emit static_cast<QApplication *>(QApplication::instance())->fontDatabaseChanged(); 643 653 } -
trunk/src/gui/text/qfontdatabase_pm.cpp
r423 r500 61 61 QT_BEGIN_NAMESPACE 62 62 63 extern FT_Library qt_getFreetype(); // qfontengine_ft.cpp 64 63 65 struct FaceData 64 66 { 67 QByteArray file; 65 68 int index; 66 69 QString familyName; … … 120 123 typedef QHash<QString, FileData> FontFileHash; 121 124 static FontFileHash knownFontFiles; 122 static bool knownFontFilesInitialized = false;123 125 124 126 static bool lookupFamilyName(FT_Face ftface, QString &familyName) … … 287 289 } 288 290 291 static QList<FaceData> readFreeTypeFont(FT_Library lib, const QByteArray &file, 292 const QByteArray *data = 0) 293 { 294 QList<FaceData> faces; 295 296 FT_Long numFaces = 0; 297 FT_Face face; 298 299 bool isMemFont = file.startsWith(":qmemoryfonts/"); 300 Q_ASSERT(!isMemFont || data); 301 302 FT_Error rc = isMemFont ? 303 FT_New_Memory_Face(lib, (const FT_Byte *)data->constData(), 304 data->size(), -1, &face) : 305 FT_New_Face(lib, file, -1, &face); 306 307 if (rc == 0) { 308 numFaces = face->num_faces; 309 FT_Done_Face(face); 310 } else { 311 // note: for invalid/unsupported font file, numFaces is left 0 so that 312 // this function will return an empty list 313 } 314 315 FD_DEBUG("readFreeTypeFont: Font file %s: FT error %d, has %ld faces", 316 file.constData(), (int) rc, numFaces); 317 318 // go throuhg each face 319 for (FT_Long idx = 0; idx < numFaces; ++idx) { 320 rc = isMemFont ? 321 FT_New_Memory_Face(lib, (const FT_Byte *)data->constData(), 322 data->size(), idx, &face) : 323 FT_New_Face(lib, file, idx, &face); 324 if (rc != 0) 325 continue; 326 327 FaceData faceData; 328 329 faceData.file = file; 330 faceData.index = idx; 331 332 if (!lookupFamilyName(face, faceData.familyName)) 333 faceData.familyName = QString::fromLocal8Bit(face->family_name); 334 335 // familyName may contain extra spaces (at least this is true for 336 // TNR.PFB that is reported as "Times New Roman ". Trim them. 337 faceData.familyName = faceData.familyName.trimmed(); 338 339 faceData.styleKey.style = face->style_flags & FT_STYLE_FLAG_ITALIC ? 340 QFont::StyleItalic : QFont::StyleNormal; 341 342 TT_OS2 *os2_table = 0; 343 if (face->face_flags & FT_FACE_FLAG_SFNT) { 344 os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); 345 } 346 if (os2_table) { 347 // map weight and width values 348 if (os2_table->usWeightClass < 400) 349 faceData.styleKey.weight = QFont::Light; 350 else if (os2_table->usWeightClass < 600) 351 faceData.styleKey.weight = QFont::Normal; 352 else if (os2_table->usWeightClass < 700) 353 faceData.styleKey.weight = QFont::DemiBold; 354 else if (os2_table->usWeightClass < 800) 355 faceData.styleKey.weight = QFont::Bold; 356 else 357 faceData.styleKey.weight = QFont::Black; 358 359 switch (os2_table->usWidthClass) { 360 case 1: faceData.styleKey.stretch = QFont::UltraCondensed; break; 361 case 2: faceData.styleKey.stretch = QFont::ExtraCondensed; break; 362 case 3: faceData.styleKey.stretch = QFont::Condensed; break; 363 case 4: faceData.styleKey.stretch = QFont::SemiCondensed; break; 364 case 5: faceData.styleKey.stretch = QFont::Unstretched; break; 365 case 6: faceData.styleKey.stretch = QFont::SemiExpanded; break; 366 case 7: faceData.styleKey.stretch = QFont::Expanded; break; 367 case 8: faceData.styleKey.stretch = QFont::ExtraExpanded; break; 368 case 9: faceData.styleKey.stretch = QFont::UltraExpanded; break; 369 default: faceData.styleKey.stretch = QFont::Unstretched; break; 370 } 371 372 quint32 unicodeRange[4] = { 373 os2_table->ulUnicodeRange1, os2_table->ulUnicodeRange2, 374 os2_table->ulUnicodeRange3, os2_table->ulUnicodeRange4 375 }; 376 quint32 codePageRange[2] = { 377 os2_table->ulCodePageRange1, os2_table->ulCodePageRange2 378 }; 379 faceData.systems = 380 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); 381 } else { 382 // we've only got simple weight information and no stretch 383 faceData.styleKey.weight = face->style_flags & FT_STYLE_FLAG_BOLD ? 384 QFont::Bold : QFont::Normal; 385 faceData.styleKey.stretch = QFont::Unstretched; 386 } 387 388 faceData.fixedPitch = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH; 389 390 faceData.smoothScalable = face->face_flags & FT_FACE_FLAG_SCALABLE; 391 392 // the font may both be scalable and contain fixed size bitmaps 393 if (face->face_flags & FT_FACE_FLAG_FIXED_SIZES) { 394 for (FT_Int i = 0; i < face->num_fixed_sizes; ++i) { 395 faceData.pixelSizes << face->available_sizes[i].height; 396 } 397 } 398 399 faces << faceData; 400 401 FT_Done_Face(face); 402 } 403 404 return faces; 405 } 406 289 407 static void populateDatabase(const QString& fam) 290 408 { … … 313 431 fontCache.beginGroup(QLatin1String("Qt/Fonts/Cache 1.0")); 314 432 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(); 319 442 QStringList files = fontCache.childGroups(); 320 443 foreach(QString file, files) { … … 333 456 QList<QFileInfo> fontFiles; 334 457 458 // take the font files from HINI_USERPROFILE\PM_Fonts 335 459 ULONG bufSize = 0; 336 460 BOOL ok = PrfQueryProfileSize(HINI_USERPROFILE, "PM_Fonts", 0, &bufSize); … … 360 484 file.append(".PFB"); 361 485 } 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)); 385 487 } 386 488 } … … 392 494 } 393 495 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 395 533 FT_Library lib = qt_getFreetype(); 396 534 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 398 538 foreach(const QFileInfo &fileInfo, fontFiles) { 399 QString fileKey = fileInfo. absoluteFilePath().toLower();539 QString fileKey = fileInfo.canonicalFilePath().toLower(); 400 540 QByteArray file = QFile::encodeName(fileKey); 401 541 … … 411 551 fontCache.value(QLatin1String("Size")).toUInt() != fileInfo.size()) { 412 552 // 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); 511 554 512 555 // store the data into the cache 513 556 fontCache.setValue(QLatin1String("DateTime"), fileInfo.lastModified()); 514 557 fontCache.setValue(QLatin1String("Size"), fileInfo.size()); 558 559 // note: for an invalid/unsupported font file, cachedFaces is empty, 560 // so only DateTime and Size will be cached indicating hat this 561 // file is not recognized 515 562 foreach(FaceData cached, cachedFaces) { 516 563 QByteArray rawData; … … 525 572 } else { 526 573 // take the face data from the cache 527 528 574 QStringList faces = fontCache.childGroups(); 529 575 … … 534 580 bool ok = false; 535 581 FaceData cached; 582 cached.file = file; 536 583 cached.index = face.toInt(&ok); 537 584 if (!ok || cached.index < 0) // not a valid index … … 549 596 } 550 597 598 foundFaces << cachedFaces; 599 551 600 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; 604 662 } 605 663 } … … 683 741 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) 684 742 { 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; 686 760 } 687 761 … … 896 970 bool QFontDatabase::removeApplicationFont(int handle) 897 971 { 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 986 bool 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 1001 bool 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. 899 1007 return false; 900 1008 } 901 1009 902 bool QFontDatabase::removeAllApplicationFonts()903 {904 // @todo implement905 return false;906 }907 908 bool QFontDatabase::supportsThreadedFontRendering()909 {910 // @todo implement911 return false;912 }913 914 1010 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.