Changeset 846 for trunk/src/gui/text/qfontdatabase_s60.cpp
- Timestamp:
- May 5, 2011, 5:36:53 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/vendor/nokia/qt/4.7.2 (added) merged: 845 /branches/vendor/nokia/qt/current merged: 844 /branches/vendor/nokia/qt/4.6.3 removed
- Property svn:mergeinfo changed
-
trunk/src/gui/text/qfontdatabase_s60.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 46 46 #include "qabstractfileengine.h" 47 47 #include "qdesktopservices.h" 48 #include "qpixmap_s60_p.h" 49 #include "qt_s60_p.h" 48 #include "qtemporaryfile.h" 49 #include "qtextcodec.h" 50 #include <private/qpixmap_s60_p.h> 51 #include <private/qt_s60_p.h> 50 52 #include "qendian.h" 51 53 #include <private/qcore_symbian_p.h> 52 #if defined(QT_NO_FREETYPE)54 #ifdef QT_NO_FREETYPE 53 55 #include <openfont.h> 54 56 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS 55 57 #include <graphics/openfontrasterizer.h> // COpenFontRasterizer has moved to a new header file 56 58 #endif // SYMBIAN_ENABLE_SPLIT_HEADERS 57 #endif 59 #endif // QT_NO_FREETYPE 58 60 59 61 QT_BEGIN_NAMESPACE 62 63 QStringList qt_symbian_fontFamiliesOnFontServer() // Also used in qfont_s60.cpp 64 { 65 QStringList result; 66 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); 67 const int numTypeFaces = S60->screenDevice()->NumTypefaces(); 68 for (int i = 0; i < numTypeFaces; i++) { 69 TTypefaceSupport typefaceSupport; 70 S60->screenDevice()->TypefaceSupport(typefaceSupport, i); 71 const QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length()); 72 result.append(familyName); 73 } 74 lock.relock(); 75 return result; 76 } 60 77 61 78 QFileInfoList alternativeFilePaths(const QString &path, const QStringList &nameFilters, … … 92 109 } 93 110 94 #if defined(QT_NO_FREETYPE)111 #ifdef QT_NO_FREETYPE 95 112 class QSymbianFontDatabaseExtrasImplementation : public QSymbianFontDatabaseExtras 96 113 { … … 100 117 101 118 const QSymbianTypeFaceExtras *extras(const QString &typeface, bool bold, bool italic) const; 102 103 private: 119 void removeAppFontData(QFontDatabasePrivate::ApplicationFont *fnt); 120 static inline bool appFontLimitReached(); 121 TUid addFontFileToFontStore(const QFileInfo &fontFileInfo); 122 static void clear(); 123 124 static inline QString tempAppFontFolder(); 125 static const QString appFontMarkerPrefix; 126 static QString appFontMarker(); // 'qaf<shortUid[+shortPid]>' 127 128 struct CFontFromFontStoreReleaser { 129 static inline void cleanup(CFont *font) 130 { 131 if (!font) 132 return; 133 const QSymbianFontDatabaseExtrasImplementation *dbExtras = 134 static_cast<const QSymbianFontDatabaseExtrasImplementation*>(privateDb()->symbianExtras); 135 dbExtras->m_store->ReleaseFont(font); 136 } 137 }; 138 139 struct CFontFromScreenDeviceReleaser { 140 static inline void cleanup(CFont *font) 141 { 142 if (!font) 143 return; 144 S60->screenDevice()->ReleaseFont(font); 145 } 146 }; 147 148 // m_heap, m_store, m_rasterizer and m_extras are used if Symbian 149 // does not provide the Font Table API 104 150 RHeap* m_heap; 105 151 CFontStore *m_store; 106 152 COpenFontRasterizer *m_rasterizer; 107 153 mutable QList<const QSymbianTypeFaceExtras *> m_extras; 154 108 155 mutable QHash<QString, const QSymbianTypeFaceExtras *> m_extrasHash; 156 mutable QSet<QString> m_applicationFontFamilies; 109 157 }; 110 158 159 const QString QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix = 160 QLatin1String("Q"); 161 162 inline QString QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder() 163 { 164 return QDir::toNativeSeparators(QDir::tempPath()) + QLatin1Char('\\'); 165 } 166 167 QString QSymbianFontDatabaseExtrasImplementation::appFontMarker() 168 { 169 static QString result; 170 if (result.isEmpty()) { 171 quint16 id = 0; 172 if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) { 173 // We are allowed to load app fonts even from previous, crashed runs 174 // of this application, since we can access the font tables. 175 const quint32 uid = RProcess().Type().MostDerived().iUid; 176 id = static_cast<quint16>(uid + (uid >> 16)); 177 } else { 178 // If no font table Api is available, we must not even load a font 179 // from a previous (crashed) run of this application. Reason: we 180 // won't get the font tables, they are not in the CFontStore. 181 // So, we use the pid, for more uniqueness. 182 id = static_cast<quint16>(RProcess().Id().Id()); 183 } 184 result = appFontMarkerPrefix + QString::fromLatin1("%1").arg(id & 0x7fff, 3, 32, QLatin1Char('0')); 185 Q_ASSERT(appFontMarkerPrefix.length() == 1 && result.length() == 4); 186 } 187 return result; 188 } 189 190 static inline bool qt_symbian_fontNameHasAppFontMarker(const QString &fontName) 191 { 192 const int idLength = 3; // Keep in sync with id length in appFontMarker(). 193 const QString &prefix = QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix; 194 if (fontName.length() < prefix.length() + idLength 195 || fontName.mid(fontName.length() - idLength - prefix.length(), prefix.length()) != prefix) 196 return false; 197 // Testing if the the id is base32 data 198 for (int i = fontName.length() - idLength; i < fontName.length(); ++i) { 199 const QChar &c = fontName.at(i); 200 if (!(c >= QLatin1Char('0') && c <= QLatin1Char('9') 201 || c >= QLatin1Char('a') && c <= QLatin1Char('v'))) 202 return false; 203 } 204 return true; 205 } 206 207 // If fontName is an application font of this app, prepend the app font marker 208 QString qt_symbian_fontNameWithAppFontMarker(const QString &fontName) 209 { 210 QFontDatabasePrivate *db = privateDb(); 211 Q_ASSERT(db); 212 const QSymbianFontDatabaseExtrasImplementation *dbExtras = 213 static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras); 214 return dbExtras->m_applicationFontFamilies.contains(fontName) ? 215 fontName + QSymbianFontDatabaseExtrasImplementation::appFontMarker() 216 : fontName; 217 } 218 219 static inline QString qt_symbian_appFontNameWithoutMarker(const QString &markedFontName) 220 { 221 return markedFontName.left(markedFontName.length() 222 - QSymbianFontDatabaseExtrasImplementation::appFontMarker().length()); 223 } 224 111 225 QSymbianFontDatabaseExtrasImplementation::QSymbianFontDatabaseExtrasImplementation() 112 226 { 113 QStringList filters; 114 filters.append(QLatin1String("*.ttf")); 115 filters.append(QLatin1String("*.ccc")); 116 filters.append(QLatin1String("*.ltt")); 117 const QFileInfoList fontFiles = alternativeFilePaths(QLatin1String("resource\\Fonts"), filters); 118 119 const TInt heapMinLength = 0x1000; 120 const TInt heapMaxLength = qMax(0x20000 * fontFiles.count(), heapMinLength); 121 m_heap = User::ChunkHeap(NULL, heapMinLength, heapMaxLength); 122 QT_TRAP_THROWING( 123 m_store = CFontStore::NewL(m_heap); 124 m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E)); 125 CleanupStack::PushL(m_rasterizer); 126 m_store->InstallRasterizerL(m_rasterizer); 127 CleanupStack::Pop(m_rasterizer);); 128 129 foreach (const QFileInfo &fontFileInfo, fontFiles) { 130 const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath()); 131 TPtrC fontFilePtr(qt_QString2TPtrC(fontFile)); 132 QT_TRAP_THROWING(m_store->AddFileL(fontFilePtr)); 227 if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) { 228 QStringList filters; 229 filters.append(QLatin1String("*.ttf")); 230 filters.append(QLatin1String("*.ccc")); 231 filters.append(QLatin1String("*.ltt")); 232 const QFileInfoList fontFiles = alternativeFilePaths(QLatin1String("resource\\Fonts"), filters); 233 234 const TInt heapMinLength = 0x1000; 235 const TInt heapMaxLength = qMax(0x20000 * fontFiles.count(), heapMinLength); 236 m_heap = User::ChunkHeap(NULL, heapMinLength, heapMaxLength); 237 QT_TRAP_THROWING( 238 m_store = CFontStore::NewL(m_heap); 239 m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E)); 240 CleanupStack::PushL(m_rasterizer); 241 m_store->InstallRasterizerL(m_rasterizer); 242 CleanupStack::Pop(m_rasterizer);); 243 244 foreach (const QFileInfo &fontFileInfo, fontFiles) 245 addFontFileToFontStore(fontFileInfo); 246 } 247 } 248 249 void QSymbianFontDatabaseExtrasImplementation::clear() 250 { 251 QFontDatabasePrivate *db = privateDb(); 252 if (!db) 253 return; 254 const QSymbianFontDatabaseExtrasImplementation *dbExtras = 255 static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras); 256 if (!dbExtras) 257 return; // initializeDb() has never been called 258 if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) { 259 qDeleteAll(dbExtras->m_extrasHash); 260 } else { 261 typedef QList<const QSymbianTypeFaceExtras *>::iterator iterator; 262 for (iterator p = dbExtras->m_extras.begin(); p != dbExtras->m_extras.end(); ++p) { 263 dbExtras->m_store->ReleaseFont((*p)->fontOwner()); 264 delete *p; 265 } 266 dbExtras->m_extras.clear(); 267 } 268 dbExtras->m_extrasHash.clear(); 269 } 270 271 void qt_cleanup_symbianFontDatabase() 272 { 273 QFontDatabasePrivate *db = privateDb(); 274 if (!db) 275 return; 276 277 QSymbianFontDatabaseExtrasImplementation::clear(); 278 279 if (!db->applicationFonts.isEmpty()) { 280 QFontDatabase::removeAllApplicationFonts(); 281 // We remove the left over temporary font files of Qt application. 282 // Active fonts are undeletable since the font server holds a handle 283 // on them, so we do not need to worry to delete other running 284 // applications' fonts. 285 const QDir dir(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder()); 286 const QStringList filter( 287 QSymbianFontDatabaseExtrasImplementation::appFontMarkerPrefix + QLatin1String("*.ttf")); 288 foreach (const QFileInfo &ttfFile, dir.entryInfoList(filter)) 289 QFile(ttfFile.absoluteFilePath()).remove(); 290 db->applicationFonts.clear(); 133 291 } 134 292 } … … 136 294 QSymbianFontDatabaseExtrasImplementation::~QSymbianFontDatabaseExtrasImplementation() 137 295 { 138 typedef QList<const QSymbianTypeFaceExtras *>::iterator iterator; 139 for (iterator p = m_extras.begin(); p != m_extras.end(); ++p) { 140 m_store->ReleaseFont((*p)->fontOwner()); 141 delete *p; 142 } 143 144 delete m_store; 145 m_heap->Close(); 296 qt_cleanup_symbianFontDatabase(); 297 if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) { 298 delete m_store; 299 m_heap->Close(); 300 } 146 301 } 147 302 … … 163 318 #endif // FNTSTORE_H_INLINES_SUPPORT_FMM 164 319 165 const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString & typeface,320 const QSymbianTypeFaceExtras *QSymbianFontDatabaseExtrasImplementation::extras(const QString &aTypeface, 166 321 bool bold, bool italic) const 167 322 { 323 const QString typeface = qt_symbian_fontNameWithAppFontMarker(aTypeface); 168 324 const QString searchKey = typeface + QString::number(int(bold)) + QString::number(int(italic)); 169 325 if (!m_extrasHash.contains(searchKey)) { 170 CFont* font = NULL;171 326 TFontSpec searchSpec(qt_QString2TPtrC(typeface), 1); 172 327 if (bold) … … 174 329 if (italic) 175 330 searchSpec.iFontStyle.SetPosture(EPostureItalic); 176 const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, searchSpec); 177 Q_ASSERT(err == KErrNone && font); 178 const CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font); 179 COpenFont *openFont = 331 332 CFont* font = NULL; 333 if (QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) { 334 const TInt err = S60->screenDevice()->GetNearestFontToDesignHeightInPixels(font, searchSpec); 335 Q_ASSERT(err == KErrNone && font); 336 QScopedPointer<CFont, CFontFromScreenDeviceReleaser> sFont(font); 337 QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font); 338 sFont.take(); 339 m_extrasHash.insert(searchKey, extras); 340 } else { 341 const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, searchSpec); 342 Q_ASSERT(err == KErrNone && font); 343 const CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font); 344 COpenFont *openFont = 180 345 #ifdef FNTSTORE_H_INLINES_SUPPORT_FMM 181 bitmapFont->openFont();182 #else 183 OpenFontFromBitmapFont(bitmapFont);346 bitmapFont->OpenFont(); 347 #else // FNTSTORE_H_INLINES_SUPPORT_FMM 348 OpenFontFromBitmapFont(bitmapFont); 184 349 #endif // FNTSTORE_H_INLINES_SUPPORT_FMM 185 const TOpenFontFaceAttrib* const attrib = openFont->FaceAttrib(); 186 const QString foundKey = 187 QString((const QChar*)attrib->FullName().Ptr(), attrib->FullName().Length()); 188 if (!m_extrasHash.contains(foundKey)) { 189 QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font, openFont); 190 m_extras.append(extras); 191 m_extrasHash.insert(searchKey, extras); 192 m_extrasHash.insert(foundKey, extras); 193 } else { 194 m_store->ReleaseFont(font); 195 m_extrasHash.insert(searchKey, m_extrasHash.value(foundKey)); 350 const TOpenFontFaceAttrib* const attrib = openFont->FaceAttrib(); 351 const QString foundKey = 352 QString((const QChar*)attrib->FullName().Ptr(), attrib->FullName().Length()); 353 if (!m_extrasHash.contains(foundKey)) { 354 QScopedPointer<CFont, CFontFromFontStoreReleaser> sFont(font); 355 QSymbianTypeFaceExtras *extras = new QSymbianTypeFaceExtras(font, openFont); 356 sFont.take(); 357 m_extras.append(extras); 358 m_extrasHash.insert(searchKey, extras); 359 m_extrasHash.insert(foundKey, extras); 360 } else { 361 m_store->ReleaseFont(font); 362 m_extrasHash.insert(searchKey, m_extrasHash.value(foundKey)); 363 } 196 364 } 197 365 } 198 366 return m_extrasHash.value(searchKey); 199 367 } 200 #else 368 369 void QSymbianFontDatabaseExtrasImplementation::removeAppFontData( 370 QFontDatabasePrivate::ApplicationFont *fnt) 371 { 372 clear(); 373 if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable() 374 && fnt->fontStoreFontFileUid.iUid != 0) 375 m_store->RemoveFile(fnt->fontStoreFontFileUid); 376 if (!fnt->families.isEmpty()) 377 m_applicationFontFamilies.remove(fnt->families.first()); 378 if (fnt->screenDeviceFontFileId != 0) 379 S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId); 380 QFile::remove(fnt->temporaryFileName); 381 *fnt = QFontDatabasePrivate::ApplicationFont(); 382 } 383 384 bool QSymbianFontDatabaseExtrasImplementation::appFontLimitReached() 385 { 386 QFontDatabasePrivate *db = privateDb(); 387 if (!db) 388 return false; 389 const int maxAppFonts = 5; 390 int registeredAppFonts = 0; 391 foreach (const QFontDatabasePrivate::ApplicationFont &appFont, db->applicationFonts) 392 if (!appFont.families.isEmpty() && ++registeredAppFonts == maxAppFonts) 393 return true; 394 return false; 395 } 396 397 TUid QSymbianFontDatabaseExtrasImplementation::addFontFileToFontStore(const QFileInfo &fontFileInfo) 398 { 399 Q_ASSERT(!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()); 400 const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath()); 401 const TPtrC fontFilePtr(qt_QString2TPtrC(fontFile)); 402 TUid fontUid = {0}; 403 TRAP_IGNORE(fontUid = m_store->AddFileL(fontFilePtr)); 404 return fontUid; 405 } 406 407 #else // QT_NO_FREETYPE 201 408 class QFontEngineFTS60 : public QFontEngineFT 202 409 { … … 210 417 default_hint_style = HintFull; 211 418 } 212 #endif // defined(QT_NO_FREETYPE)419 #endif // QT_NO_FREETYPE 213 420 214 421 /* … … 219 426 qreal QFontEngineS60::pixelsToPoints(qreal pixels, Qt::Orientation orientation) 220 427 { 428 CWsScreenDevice* device = S60->screenDevice(); 221 429 return (orientation == Qt::Horizontal? 222 S60->screenDevice()->HorizontalPixelsToTwips(pixels)223 : S60->screenDevice()->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint;430 device->HorizontalPixelsToTwips(pixels) 431 :device->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint; 224 432 } 225 433 226 434 qreal QFontEngineS60::pointsToPixels(qreal points, Qt::Orientation orientation) 227 435 { 436 CWsScreenDevice* device = S60->screenDevice(); 228 437 const int twips = points * KTwipsPerPoint; 229 438 return orientation == Qt::Horizontal? 230 S60->screenDevice()->HorizontalTwipsToPixels(twips)231 : S60->screenDevice()->VerticalTwipsToPixels(twips);439 device->HorizontalTwipsToPixels(twips) 440 :device->VerticalTwipsToPixels(twips); 232 441 } 233 442 … … 256 465 } 257 466 467 static bool registerScreenDeviceFont(int screenDeviceFontIndex, 468 const QSymbianFontDatabaseExtrasImplementation *dbExtras) 469 { 470 TTypefaceSupport typefaceSupport; 471 S60->screenDevice()->TypefaceSupport(typefaceSupport, screenDeviceFontIndex); 472 473 QString familyName((const QChar*)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length()); 474 if (qt_symbian_fontNameHasAppFontMarker(familyName)) { 475 const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker(); 476 if (familyName.endsWith(marker)) { 477 familyName = qt_symbian_appFontNameWithoutMarker(familyName); 478 dbExtras->m_applicationFontFamilies.insert(familyName); 479 } else { 480 return false; // This was somebody else's application font. Skip it. 481 } 482 } 483 484 CFont *font; // We have to get a font instance in order to know all the details 485 TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11); 486 if (S60->screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone) 487 return false; 488 QScopedPointer<CFont, QSymbianFontDatabaseExtrasImplementation::CFontFromScreenDeviceReleaser> sFont(font); 489 if (font->TypeUid() != KCFbsFontUid) 490 return false; 491 TOpenFontFaceAttrib faceAttrib; 492 const CFbsFont *cfbsFont = static_cast<const CFbsFont *>(font); 493 cfbsFont->GetFaceAttrib(faceAttrib); 494 495 QtFontStyle::Key styleKey; 496 styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal; 497 styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal; 498 499 QtFontFamily *family = privateDb()->family(familyName, true); 500 family->fixedPitch = faceAttrib.IsMonoWidth(); 501 QtFontFoundry *foundry = family->foundry(QString(), true); 502 QtFontStyle *style = foundry->style(styleKey, true); 503 style->smoothScalable = typefaceSupport.iIsScalable; 504 style->pixelSize(0, true); 505 506 const QSymbianTypeFaceExtras *typeFaceExtras = 507 dbExtras->extras(familyName, faceAttrib.IsBold(), faceAttrib.IsItalic()); 508 const QByteArray os2Table = typeFaceExtras->getSfntTable(MAKE_TAG('O', 'S', '/', '2')); 509 const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData()); 510 const unsigned char* ulUnicodeRange = data + 42; 511 quint32 unicodeRange[4] = { 512 qFromBigEndian<quint32>(ulUnicodeRange), 513 qFromBigEndian<quint32>(ulUnicodeRange + 4), 514 qFromBigEndian<quint32>(ulUnicodeRange + 8), 515 qFromBigEndian<quint32>(ulUnicodeRange + 12) 516 }; 517 const unsigned char* ulCodePageRange = data + 78; 518 quint32 codePageRange[2] = { 519 qFromBigEndian<quint32>(ulCodePageRange), 520 qFromBigEndian<quint32>(ulCodePageRange + 4) 521 }; 522 const QList<QFontDatabase::WritingSystem> writingSystems = 523 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); 524 foreach (const QFontDatabase::WritingSystem system, writingSystems) 525 family->writingSystems[system] = QtFontFamily::Supported; 526 return true; 527 } 528 258 529 static void initializeDb() 259 530 { … … 262 533 return; 263 534 264 #if defined(QT_NO_FREETYPE)535 #ifdef QT_NO_FREETYPE 265 536 if (!db->symbianExtras) 266 537 db->symbianExtras = new QSymbianFontDatabaseExtrasImplementation; 267 538 268 539 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); 269 270 const int numTypeFaces = QS60Data::screenDevice()->NumTypefaces();540 541 const int numTypeFaces = S60->screenDevice()->NumTypefaces(); 271 542 const QSymbianFontDatabaseExtrasImplementation *dbExtras = 272 543 static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras); 273 bool fontAdded = false; 274 for (int i = 0; i < numTypeFaces; i++) { 275 TTypefaceSupport typefaceSupport; 276 QS60Data::screenDevice()->TypefaceSupport(typefaceSupport, i); 277 CFont *font; // We have to get a font instance in order to know all the details 278 TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11); 279 if (QS60Data::screenDevice()->GetNearestFontInPixels(font, fontSpec) != KErrNone) 280 continue; 281 if (font->TypeUid() == KCFbsFontUid) { 282 TOpenFontFaceAttrib faceAttrib; 283 const CFbsFont *cfbsFont = static_cast<const CFbsFont *>(font); 284 cfbsFont->GetFaceAttrib(faceAttrib); 285 286 QtFontStyle::Key styleKey; 287 styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal; 288 styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal; 289 290 QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length()); 291 QtFontFamily *family = db->family(familyName, true); 292 family->fixedPitch = faceAttrib.IsMonoWidth(); 293 QtFontFoundry *foundry = family->foundry(QString(), true); 294 QtFontStyle *style = foundry->style(styleKey, true); 295 style->smoothScalable = typefaceSupport.iIsScalable; 296 style->pixelSize(0, true); 297 298 const QSymbianTypeFaceExtras *typeFaceExtras = 299 dbExtras->extras(familyName, faceAttrib.IsBold(), faceAttrib.IsItalic()); 300 const QByteArray os2Table = typeFaceExtras->getSfntTable(MAKE_TAG('O', 'S', '/', '2')); 301 const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData()); 302 const unsigned char* ulUnicodeRange = data + 42; 303 quint32 unicodeRange[4] = { 304 qFromBigEndian<quint32>(ulUnicodeRange), 305 qFromBigEndian<quint32>(ulUnicodeRange + 4), 306 qFromBigEndian<quint32>(ulUnicodeRange + 8), 307 qFromBigEndian<quint32>(ulUnicodeRange + 12) 308 }; 309 const unsigned char* ulCodePageRange = data + 78; 310 quint32 codePageRange[2] = { 311 qFromBigEndian<quint32>(ulCodePageRange), 312 qFromBigEndian<quint32>(ulCodePageRange + 4) 313 }; 314 const QList<QFontDatabase::WritingSystem> writingSystems = 315 determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); 316 foreach (const QFontDatabase::WritingSystem system, writingSystems) 317 family->writingSystems[system] = QtFontFamily::Supported; 318 319 fontAdded = true; 320 } 321 QS60Data::screenDevice()->ReleaseFont(font); 322 } 323 324 Q_ASSERT(fontAdded); 325 326 lock.relock(); 327 328 #else // defined(QT_NO_FREETYPE) 544 for (int i = 0; i < numTypeFaces; i++) 545 registerScreenDeviceFont(i, dbExtras); 546 547 // We have to clear/release all CFonts, here, in case one of the fonts is 548 // an application font of another running Qt app. Otherwise the other Qt app 549 // cannot remove it's application font, anymore -> "Zombie Font". 550 QSymbianFontDatabaseExtrasImplementation::clear(); 551 552 lock.relock(); 553 554 #else // QT_NO_FREETYPE 329 555 QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation)); 330 556 dir.setNameFilters(QStringList() << QLatin1String("*.ttf") … … 335 561 db->addTTFile(file); 336 562 } 337 #endif // defined(QT_NO_FREETYPE)563 #endif // QT_NO_FREETYPE 338 564 } 339 565 … … 345 571 } 346 572 573 struct OffsetTable { 574 quint32 sfntVersion; 575 quint16 numTables, searchRange, entrySelector, rangeShift; 576 }; 577 578 struct TableRecord { 579 quint32 tag, checkSum, offset, length; 580 }; 581 582 struct NameTableHead { 583 quint16 format, count, stringOffset; 584 }; 585 586 struct NameRecord { 587 quint16 platformID, encodingID, languageID, nameID, length, offset; 588 }; 589 590 static quint32 ttfCalcChecksum(const char *data, quint32 bytesCount) 591 { 592 quint32 result = 0; 593 const quint32 *ptr = reinterpret_cast<const quint32*>(data); 594 const quint32 *endPtr = 595 ptr + (bytesCount + sizeof(quint32) - 1) / sizeof(quint32); 596 while (ptr < endPtr) { 597 const quint32 unit32Value = *ptr++; 598 result += qFromBigEndian(unit32Value); 599 } 600 return result; 601 } 602 603 static inline quint32 toDWordBoundary(quint32 value) 604 { 605 return (value + 3) & ~3; 606 } 607 608 static inline quint32 dWordPadding(quint32 value) 609 { 610 return (4 - (value & 3)) & 3; 611 } 612 613 static inline bool ttfMarkNameTable(QByteArray &table, const QString &marker) 614 { 615 const quint32 tableLength = static_cast<quint32>(table.size()); 616 617 if (tableLength > 50000 // hard limit 618 || tableLength < sizeof(NameTableHead)) // corrupt name table 619 return false; 620 621 const NameTableHead *head = reinterpret_cast<const NameTableHead*>(table.constData()); 622 const quint16 count = qFromBigEndian(head->count); 623 const quint16 stringOffset = qFromBigEndian(head->stringOffset); 624 if (count > 200 // hard limit 625 || stringOffset >= tableLength // corrupt name table 626 || sizeof(NameTableHead) + count * sizeof(NameRecord) >= tableLength) // corrupt name table 627 return false; 628 629 QTextEncoder encoder(QTextCodec::codecForName("UTF-16BE"), QTextCodec::IgnoreHeader); 630 const QByteArray markerUtf16BE = encoder.fromUnicode(marker); 631 const QByteArray markerAscii = marker.toAscii(); 632 633 QByteArray markedTable; 634 markedTable.reserve(tableLength + marker.length() * 20); // Original size plus some extra 635 markedTable.append(table, stringOffset); 636 QByteArray markedStrings; 637 quint32 stringDataCount = stringOffset; 638 for (quint16 i = 0; i < count; ++i) { 639 const quint32 nameRecordOffset = sizeof(NameTableHead) + sizeof(NameRecord) * i; 640 NameRecord *nameRecord = 641 reinterpret_cast<NameRecord*>(markedTable.data() + nameRecordOffset); 642 const quint16 nameID = qFromBigEndian(nameRecord->nameID); 643 const quint16 platformID = qFromBigEndian(nameRecord->platformID); 644 const quint16 encodingID = qFromBigEndian(nameRecord->encodingID); 645 const quint16 offset = qFromBigEndian(nameRecord->offset); 646 const quint16 length = qFromBigEndian(nameRecord->length); 647 stringDataCount += length; 648 if (stringDataCount > 80000 // hard limit. String data may be > name table size. Multiple records can reference the same string. 649 || static_cast<quint32>(stringOffset + offset + length) > tableLength) // String outside bounds 650 return false; 651 const bool needsMarker = 652 nameID == 1 || nameID == 3 || nameID == 4 || nameID == 16 || nameID == 21; 653 const bool isUnicode = 654 platformID == 0 || platformID == 3 && encodingID == 1; 655 const QByteArray originalString = 656 QByteArray::fromRawData(table.constData() + stringOffset + offset, length); 657 QByteArray markedString; 658 if (needsMarker) { 659 const int maxBytesLength = (KMaxTypefaceNameLength - marker.length()) * (isUnicode ? 2 : 1); 660 markedString = originalString.left(maxBytesLength) + (isUnicode ? markerUtf16BE : markerAscii); 661 } else { 662 markedString = originalString; 663 } 664 nameRecord->offset = qToBigEndian(static_cast<quint16>(markedStrings.length())); 665 nameRecord->length = qToBigEndian(static_cast<quint16>(markedString.length())); 666 markedStrings.append(markedString); 667 } 668 markedTable.append(markedStrings); 669 table = markedTable; 670 return true; 671 } 672 673 const quint32 ttfMaxFileSize = 3500000; 674 675 static inline bool ttfMarkAppFont(QByteArray &ttf, const QString &marker) 676 { 677 const quint32 ttfChecksumNumber = 0xb1b0afba; 678 const quint32 alignment = 4; 679 const quint32 ttfLength = static_cast<quint32>(ttf.size()); 680 if (ttfLength > ttfMaxFileSize // hard limit 681 || ttfLength % alignment != 0 // ttf sizes are always factors of 4 682 || ttfLength <= sizeof(OffsetTable) // ttf too short 683 || ttfCalcChecksum(ttf.constData(), ttf.size()) != ttfChecksumNumber) // ttf checksum is invalid 684 return false; 685 686 const OffsetTable *offsetTable = reinterpret_cast<const OffsetTable*>(ttf.constData()); 687 const quint16 numTables = qFromBigEndian(offsetTable->numTables); 688 const quint32 recordsLength = 689 toDWordBoundary(sizeof(OffsetTable) + numTables * sizeof(TableRecord)); 690 if (numTables > 30 // hard limit 691 || recordsLength + numTables * alignment > ttfLength) // Corrupt ttf. Tables would not fit, even if empty. 692 return false; 693 694 QByteArray markedTtf; 695 markedTtf.reserve(ttfLength + marker.length() * 20); // Original size plus some extra 696 markedTtf.append(ttf.constData(), recordsLength); 697 698 const quint32 ttfCheckSumAdjustmentOffset = 8; // Offset from the start of 'head' 699 int indexOfHeadTable = -1; 700 quint32 ttfDataSize = recordsLength; 701 typedef QPair<quint32, quint32> Range; 702 QList<Range> memoryRanges; 703 memoryRanges.reserve(numTables); 704 for (int i = 0; i < numTables; ++i) { 705 TableRecord *tableRecord = 706 reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord)); 707 const quint32 offset = qFromBigEndian(tableRecord->offset); 708 const quint32 length = qFromBigEndian(tableRecord->length); 709 const quint32 lengthAligned = toDWordBoundary(length); 710 ttfDataSize += lengthAligned; 711 if (offset < recordsLength // must not intersect ttf header/records 712 || offset % alignment != 0 // must be aligned 713 || offset > ttfLength - alignment // table out of bounds 714 || offset + lengthAligned > ttfLength // table out of bounds 715 || ttfDataSize > ttfLength) // tables would not fit into the ttf 716 return false; 717 718 foreach (const Range &range, memoryRanges) 719 if (offset < range.first + range.second && offset + lengthAligned > range.first) 720 return false; // Overlaps with another table 721 memoryRanges.append(Range(offset, lengthAligned)); 722 723 quint32 checkSum = qFromBigEndian(tableRecord->checkSum); 724 if (tableRecord->tag == qToBigEndian(static_cast<quint32>('head'))) { 725 if (length < ttfCheckSumAdjustmentOffset + sizeof(quint32)) 726 return false; // Invalid 'head' table 727 const quint32 *checkSumAdjustmentTag = 728 reinterpret_cast<const quint32*>(ttf.constData() + offset + ttfCheckSumAdjustmentOffset); 729 const quint32 checkSumAdjustment = qFromBigEndian(*checkSumAdjustmentTag); 730 checkSum += checkSumAdjustment; 731 indexOfHeadTable = i; // For the ttf checksum re-calculation, later 732 } 733 if (checkSum != ttfCalcChecksum(ttf.constData() + offset, length)) 734 return false; // Table checksum is invalid 735 736 bool updateTableChecksum = false; 737 QByteArray table; 738 if (tableRecord->tag == qToBigEndian(static_cast<quint32>('name'))) { 739 table = QByteArray(ttf.constData() + offset, length); 740 if (!ttfMarkNameTable(table, marker)) 741 return false; // Name table was not markable. 742 updateTableChecksum = true; 743 } else { 744 table = QByteArray::fromRawData(ttf.constData() + offset, length); 745 } 746 747 tableRecord->offset = qToBigEndian(markedTtf.size()); 748 tableRecord->length = qToBigEndian(table.size()); 749 markedTtf.append(table); 750 markedTtf.append(QByteArray(dWordPadding(table.size()), 0)); // 0-padding 751 if (updateTableChecksum) { 752 TableRecord *tableRecord = // Need to recalculate, since markedTtf changed 753 reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + i * sizeof(TableRecord)); 754 const quint32 offset = qFromBigEndian(tableRecord->offset); 755 const quint32 length = qFromBigEndian(tableRecord->length); 756 tableRecord->checkSum = qToBigEndian(ttfCalcChecksum(markedTtf.constData() + offset, length)); 757 } 758 } 759 if (indexOfHeadTable == -1 // 'head' table is mandatory 760 || ttfDataSize != ttfLength) // We do not allow ttf data "holes". Neither does Symbian. 761 return false; 762 TableRecord *headRecord = 763 reinterpret_cast<TableRecord*>(markedTtf.data() + sizeof(OffsetTable) + indexOfHeadTable * sizeof(TableRecord)); 764 quint32 *checkSumAdjustmentTag = 765 reinterpret_cast<quint32*>(markedTtf.data() + qFromBigEndian(headRecord->offset) + ttfCheckSumAdjustmentOffset); 766 *checkSumAdjustmentTag = 0; 767 const quint32 ttfChecksum = ttfCalcChecksum(markedTtf.constData(), markedTtf.count()); 768 *checkSumAdjustmentTag = qToBigEndian(ttfChecksumNumber - ttfChecksum); 769 ttf = markedTtf; 770 return true; 771 } 772 773 static inline bool ttfCanSymbianLoadFont(const QByteArray &data, const QString &fileName) 774 { 775 bool result = false; 776 QString ttfFileName; 777 QFile tempFileGuard; 778 QFileInfo info(fileName); 779 if (!data.isEmpty()) { 780 QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder() 781 + QSymbianFontDatabaseExtrasImplementation::appFontMarker() 782 + QLatin1String("XXXXXX.ttf")); 783 if (!tempfile.open() || tempfile.write(data) == -1) 784 return false; 785 ttfFileName = QDir::toNativeSeparators(QFileInfo(tempfile).canonicalFilePath()); 786 tempfile.setAutoRemove(false); 787 tempfile.close(); 788 tempFileGuard.setFileName(ttfFileName); 789 if (!tempFileGuard.open(QIODevice::ReadOnly)) 790 return false; 791 } else if (info.isFile()) { 792 ttfFileName = QDir::toNativeSeparators(info.canonicalFilePath()); 793 } else { 794 return false; 795 } 796 797 CFontStore *store = 0; 798 RHeap* heap = User::ChunkHeap(NULL, 0x1000, 0x20000); 799 if (heap) { 800 QT_TRAP_THROWING( 801 CleanupClosePushL(*heap); 802 store = CFontStore::NewL(heap); 803 CleanupStack::PushL(store); 804 COpenFontRasterizer *rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E)); 805 CleanupStack::PushL(rasterizer); 806 store->InstallRasterizerL(rasterizer); 807 CleanupStack::Pop(rasterizer); 808 TUid fontUid = {-1}; 809 TRAP_IGNORE(fontUid = store->AddFileL(qt_QString2TPtrC(ttfFileName))); 810 if (fontUid.iUid != -1) 811 result = true; 812 CleanupStack::PopAndDestroy(2, heap); // heap, store 813 ); 814 } 815 816 if (tempFileGuard.isOpen()) 817 tempFileGuard.remove(); 818 819 return result; 820 } 821 347 822 static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) 348 823 { 349 Q_UNUSED(fnt); 824 if (QSymbianFontDatabaseExtrasImplementation::appFontLimitReached() 825 || fnt->data.size() > ttfMaxFileSize // hard limit 826 || fnt->data.isEmpty() && (!fnt->fileName.endsWith(QLatin1String(".ttf"), Qt::CaseInsensitive) // Only buffer or .ttf 827 || QFileInfo(fnt->fileName).size() > ttfMaxFileSize)) // hard limit 828 return; 829 830 // Using ttfCanSymbianLoadFont() causes crashes on app destruction (Symbian^3|PR1 and lower). 831 // Therefore, not using it for now, but eventually in a later version. 832 // if (!ttfCanSymbianLoadFont(fnt->data, fnt->fileName)) 833 // return; 834 835 QFontDatabasePrivate *db = privateDb(); 836 if (!db) 837 return; 838 839 if (!db->count) 840 initializeDb(); 841 842 QSymbianFontDatabaseExtrasImplementation *dbExtras = 843 static_cast<QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras); 844 if (!dbExtras) 845 return; 846 847 const QString &marker = QSymbianFontDatabaseExtrasImplementation::appFontMarker(); 848 849 // The QTemporaryFile object being used in the following section must be 850 // destructed before letting Symbian load the TTF file. Symbian would not 851 // load it otherwise, because QTemporaryFile will still keep some handle 852 // on it. The scope is used to reduce the life time of the QTemporaryFile. 853 // In order to prevent other processes from modifying the file between the 854 // moment where the QTemporaryFile is destructed and the file is loaded by 855 // Symbian, we have a QFile "tempFileGuard" outside the scope which opens 856 // the file in ReadOnly mode while the QTemporaryFile is still alive. 857 QFile tempFileGuard; 858 { 859 QTemporaryFile tempfile(QSymbianFontDatabaseExtrasImplementation::tempAppFontFolder() 860 + marker + QLatin1String("XXXXXX.ttf")); 861 if (!tempfile.open()) 862 return; 863 const QString tempFileName = QFileInfo(tempfile).canonicalFilePath(); 864 if (fnt->data.isEmpty()) { 865 QFile sourceFile(fnt->fileName); 866 if (!sourceFile.open(QIODevice::ReadOnly)) 867 return; 868 fnt->data = sourceFile.readAll(); 869 } 870 if (!ttfMarkAppFont(fnt->data, marker) || tempfile.write(fnt->data) == -1) 871 return; 872 tempfile.setAutoRemove(false); 873 tempfile.close(); // Tempfile still keeps a file handle, forbidding write access 874 fnt->data.clear(); // The TTF data was marked and saved. Not needed in memory, anymore. 875 tempFileGuard.setFileName(tempFileName); 876 if (!tempFileGuard.open(QIODevice::ReadOnly)) 877 return; 878 fnt->temporaryFileName = tempFileName; 879 } 880 881 const QString fullFileName = QDir::toNativeSeparators(fnt->temporaryFileName); 882 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); 883 const QStringList fontsOnServerBefore = qt_symbian_fontFamiliesOnFontServer(); 884 const TInt err = 885 S60->screenDevice()->AddFile(qt_QString2TPtrC(fullFileName), fnt->screenDeviceFontFileId); 886 tempFileGuard.close(); // Did its job 887 const QStringList fontsOnServerAfter = qt_symbian_fontFamiliesOnFontServer(); 888 if (err == KErrNone && fontsOnServerBefore.count() < fontsOnServerAfter.count()) { // Added to screen device? 889 int fontOnServerIndex = fontsOnServerAfter.count() - 1; 890 for (int i = 0; i < fontsOnServerBefore.count(); i++) { 891 if (fontsOnServerBefore.at(i) != fontsOnServerAfter.at(i)) { 892 fontOnServerIndex = i; 893 break; 894 } 895 } 896 897 // Must remove all font engines with their CFonts, first. 898 QFontCache::instance()->clear(); 899 db->free(); 900 QSymbianFontDatabaseExtrasImplementation::clear(); 901 902 if (!QSymbianTypeFaceExtras::symbianFontTableApiAvailable()) 903 fnt->fontStoreFontFileUid = dbExtras->addFontFileToFontStore(QFileInfo(fullFileName)); 904 905 const QString &appFontName = fontsOnServerAfter.at(fontOnServerIndex); 906 fnt->families.append(qt_symbian_appFontNameWithoutMarker(appFontName)); 907 if (!qt_symbian_fontNameHasAppFontMarker(appFontName) 908 || !registerScreenDeviceFont(fontOnServerIndex, dbExtras)) 909 dbExtras->removeAppFontData(fnt); 910 } else { 911 if (fnt->screenDeviceFontFileId > 0) 912 S60->screenDevice()->RemoveFile(fnt->screenDeviceFontFileId); // May still have the file open! 913 QFile::remove(fnt->temporaryFileName); 914 *fnt = QFontDatabasePrivate::ApplicationFont(); 915 } 916 lock.relock(); 350 917 } 351 918 352 919 bool QFontDatabase::removeApplicationFont(int handle) 353 920 { 354 Q_UNUSED(handle); 355 return false; 921 QMutexLocker locker(fontDatabaseMutex()); 922 923 QFontDatabasePrivate *db = privateDb(); 924 if (!db || handle < 0 || handle >= db->applicationFonts.count()) 925 return false; 926 QSymbianFontDatabaseExtrasImplementation *dbExtras = 927 static_cast<QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras); 928 if (!dbExtras) 929 return false; 930 931 QFontDatabasePrivate::ApplicationFont *fnt = &db->applicationFonts[handle]; 932 if (fnt->families.isEmpty()) 933 return true; // Nothing to remove. Return peacefully. 934 935 // Must remove all font engines with their CFonts, first 936 QFontCache::instance()->clear(); 937 db->free(); 938 dbExtras->removeAppFontData(fnt); 939 940 db->invalidate(); // This will just emit 'fontDatabaseChanged()' 941 return true; 356 942 } 357 943 358 944 bool QFontDatabase::removeAllApplicationFonts() 359 945 { 360 return false; 946 QMutexLocker locker(fontDatabaseMutex()); 947 948 const int applicationFontsCount = privateDb()->applicationFonts.count(); 949 for (int i = 0; i < applicationFontsCount; ++i) 950 if (!removeApplicationFont(i)) 951 return false; 952 return true; 361 953 } 362 954 … … 377 969 } 378 970 379 QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate * , const QFontDef &req)971 QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *d, const QFontDef &req) 380 972 { 381 973 const QFontCache::Key key(cleanedFontDef(req), script); … … 391 983 QtFontDesc desc; 392 984 QList<int> blacklistedFamilies; 393 match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies);985 match(script, key.def, key.def.family, QString(), -1, &desc, blacklistedFamilies); 394 986 if (!desc.family) // falling back to application font 395 987 desc.family = db->family(QApplication::font().defaultFamily()); … … 417 1009 QFontDef request = req; 418 1010 request.family = fontFamily; 419 #if defined(QT_NO_FREETYPE)1011 #ifdef QT_NO_FREETYPE 420 1012 const QSymbianFontDatabaseExtrasImplementation *dbExtras = 421 1013 static_cast<const QSymbianFontDatabaseExtrasImplementation*>(db->symbianExtras); 422 1014 const QSymbianTypeFaceExtras *typeFaceExtras = 423 1015 dbExtras->extras(fontFamily, request.weight > QFont::Normal, request.style != QFont::StyleNormal); 1016 1017 // We need a valid pixelSize, e.g. for lineThickness() 1018 if (request.pixelSize < 0) 1019 request.pixelSize = request.pointSize * d->dpi / 72; 1020 424 1021 fe = new QFontEngineS60(request, typeFaceExtras); 425 #else 1022 #else // QT_NO_FREETYPE 1023 Q_UNUSED(d) 426 1024 QFontEngine::FaceId faceId; 427 1025 const QtFontFamily * const reqQtFontFamily = db->family(fontFamily); … … 434 1032 else 435 1033 delete fte; 436 #endif 1034 #endif // QT_NO_FREETYPE 437 1035 438 1036 Q_ASSERT(fe);
Note:
See TracChangeset
for help on using the changeset viewer.