Changeset 230
- Timestamp:
- Oct 16, 2009, 3:22:12 PM (16 years ago)
- File:
-
- 1 edited
-
trunk/src/gui/text/qfontdatabase_pm.cpp (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gui/text/qfontdatabase_pm.cpp
r228 r230 46 46 #include "qfontengine_pm_p.h" 47 47 48 49 50 51 52 48 53 #include <ft2build.h> 49 54 #include FT_FREETYPE_H … … 53 58 54 59 QT_BEGIN_NAMESPACE 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 55 121 56 122 static void populateDatabase(const QString& fam) … … 72 138 const QString foundryName; 73 139 74 QList<QByteArray> fontFiles; 140 #ifdef QFONTDATABASE_DEBUG 141 QTime timer; 142 timer.start(); 143 #endif 144 145 QSettings fontCache(QSettings::UserScope, QLatin1String("Trolltech")); 146 fontCache.beginGroup(QLatin1String("Qt/Fonts/Cache 1.0")); 147 148 if (!knownFontFilesInitialized) { 149 // get the initial list of know font files from the cache (necessary to 150 // detect deleted font files) 151 knownFontFilesInitialized = true; 152 QStringList files = fontCache.childGroups(); 153 foreach(QString file, files) { 154 file.replace("|", "/"); 155 knownFontFiles.insert(file, FileData()); 156 // note that QFileInfo is empty so the file will be considered as 157 // NEW which is necessary for the font to get into the database 158 } 159 } else { 160 // reset the 'seen' flag 161 for (FontFileHash::iterator it = knownFontFiles.begin(); 162 it != knownFontFiles.end(); ++it) 163 it.value().seen = false; 164 } 165 166 QList<QFileInfo> fontFiles; 75 167 76 168 ULONG bufSize = 0; … … 101 193 file.append(".PFB"); 102 194 } 103 fontFiles << file; 195 QFileInfo fileInfo(QFile::decodeName(file)); 196 QString fileName = fileInfo.canonicalFilePath().toLower(); 197 if (!fileName.isEmpty()) { // file may have been deleted 198 fileInfo.setFile(fileName); 199 // check the in-process file name cache 200 FileData &cached = knownFontFiles[fileName]; 201 if (cached.fileInfo.filePath().isEmpty() || 202 cached.fileInfo.lastModified() != fileInfo.lastModified() || 203 cached.fileInfo.size() != fileInfo.size()) { 204 // no cache entry or outdated, process it 205 cached.fileInfo = fileInfo; 206 cached.seen = true; 207 fontFiles << fileInfo; 208 FD_DEBUG("populateDatabase: NEW/UPDATED font file %s", 209 qPrintable(fileName)); 210 } else { 211 // just set the 'seen' flag and skip this font 212 // (it's already in the database) 213 knownFontFiles[fileName].seen = true; 214 FD_DEBUG("populateDatabase: UNCHANGED font file %s", 215 qPrintable(fileName)); 216 } 217 } 104 218 } 105 219 } … … 114 228 FT_Library lib = qt_getFreetype(); 115 229 116 foreach(const QByteArray &file, fontFiles) { 117 FT_Face face; 118 FT_Error rc = FT_New_Face(lib, file, -1, &face); 119 120 FD_DEBUG("populateDatabase: Font file %s: FT error %d, has %ld faces", 121 file.constData(), (int) rc, rc ? -1 : face->num_faces); 122 if (rc != 0) 123 continue; 124 125 FT_Long numFaces = face->num_faces; 126 FT_Done_Face(face); 127 128 // go throuhg each face 129 for (FT_Long idx = 0; idx < numFaces; ++idx) { 130 rc = FT_New_Face(lib, file, idx, &face); 131 if (rc != 0) 132 continue; 133 134 QString familyName = QString::fromLatin1(face->family_name); 135 136 // familyName may contain extra spaces (at least this is true for 137 // TNR.PFB that is reported as "Times New Roman ". Trim them. 138 familyName = familyName.trimmed(); 139 140 QtFontStyle::Key styleKey; 141 142 styleKey.style = face->style_flags & FT_STYLE_FLAG_ITALIC ? 143 QFont::StyleItalic : QFont::StyleNormal; 144 145 QList<QFontDatabase::WritingSystem> systems; 146 147 TT_OS2 *os2_table = 0; 148 if (face->face_flags & FT_FACE_FLAG_SFNT) { 149 os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); 150 } 151 if (os2_table) { 152 // map weight and width values 153 if (os2_table->usWeightClass < 400) 154 styleKey.weight = QFont::Light; 155 else if (os2_table->usWeightClass < 600) 156 styleKey.weight = QFont::Normal; 157 else if (os2_table->usWeightClass < 700) 158 styleKey.weight = QFont::DemiBold; 159 else if (os2_table->usWeightClass < 800) 160 styleKey.weight = QFont::Bold; 161 else 162 styleKey.weight = QFont::Black; 163 164 switch (os2_table->usWidthClass) { 165 case 1: styleKey.stretch = QFont::UltraCondensed; break; 166 case 2: styleKey.stretch = QFont::ExtraCondensed; break; 167 case 3: styleKey.stretch = QFont::Condensed; break; 168 case 4: styleKey.stretch = QFont::SemiCondensed; break; 169 case 5: styleKey.stretch = QFont::Unstretched; break; 170 case 6: styleKey.stretch = QFont::SemiExpanded; break; 171 case 7: styleKey.stretch = QFont::Expanded; break; 172 case 8: styleKey.stretch = QFont::ExtraExpanded; break; 173 case 9: styleKey.stretch = QFont::UltraExpanded; break; 174 default: styleKey.stretch = QFont::Unstretched; break; 230 // go through each font file and get available faces 231 foreach(const QFileInfo &fileInfo, fontFiles) { 232 QString fileKey = fileInfo.absoluteFilePath().toLower(); 233 QByteArray file = QFile::encodeName(fileKey); 234 235 // QSettings uses / for splitting into groups, suppress it 236 fileKey.replace("/", "|"); 237 238 QList<FaceData> cachedFaces; 239 240 // first, look up the cached data 241 fontCache.beginGroup(fileKey); 242 243 if (fontCache.value(QLatin1String("DateTime")).toDateTime() != fileInfo.lastModified() || 244 fontCache.value(QLatin1String("Size")).toUInt() != fileInfo.size()) { 245 // the cache is outdated or doesn't exist, query the font file 246 247 FT_Long numFaces = 0; 248 FT_Face face; 249 250 FT_Error rc = FT_New_Face(lib, file, -1, &face); 251 if (rc == 0) { 252 numFaces = face->num_faces; 253 FT_Done_Face(face); 254 } else { 255 // invalid/unsupported font file, numFaces is left 0 so that 256 // only DateTime and Size will be cached indicating that this 257 // file is not recognized 258 } 259 260 FD_DEBUG("populateDatabase: Font file %s: FT error %d, has %ld faces", 261 file.constData(), (int) rc, numFaces); 262 263 // go throuhg each face 264 for (FT_Long idx = 0; idx < numFaces; ++idx) { 265 rc = FT_New_Face(lib, file, idx, &face); 266 if (rc != 0) 267 continue; 268 269 FaceData cached; 270 271 cached.index = idx; 272 cached.familyName = QString::fromLatin1(face->family_name); 273 274 // familyName may contain extra spaces (at least this is true for 275 // TNR.PFB that is reported as "Times New Roman ". Trim them. 276 cached.familyName = cached.familyName.trimmed(); 277 278 cached.styleKey.style = face->style_flags & FT_STYLE_FLAG_ITALIC ? 279 QFont::StyleItalic : QFont::StyleNormal; 280 281 TT_OS2 *os2_table = 0; 282 if (face->face_flags & FT_FACE_FLAG_SFNT) { 283 os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); 175 284 } 176 177 quint32 unicodeRange[4] = { 178 os2_table->ulUnicodeRange1, os2_table->ulUnicodeRange2, 179 os2_table->ulUnicodeRange3, os2_table->ulUnicodeRange4 180 }; 181 quint32 codePageRange[2] = { 182 os2_table->ulCodePageRange1, os2_table->ulCodePageRange2 183 }; 184 systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); 185 } else { 186 // we've only got simple weight information and no stretch 187 styleKey.weight = face->style_flags & FT_STYLE_FLAG_BOLD ? 188 QFont::Bold : QFont::Normal; 189 styleKey.stretch = QFont::Unstretched; 190 } 191 192 QtFontFamily *family = privateDb()->family(familyName, true); 285 if (os2_table) { 286 // map weight and width values 287 if (os2_table->usWeightClass < 400) 288 cached.styleKey.weight = QFont::Light; 289 else if (os2_table->usWeightClass < 600) 290 cached.styleKey.weight = QFont::Normal; 291 else if (os2_table->usWeightClass < 700) 292 cached.styleKey.weight = QFont::DemiBold; 293 else if (os2_table->usWeightClass < 800) 294 cached.styleKey.weight = QFont::Bold; 295 else 296 cached.styleKey.weight = QFont::Black; 297 298 switch (os2_table->usWidthClass) { 299 case 1: cached.styleKey.stretch = QFont::UltraCondensed; break; 300 case 2: cached.styleKey.stretch = QFont::ExtraCondensed; break; 301 case 3: cached.styleKey.stretch = QFont::Condensed; break; 302 case 4: cached.styleKey.stretch = QFont::SemiCondensed; break; 303 case 5: cached.styleKey.stretch = QFont::Unstretched; break; 304 case 6: cached.styleKey.stretch = QFont::SemiExpanded; break; 305 case 7: cached.styleKey.stretch = QFont::Expanded; break; 306 case 8: cached.styleKey.stretch = QFont::ExtraExpanded; break; 307 case 9: cached.styleKey.stretch = QFont::UltraExpanded; break; 308 default: cached.styleKey.stretch = QFont::Unstretched; break; 309 } 310 311 quint32 unicodeRange[4] = { 312 os2_table->ulUnicodeRange1, os2_table->ulUnicodeRange2, 313 os2_table->ulUnicodeRange3, os2_table->ulUnicodeRange4 314 }; 315 quint32 codePageRange[2] = { 316 os2_table->ulCodePageRange1, os2_table->ulCodePageRange2 317 }; 318 cached.systems = 319 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); 320 } else { 321 // we've only got simple weight information and no stretch 322 cached.styleKey.weight = face->style_flags & FT_STYLE_FLAG_BOLD ? 323 QFont::Bold : QFont::Normal; 324 cached.styleKey.stretch = QFont::Unstretched; 325 } 326 327 cached.fixedPitch = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH; 328 329 cached.smoothScalable = face->face_flags & FT_FACE_FLAG_SCALABLE; 330 331 // the font may both be scalable and contain fixed size bitmaps 332 if (face->face_flags & FT_FACE_FLAG_FIXED_SIZES) { 333 for (FT_Int i = 0; i < face->num_fixed_sizes; ++i) { 334 cached.pixelSizes << face->available_sizes[i].height; 335 } 336 } 337 338 cachedFaces << cached; 339 340 FT_Done_Face(face); 341 } 342 343 // store the data into the cache 344 fontCache.setValue(QLatin1String("DateTime"), fileInfo.lastModified()); 345 fontCache.setValue(QLatin1String("Size"), fileInfo.size()); 346 foreach(FaceData cached, cachedFaces) { 347 QByteArray rawData; 348 QDataStream data(&rawData, QIODevice::WriteOnly); 349 data << cached; 350 351 QString face = QString::number(cached.index); 352 fontCache.beginGroup(face); 353 fontCache.setValue(QLatin1String("Info"), rawData); 354 fontCache.endGroup(); 355 } 356 } else { 357 // take the face data from the cache 358 359 QStringList faces = fontCache.childGroups(); 360 361 FD_DEBUG("populateDatabase: Font file %s: IN CACHE, has %d faces", 362 file.constData(), faces.count()); 363 364 foreach(QString face, faces) { 365 bool ok = false; 366 FaceData cached; 367 cached.index = face.toInt(&ok); 368 if (!ok || cached.index < 0) // not a valid index 369 continue; 370 371 fontCache.beginGroup(face); 372 QByteArray rawData = 373 fontCache.value(QLatin1String("Info")).toByteArray(); 374 QDataStream data(rawData); 375 data >> cached; 376 fontCache.endGroup(); 377 378 cachedFaces << cached; 379 } 380 } 381 382 fontCache.endGroup(); 383 384 // go throuhg each cached face and add it to the database 385 foreach(FaceData cached, cachedFaces) { 386 387 QtFontFamily *family = privateDb()->family(cached.familyName, true); 193 388 194 389 // @todo is it possible that the same family is both fixed and not? 195 Q_ASSERT(!family->fixedPitch || face->face_flags & FT_FACE_FLAG_FIXED_WIDTH);196 family->fixedPitch = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH;197 198 if ( systems.isEmpty() ||familyName.compare("Workplace Sans")) {390 Q_ASSERT(!family->fixedPitch || ); 391 family->fixedPitch = ; 392 393 if (familyName.compare("Workplace Sans")) { 199 394 // it was hard or impossible to determine the actual writing system 200 395 // of the font (as in case of OS/2 bitmap and PFB fonts for which it is … … 210 405 family->writingSystems[ws] = QtFontFamily::Supported; 211 406 } else { 212 for (int i = 0; i < systems.count(); ++i)213 family->writingSystems[ systems.at(i)] = QtFontFamily::Supported;407 for (int i = 0; i < systems.count(); ++i) 408 family->writingSystems[systems.at(i)] = QtFontFamily::Supported; 214 409 } 215 410 216 411 QtFontFoundry *foundry = family->foundry(foundryName, true); 217 QtFontStyle *style = foundry->style( styleKey, true);412 QtFontStyle *style = foundry->style(styleKey, true); 218 413 219 414 // so far, all recognized fonts are antialiased 220 415 style->antialiased = true; 221 416 222 if ((face->face_flags & FT_FACE_FLAG_SCALABLE) && 223 !style->smoothScalable) { 417 if (cached.smoothScalable && !style->smoothScalable) { 224 418 // add new scalable style only if it hasn't been already added -- 225 419 // the first one of two duplicate (in Qt terms) non-bitmap font … … 229 423 style->pixelSize(SMOOTH_SCALABLE, true); 230 424 size->fileName = file; 231 size->fileIndex = idx; 232 } 233 234 // the font may both be scalable and contain fixed size bitmaps 235 if (face->face_flags & FT_FACE_FLAG_FIXED_SIZES) { 236 for (FT_Int i = 0; i < face->num_fixed_sizes; ++i) { 237 QtFontSize *size = 238 style->pixelSize(face->available_sizes[i].height, true); 239 // the first bitmap style with a given pixel and point size wins 240 if (!size->fileName.isEmpty()) 241 continue; 242 size->fileName = file; 243 size->fileIndex = idx; 244 } 245 } 246 247 FT_Done_Face(face); 248 } 249 } 425 size->fileIndex = cached.index; 426 } 427 428 foreach(unsigned short pixelSize, cached.pixelSizes) { 429 QtFontSize *size = style->pixelSize(pixelSize, true); 430 // the first bitmap style with a given pixel and point size wins 431 if (!size->fileName.isEmpty()) 432 continue; 433 size->fileName = file; 434 size->fileIndex = cached.index; 435 } 436 } 437 } 438 439 // go through the known file list to detect what files have been removed 440 for (FontFileHash::iterator it = knownFontFiles.begin(); 441 it != knownFontFiles.end();) { 442 if (!it.value().seen) { 443 FD_DEBUG("populateDatabase: DELETED font file %s", 444 qPrintable(it.key())); 445 // remove from the both caches 446 QString fileKey = it.key(); 447 fileKey.replace("/", "|"); 448 fontCache.remove(fileKey); 449 it = knownFontFiles.erase(it); 450 // @todo should we remove all references to this file from the 451 // font database? My concern is that this font may be in use by Qt 452 // and its glyphs may be still cached when file deletion happens 453 } else { 454 ++it; 455 } 456 } 457 458 #ifdef QFONTDATABASE_DEBUG 459 FD_DEBUG("populateDatabase: took %d ms", timer.elapsed()); 460 #endif 250 461 } 251 462
Note:
See TracChangeset
for help on using the changeset viewer.
