diff options
Diffstat (limited to 'src/platformsupport/fontdatabases')
8 files changed, 324 insertions, 244 deletions
diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp index 33f3601b97..1ed5ede3e8 100644 --- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp @@ -113,27 +113,18 @@ void QBasicFontDatabase::populateFontDatabase() } } -QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *usrPtr) +QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPtr) { - QFontEngineFT *engine; FontFile *fontfile = static_cast<FontFile *> (usrPtr); QFontEngine::FaceId fid; fid.filename = QFile::encodeName(fontfile->fileName); fid.index = fontfile->indexValue; - engine = new QFontEngineFT(fontDef); bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; - if (!engine->init(fid,antialias,format)) { - delete engine; - engine = 0; - return engine; - } - if (engine->invalid()) { - delete engine; - engine = 0; - } else if (!engine->supportsScript(script)) { - qWarning(" OpenType support missing for script %d", int(script)); + + QFontEngineFT *engine = new QFontEngineFT(fontDef); + if (!engine->init(fid, antialias, format) || engine->invalid()) { delete engine; engine = 0; } diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h index 4d6fd2ceeb..45d7218ece 100644 --- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h @@ -58,7 +58,7 @@ class QBasicFontDatabase : public QPlatformFontDatabase { public: void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index 8c3ca2d229..a9a85f1316 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -69,21 +69,52 @@ static inline bool requiresOpenType(int writingSystem) || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko); } -static int getFCWeight(int fc_weight) +static inline int weightFromFcWeight(int fcweight) { - int qtweight = QFont::Black; - if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_REGULAR) / 2) - qtweight = QFont::Light; - else if (fc_weight <= (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2) - qtweight = QFont::Normal; - else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_BOLD) / 2) - qtweight = QFont::DemiBold; - else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2) - qtweight = QFont::Bold; + // Font Config uses weights from 0 to 215 (the highest enum value) while QFont ranges from + // 0 to 99. The spacing between the values for the enums are uneven so a linear mapping from + // Font Config values to Qt would give surprising results. So, we do a piecewise linear + // mapping. This ensures that where there is a corresponding enum on both sides (for example + // FC_WEIGHT_DEMIBOLD and QFont::DemiBold) we map one to the other but other values map + // to intermediate Qt weights. + const int maxWeight = 99; + int qtweight; + if (fcweight < 0) + qtweight = 0; + else if (fcweight <= FC_WEIGHT_LIGHT) + qtweight = (fcweight * QFont::Light) / FC_WEIGHT_LIGHT; + else if (fcweight <= FC_WEIGHT_NORMAL) + qtweight = QFont::Light + ((fcweight - FC_WEIGHT_LIGHT) * (QFont::Normal - QFont::Light)) / (FC_WEIGHT_NORMAL - FC_WEIGHT_LIGHT); + else if (fcweight <= FC_WEIGHT_DEMIBOLD) + qtweight = QFont::Normal + ((fcweight - FC_WEIGHT_NORMAL) * (QFont::DemiBold - QFont::Normal)) / (FC_WEIGHT_DEMIBOLD - FC_WEIGHT_NORMAL); + else if (fcweight <= FC_WEIGHT_BOLD) + qtweight = QFont::DemiBold + ((fcweight - FC_WEIGHT_DEMIBOLD) * (QFont::Bold - QFont::DemiBold)) / (FC_WEIGHT_BOLD - FC_WEIGHT_DEMIBOLD); + else if (fcweight <= FC_WEIGHT_BLACK) + qtweight = QFont::Bold + ((fcweight - FC_WEIGHT_BOLD) * (QFont::Black - QFont::Bold)) / (FC_WEIGHT_BLACK - FC_WEIGHT_BOLD); + else if (fcweight <= FC_WEIGHT_ULTRABLACK) + qtweight = QFont::Black + ((fcweight - FC_WEIGHT_BLACK) * (maxWeight - QFont::Black)) / (FC_WEIGHT_ULTRABLACK - FC_WEIGHT_BLACK); + else + qtweight = maxWeight; return qtweight; } +static inline int stretchFromFcWidth(int fcwidth) +{ + // Font Config enums for width match pretty closely with those used by Qt so just use + // Font Config values directly while enforcing the same limits imposed by QFont. + const int maxStretch = 4000; + int qtstretch; + if (fcwidth < 1) + qtstretch = 1; + else if (fcwidth > maxStretch) + qtstretch = maxStretch; + else + qtstretch = fcwidth; + + return qtstretch; +} + static const char *specialLanguages[] = { "", // Unknown "", // Inherited @@ -309,6 +340,7 @@ void QFontconfigDatabase::populateFontDatabase() int weight_value; int slant_value; int spacing_value; + int width_value; FcChar8 *file_value; int indexValue; FcChar8 *foundry_value; @@ -322,7 +354,7 @@ void QFontconfigDatabase::populateFontDatabase() const char *properties [] = { FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT, FC_SPACING, FC_FILE, FC_INDEX, - FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT, + FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WIDTH, #if FC_VERSION >= 20297 FC_CAPABILITY, @@ -356,6 +388,8 @@ void QFontconfigDatabase::populateFontDatabase() slant_value = FC_SLANT_ROMAN; if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch) weight_value = FC_WEIGHT_REGULAR; + if (FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width_value) != FcResultMatch) + width_value = FC_WIDTH_NORMAL; if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch) spacing_value = FC_PROPORTIONAL; if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch) @@ -417,17 +451,16 @@ void QFontconfigDatabase::populateFontDatabase() : ((slant_value == FC_SLANT_OBLIQUE) ? QFont::StyleOblique : QFont::StyleNormal); - QFont::Weight weight = QFont::Weight(getFCWeight(weight_value)); + // Note: weight should really be an int but registerFont incorrectly uses an enum + QFont::Weight weight = QFont::Weight(weightFromFcWeight(weight_value)); double pixel_size = 0; - if (!scalable) { - int width = 100; - FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width); + if (!scalable) FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size); - } bool fixedPitch = spacing_value >= FC_MONO; - QFont::Stretch stretch = QFont::Unstretched; + // Note: stretch should really be an int but registerFont incorrectly uses an enum + QFont::Stretch stretch = QFont::Stretch(stretchFromFcWidth(width_value)); QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString(); QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile); // qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; @@ -476,7 +509,7 @@ QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine, return new QFontEngineMultiFontConfig(fontEngine, script); } -QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QChar::Script script, void *usrPtr) +QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr) { if (!usrPtr) return 0; @@ -509,6 +542,10 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QChar::Script sc FcPatternAdd(pattern,FC_INDEX,value,true); FcResult result; + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + FcPattern *match = FcFontMatch(0, pattern, &result); if (match) { QFontEngineFT::HintStyle default_hint_style; @@ -596,16 +633,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QChar::Script sc FcPatternDestroy(pattern); - if (!engine->init(fid,antialias,format)) { - delete engine; - engine = 0; - return engine; - } - if (engine->invalid()) { - delete engine; - engine = 0; - } else if (!engine->supportsScript(script)) { - qWarning(" OpenType support missing for script %d", int(script)); + if (!engine->init(fid, antialias, format) || engine->invalid()) { delete engine; engine = 0; } diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h index 6d6dae680e..9f1fd28144 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h @@ -52,7 +52,7 @@ class QFontconfigDatabase : public QBasicFontDatabase public: void populateFontDatabase(); QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script); - QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); QString resolveFontFamilyAlias(const QString &family) const; diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 38c44e3f35..afee68ebed 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -93,6 +93,7 @@ static const char *languageForWritingSystem[] = { }; enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) }; +#ifdef Q_OS_OSX static NSInteger languageMapSort(id obj1, id obj2, void *context) { NSArray *map1 = (NSArray *) obj1; @@ -104,6 +105,7 @@ static NSInteger languageMapSort(id obj1, id obj2, void *context) return [languages indexOfObject: lang1] - [languages indexOfObject: lang2]; } +#endif QCoreTextFontDatabase::QCoreTextFontDatabase() { @@ -163,10 +165,10 @@ QCoreTextFontDatabase::QCoreTextFontDatabase() [fontImage release]; } QCoreTextFontEngine::defaultGlyphFormat = (font_smoothing > 0 - ? QFontEngineGlyphCache::Raster_RGBMask - : QFontEngineGlyphCache::Raster_A8); + ? QFontEngine::Format_A32 + : QFontEngine::Format_A8); #else - QCoreTextFontEngine::defaultGlyphFormat = QFontEngineGlyphCache::Raster_A8; + QCoreTextFontEngine::defaultGlyphFormat = QFontEngine::Format_A8; #endif } @@ -202,8 +204,8 @@ void QCoreTextFontDatabase::populateFontDatabase() void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font) { QString foundryName = QStringLiteral("CoreText"); - QCFString familyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(font, kCTFontFamilyNameAttribute, NULL); - QCFString styleName = (CFStringRef)CTFontDescriptorCopyLocalizedAttribute(font, kCTFontStyleNameAttribute, NULL); + QCFString familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); + QCFString styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute); QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute); QFont::Weight weight = QFont::Normal; QFont::Style style = QFont::StyleNormal; @@ -265,12 +267,6 @@ void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font) QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch, true /* antialiased */, true /* scalable */, pixelSize, fixedPitch, writingSystems, (void *) font); - - // We need to map back and forth between PostScript-names and family-names for fallback list construction - CFStringRef psName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontNameAttribute); - psNameToFamily[QCFString::toQString((NSString *) psName)] = familyName; - familyNameToPsName[familyName] = QCFString::toQString((NSString *) psName); - CFRelease(psName); } void QCoreTextFontDatabase::releaseHandle(void *handle) @@ -278,10 +274,8 @@ void QCoreTextFontDatabase::releaseHandle(void *handle) CFRelease(CTFontDescriptorRef(handle)); } -QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, QChar::Script script, void *usrPtr) +QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr) { - Q_UNUSED(script); - qreal scaledPointSize = f.pixelSize; // When 96 DPI is forced, the Mac plugin will use DPI 72 for some @@ -352,26 +346,18 @@ QFont::StyleHint styleHintFromNSString(NSString *style) return QFont::AnyStyle; } -static QString familyNameFromPostScriptName(QHash<QString, QString> &psNameToFamily, - NSString *psName) +#ifdef Q_OS_OSX +static QString familyNameFromPostScriptName(NSString *psName) { - QString name = QCFString::toQString(psName); - if (psNameToFamily.contains(name)) - return psNameToFamily[name]; - else { - // Some of the font name in DefaultFontFallbacks.plist are hidden fonts like AquaHiraKaku, - // their family name begins with a dot, like ".AquaHiraKaku" or ".Apple Symbols Fallback", - // the only way (I've found) to get it are actually creating a CTFont with them. We only - // need to do it once though. - QCFType<CTFontRef> font = CTFontCreateWithName((CFStringRef) psName, 12.0, NULL); - if (font) { - QCFString family = CTFontCopyFamilyName(font); - psNameToFamily[name] = family; - return family; - } - return name; - } + QCFType<CTFontDescriptorRef> fontDescriptor = (CTFontDescriptorRef) CTFontDescriptorCreateWithNameAndSize((CFStringRef)psName, 12.0); + QCFString familyName = (CFStringRef) CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute); + QString name = QCFString::toQString(familyName); + if (name.isEmpty()) + qWarning() << "QCoreTextFontDatabase: Failed to resolve family name for PostScript name " << QCFString::toQString((CFStringRef)psName); + + return name; } +#endif QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { @@ -391,29 +377,29 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo if (fallbackLists.contains(family)) return fallbackLists.value(family); - if (!familyNameToPsName.contains(family)) - const_cast<QCoreTextFontDatabase*>(this)->populateFontDatabase(); - - QCFType<CTFontRef> font = CTFontCreateWithName(QCFString(familyNameToPsName[family]), 12.0, NULL); - if (font) { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"]; - - QCFType<CFArrayRef> cascadeList = (CFArrayRef) CTFontCopyDefaultCascadeListForLanguages(font, (CFArrayRef) languages); - if (cascadeList) { - QStringList fallbackList; - const int numCascades = CFArrayGetCount(cascadeList); - for (int i = 0; i < numCascades; ++i) { - CTFontDescriptorRef fontFallback = (CTFontDescriptorRef) CFArrayGetValueAtIndex(cascadeList, i); - QCFString fallbackFamilyName = (CFStringRef) CTFontDescriptorCopyLocalizedAttribute(fontFallback, kCTFontFamilyNameAttribute, NULL); - fallbackList.append(QCFString::toQString(fallbackFamilyName)); + QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, QCFString(family)); + if (QCFType<CTFontDescriptorRef> fontDescriptor = CTFontDescriptorCreateWithAttributes(attributes)) { + if (QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(fontDescriptor, 12.0, 0)) { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"]; + + QCFType<CFArrayRef> cascadeList = (CFArrayRef) CTFontCopyDefaultCascadeListForLanguages(font, (CFArrayRef) languages); + if (cascadeList) { + QStringList fallbackList; + const int numCascades = CFArrayGetCount(cascadeList); + for (int i = 0; i < numCascades; ++i) { + CTFontDescriptorRef fontFallback = (CTFontDescriptorRef) CFArrayGetValueAtIndex(cascadeList, i); + QCFString fallbackFamilyName = (CFStringRef) CTFontDescriptorCopyAttribute(fontFallback, kCTFontFamilyNameAttribute); + fallbackList.append(QCFString::toQString(fallbackFamilyName)); + } + fallbackLists[family] = fallbackList; } - fallbackLists[family] = fallbackList; } - } - if (fallbackLists.contains(family)) - return fallbackLists.value(family); + if (fallbackLists.contains(family)) + return fallbackLists.value(family); + } } #endif } @@ -426,9 +412,6 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo static bool didPopulateStyleFallbacks = false; if (!didPopulateStyleFallbacks) { #if defined(Q_OS_MACX) - // Ensure we have the psNameToFamily mapping set up - const_cast<QCoreTextFontDatabase*>(this)->populateFontDatabase(); - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"]; @@ -444,10 +427,10 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo NSArray *langs = [(NSArray *) item sortedArrayUsingFunction: languageMapSort context: languages]; for (NSArray *map in langs) - fallbackList.append(familyNameFromPostScriptName(psNameToFamily, [map objectAtIndex: 1])); + fallbackList.append(familyNameFromPostScriptName([map objectAtIndex: 1])); } else if ([item isKindOfClass: [NSString class]]) - fallbackList.append(familyNameFromPostScriptName(psNameToFamily, item)); + fallbackList.append(familyNameFromPostScriptName(item)); } if (QCoreTextFontEngine::supportsColorGlyphs()) @@ -474,104 +457,120 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo return fallbackLists[styleLookupKey.arg(styleHint)]; } -#ifdef Q_OS_MACX +#if HAVE_CORETEXT +static CFArrayRef createDescriptorArrayForFont(CTFontRef font) +{ + CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(array, QCFType<CTFontDescriptorRef>(CTFontCopyFontDescriptor(font))); + return array; +} +#endif + QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { - CTFontRef font = NULL; + QCFType<CFArrayRef> fonts; + QStringList families; +#if HAVE_CORETEXT + if (&CTFontManagerRegisterGraphicsFont) { + CFErrorRef error = 0; if (!fontData.isEmpty()) { QByteArray* fontDataCopy = new QByteArray(fontData); QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy, fontDataCopy->constData(), fontDataCopy->size(), releaseFontData); - CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider); + QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider); if (cgFont) { - CFErrorRef error; - bool success = CTFontManagerRegisterGraphicsFont(cgFont, &error); - if (success) { - font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL); - m_applicationGraphicsFonts.append(QCFType<CGFontRef>::constructFromGet(cgFont)); - } else { - NSLog(@"Unable to register font: %@", error); - CFRelease(error); + if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) { + QCFType<CTFontRef> font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL); + fonts = createDescriptorArrayForFont(font); + m_applicationFonts.append(QVariant::fromValue(QCFType<CGFontRef>::constructFromGet(cgFont))); } - CGFontRelease(cgFont); } } else { - CFErrorRef error; QCFType<CFURLRef> fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false); - bool success = CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error); - if (success) { - const void *keys[] = { kCTFontURLAttribute }; - const void *values[] = { fontURL }; - QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(NULL, keys, values, 1, - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithAttributes(attributes); - font = CTFontCreateWithFontDescriptor(descriptor, 0.0, NULL); - m_applicationURLFonts.append(QCFType<CFURLRef>::constructFromGet(fontURL)); - } else { - NSLog(@"Unable to register font: %@", error); - CFRelease(error); + if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error)) { +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_6, __IPHONE_7_0) + if (&CTFontManagerCreateFontDescriptorsFromURL) + fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL); + else +#endif + { + // We're limited to a single font per file, unless we dive into the font tables + QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionaryAddValue(attributes, kCTFontURLAttribute, fontURL); + QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithAttributes(attributes); + QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(descriptor, 0.0, NULL); + fonts = createDescriptorArrayForFont(font); + } + + m_applicationFonts.append(QVariant::fromValue(QCFType<CFURLRef>::constructFromGet(fontURL))); } } - if (font) { - QStringList families; - families.append(QCFString(CTFontCopyFamilyName(font))); - - QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font); - populateFromDescriptor(descriptor); - - CFRelease(font); - return families; + if (error) { + NSLog(@"Unable to register font: %@", error); + CFRelease(error); } - } else + } +#endif +#if HAVE_CORETEXT && HAVE_ATS + else #endif +#if HAVE_ATS { - ATSFontContainerRef fontContainer; - OSStatus e; + ATSFontContainerRef fontContainer; + OSStatus e; - if (!fontData.isEmpty()) { - e = ATSFontActivateFromMemory((void *) fontData.constData(), fontData.size(), - kATSFontContextLocal, kATSFontFormatUnspecified, NULL, - kATSOptionFlagsDefault, &fontContainer); - } else { - FSRef ref; - OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref); - if (qt_mac_create_fsref(fileName, &ref) != noErr) - return QStringList(); - e = ATSFontActivateFromFileReference(&ref, kATSFontContextLocal, kATSFontFormatUnspecified, 0, - kATSOptionFlagsDefault, &fontContainer); - } - - if (e == noErr) { - ItemCount fontCount = 0; - e = ATSFontFindFromContainer(fontContainer, kATSOptionFlagsDefault, 0, 0, &fontCount); - if (e != noErr) - return QStringList(); - - QVarLengthArray<ATSFontRef> containedFonts(fontCount); - e = ATSFontFindFromContainer(fontContainer, kATSOptionFlagsDefault, fontCount, containedFonts.data(), &fontCount); - if (e != noErr) - return QStringList(); - - QStringList families; - for (int i = 0; i < containedFonts.size(); ++i) { - QCFType<CTFontRef> font = CTFontCreateWithPlatformFont(containedFonts[i], 12.0, NULL, NULL); - QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font); - populateFromDescriptor(descriptor); - families.append(QCFString(CTFontCopyFamilyName(font))); + if (!fontData.isEmpty()) { + e = ATSFontActivateFromMemory((void *) fontData.constData(), fontData.size(), + kATSFontContextLocal, kATSFontFormatUnspecified, NULL, + kATSOptionFlagsDefault, &fontContainer); + } else { + FSRef ref; + OSErr qt_mac_create_fsref(const QString &file, FSRef *fsref); + if (qt_mac_create_fsref(fileName, &ref) != noErr) + return QStringList(); + e = ATSFontActivateFromFileReference(&ref, kATSFontContextLocal, kATSFontFormatUnspecified, 0, + kATSOptionFlagsDefault, &fontContainer); } - m_applicationFonts.append(fontContainer); - return families; + if (e == noErr) { + ItemCount fontCount = 0; + e = ATSFontFindFromContainer(fontContainer, kATSOptionFlagsDefault, 0, 0, &fontCount); + if (e != noErr) + return QStringList(); + + QVarLengthArray<ATSFontRef> containedFonts(fontCount); + e = ATSFontFindFromContainer(fontContainer, kATSOptionFlagsDefault, fontCount, containedFonts.data(), &fontCount); + if (e != noErr) + return QStringList(); + + CFMutableArrayRef fontsArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + for (int i = 0; i < containedFonts.size(); ++i) { + QCFType<CTFontRef> font = CTFontCreateWithPlatformFont(containedFonts[i], 12.0, NULL, NULL); + CFArrayAppendValue(fontsArray, QCFType<CTFontDescriptorRef>(CTFontCopyFontDescriptor(font))); + } + + fonts = fontsArray; + + m_applicationFonts.append(QVariant::fromValue(fontContainer)); + } } +#endif + + if (fonts) { + const int numFonts = CFArrayGetCount(fonts); + for (int i = 0; i < numFonts; ++i) { + CTFontDescriptorRef fontDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fonts, i)); + populateFromDescriptor(fontDescriptor); + QCFType<CFStringRef> familyName = CFStringRef(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute)); + families.append(QCFString(familyName)); + } } - return QStringList(); + return families; } -#endif QFont QCoreTextFontDatabase::defaultFont() const { @@ -596,25 +595,31 @@ QList<int> QCoreTextFontDatabase::standardSizes() const void QCoreTextFontDatabase::removeApplicationFonts() { -#ifdef Q_OS_MACX -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { - CFErrorRef error; - for (int i = 0; i < m_applicationGraphicsFonts.count(); ++i) - CTFontManagerUnregisterGraphicsFont(m_applicationGraphicsFonts[i], &error); - m_applicationGraphicsFonts.clear(); - - for (int i = 0; i < m_applicationURLFonts.count(); ++i) - CTFontManagerUnregisterFontsForURL(m_applicationURLFonts[i], kCTFontManagerScopeProcess, &error); - m_applicationURLFonts.clear(); - } else + foreach (const QVariant &font, m_applicationFonts) { +#if HAVE_CORETEXT + if (&CTFontManagerUnregisterGraphicsFont && &CTFontManagerUnregisterFontsForURL) { + CFErrorRef error; + if (font.canConvert(qMetaTypeId<QCFType<CGFontRef> >())) { + CTFontManagerUnregisterGraphicsFont(font.value<QCFType<CGFontRef> >(), &error); + } else if (font.canConvert(qMetaTypeId<QCFType<CFURLRef> >())) { + CTFontManagerUnregisterFontsForURL(font.value<QCFType<CFURLRef> >(), kCTFontManagerScopeProcess, &error); + } + } #endif - { - for (int i = 0; i < m_applicationFonts.count(); ++i) - ATSFontDeactivate(m_applicationFonts[i], 0, kATSOptionFlagsDoNotNotify); +#if HAVE_CORETEXT && HAVE_ATS + else +#endif +#if HAVE_ATS + if (font.canConvert(qMetaTypeId<ATSFontContainerRef>())) { + ATSFontDeactivate(font.value<ATSFontContainerRef>(), 0, kATSOptionFlagsDoNotNotify); + } +#endif + } + m_applicationFonts.clear(); + +#if HAVE_ATS ATSFontNotify(kATSFontNotifyActionFontsChanged, 0); - } #endif } diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h index ee1016509b..c6fc791503 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h @@ -42,6 +42,10 @@ #ifndef QCORETEXTFONTDATABASE_H #define QCORETEXTFONTDATABASE_H +#include <qglobal.h> +#define HAVE_CORETEXT QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_8, __IPHONE_4_1) +#define HAVE_ATS QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_5, __IPHONE_NA) + #include <qpa/qplatformfontdatabase.h> #include <private/qcore_mac_p.h> @@ -52,6 +56,14 @@ #include <CoreGraphics/CoreGraphics.h> #endif +#if HAVE_CORETEXT +Q_DECLARE_METATYPE(QCFType<CGFontRef>); +Q_DECLARE_METATYPE(QCFType<CFURLRef>); +#endif +#if HAVE_ATS +Q_DECLARE_METATYPE(ATSFontContainerRef); +#endif + QT_BEGIN_NAMESPACE class QCoreTextFontDatabase : public QPlatformFontDatabase @@ -60,12 +72,11 @@ public: QCoreTextFontDatabase(); ~QCoreTextFontDatabase(); void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle); + + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; -#ifdef Q_OS_MACX QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); -#endif void releaseHandle(void *handle); QFont defaultFont() const; QList<int> standardSizes() const; @@ -74,17 +85,10 @@ private: void populateFromDescriptor(CTFontDescriptorRef font); mutable QString defaultFontName; - mutable QHash<QString, QString> psNameToFamily; - mutable QHash<QString, QString> familyNameToPsName; void removeApplicationFonts(); -#ifdef Q_OS_MACX -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 - QVector<QCFType<CGFontRef> > m_applicationGraphicsFonts; - QVector<QCFType<CFURLRef> > m_applicationURLFonts; -#endif - QVector<ATSFontContainerRef> m_applicationFonts; -#endif + + QVector<QVariant> m_applicationFonts; }; QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index 9b8f10f588..3c30df6efb 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -63,21 +63,18 @@ static void loadAdvancesForGlyphs(CTFontRef ctfont, for (int i = 0; i < len; ++i) { if (glyphs->glyphs[i] & 0xff000000) continue; - glyphs->advances_x[i] = QFixed::fromReal(advances[i].width); - glyphs->advances_y[i] = QFixed::fromReal(advances[i].height); + glyphs->advances[i] = QFixed::fromReal(advances[i].width); } if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - for (int i = 0; i < len; ++i) { - glyphs->advances_x[i] = glyphs->advances_x[i].round(); - glyphs->advances_y[i] = glyphs->advances_y[i].round(); - } + for (int i = 0; i < len; ++i) + glyphs->advances[i] = glyphs->advances[i].round(); } } int QCoreTextFontEngine::antialiasingThreshold = 0; -QFontEngineGlyphCache::Type QCoreTextFontEngine::defaultGlyphFormat = QFontEngineGlyphCache::Raster_RGBMask; +QFontEngine::GlyphFormat QCoreTextFontEngine::defaultGlyphFormat = QFontEngine::Format_A32; CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef) { @@ -88,6 +85,7 @@ CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef) } QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) + : QFontEngine(Mac) { fontDef = def; transform = qt_transform_from_fontdef(fontDef); @@ -98,6 +96,7 @@ QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) } QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def) + : QFontEngine(Mac) { fontDef = def; transform = qt_transform_from_fontdef(fontDef); @@ -158,7 +157,7 @@ void QCoreTextFontEngine::init() #if defined(Q_OS_IOS) || MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 if (supportsColorGlyphs() && (traits & kCTFontColorGlyphsTrait)) - glyphFormat = QFontEngineGlyphCache::Raster_ARGB; + glyphFormat = QFontEngine::Format_ARGB; else #endif glyphFormat = defaultGlyphFormat; @@ -191,12 +190,37 @@ void QCoreTextFontEngine::init() avgCharWidth = QFontEngine::averageCharWidth(); cache_cost = (CTFontGetAscent(ctfont) + CTFontGetDescent(ctfont)) * avgCharWidth.toInt() * 2000; + + setUserData(QVariant::fromValue((void *)cgFont)); +} + +glyph_t QCoreTextFontEngine::glyphIndex(uint ucs4) const +{ + int len = 0; + + QChar str[2]; + if (Q_UNLIKELY(QChar::requiresSurrogates(ucs4))) { + str[len++] = QChar(QChar::highSurrogate(ucs4)); + str[len++] = QChar(QChar::lowSurrogate(ucs4)); + } else { + str[len++] = QChar(ucs4); + } + + CGGlyph glyphIndices[2]; + + CTFontGetGlyphsForCharacters(ctfont, (const UniChar *)str, glyphIndices, len); + + return glyphIndices[0]; } bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const { - QCFType<CFStringRef> cfstring; + Q_ASSERT(glyphs->numGlyphs >= *nglyphs); + if (*nglyphs < len) { + *nglyphs = len; + return false; + } QVarLengthArray<CGGlyph> cgGlyphs(len); CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len); @@ -228,15 +252,12 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout * for (int i = 0; i < glyph_pos; ++i) { if (glyphs->glyphs[i] & 0xff000000) continue; - glyphs->advances_x[i] = QFixed::fromReal(advances[i].width); - glyphs->advances_y[i] = QFixed::fromReal(advances[i].height); + glyphs->advances[i] = QFixed::fromReal(advances[i].width); } if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - for (int i = 0; i < glyph_pos; ++i) { - glyphs->advances_x[i] = glyphs->advances_x[i].round(); - glyphs->advances_y[i] = glyphs->advances_y[i].round(); - } + for (int i = 0; i < glyph_pos; ++i) + glyphs->advances[i] = glyphs->advances[i].round(); } return true; } @@ -428,7 +449,7 @@ static void convertCGPathToQPainterPath(void *info, const CGPathElement *element void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs, QPainterPath *path, QTextItem::RenderFlags) { - if (glyphFormat == QFontEngineGlyphCache::Raster_ARGB) + if (glyphFormat == QFontEngine::Format_ARGB) return; // We can't convert color-glyphs to path CGAffineTransform cgMatrix = CGAffineTransformIdentity; @@ -456,30 +477,67 @@ static void qcoretextfontengine_scaleMetrics(glyph_metrics_t &br, const QTransfo } } -glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed pos, const QTransform &matrix, GlyphFormat format) +glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, GlyphFormat format) { if (matrix.type() > QTransform::TxScale) - return QFontEngine::alphaMapBoundingBox(glyph, pos, matrix, format); + return QFontEngine::alphaMapBoundingBox(glyph, subPixelPosition, matrix, format); glyph_metrics_t br = boundingBox(glyph); qcoretextfontengine_scaleMetrics(br, matrix); - br.width = qAbs(qRound(br.width)) + 2; - br.height = qAbs(qRound(br.height)) + 2; + // Normalize width and height + if (br.width < 0) + br.width = -br.width; + if (br.height < 0) + br.height = -br.height; + + if (format == QFontEngine::Format_A8 || format == QFontEngine::Format_A32) { + // Drawing a glyph at x-position 0 with anti-aliasing enabled + // will potentially fill the pixel to the left of 0, as the + // coordinates are not aligned to the center of pixels. To + // prevent clipping of this pixel we need to shift the glyph + // in the bitmap one pixel to the right. The shift needs to + // be reflected in the glyph metrics as well, so that the final + // position of the glyph is correct, which is why doing the + // shift in imageForGlyph() is not enough. + br.x -= 1; + + // As we've shifted the glyph one pixel to the right, we need + // to expand the width of the alpha map bounding box as well. + br.width += 1; + + // But we have the same anti-aliasing problem on the right + // hand side of the glyph, eg. if the width of the glyph + // results in the bounding rect landing between two pixels. + // We pad the bounding rect again to account for the possible + // anti-aliased drawing. + br.width += 1; + + // We also shift the glyph to right right based on the subpixel + // position, so we pad the bounding box to take account for the + // subpixel positions that may result in the glyph being drawn + // one pixel to the right of the 0-subpixel position. + br.width += 1; + + // The same same logic as for the x-position needs to be applied + // to the y-position, except we don't need to compensate for + // the subpixel positioning. + br.y -= 1; + br.height += 2; + } return br; } -QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool aa, const QTransform &m) +QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool aa, const QTransform &matrix) { - glyph_metrics_t br = boundingBox(glyph); - qcoretextfontengine_scaleMetrics(br, m); + glyph_metrics_t br = alphaMapBoundingBox(glyph, subPixelPosition, matrix, glyphFormat); - bool isColorGlyph = glyphFormat == QFontEngineGlyphCache::Raster_ARGB; - QImage::Format format = isColorGlyph ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; - QImage im(qAbs(qRound(br.width)) + 2, qAbs(qRound(br.height)) + 2, format); + bool isColorGlyph = glyphFormat == QFontEngine::Format_ARGB; + QImage::Format imageFormat = isColorGlyph ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + QImage im(br.width.ceil().toInt(), br.height.ceil().toInt(), imageFormat); im.fill(0); #ifndef Q_OS_IOS @@ -507,8 +565,8 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition if (!isColorGlyph) // CTFontDrawGlyphs incorporates the font's matrix already cgMatrix = CGAffineTransformConcat(cgMatrix, transform); - if (m.isScaling()) - cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMakeScale(m.m11(), m.m22())); + if (matrix.isScaling()) + cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMakeScale(matrix.m11(), matrix.m22())); CGGlyph cgGlyph = glyph; qreal pos_x = -br.x.truncate() + subPixelPosition.toReal(); @@ -617,7 +675,7 @@ QFontEngine::FaceId QCoreTextFontEngine::faceId() const return QFontEngine::FaceId(); } -bool QCoreTextFontEngine::canRender(const QChar *string, int len) +bool QCoreTextFontEngine::canRender(const QChar *string, int len) const { QVarLengthArray<CGGlyph> cgGlyphs(len); return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len); @@ -626,16 +684,13 @@ bool QCoreTextFontEngine::canRender(const QChar *string, int len) bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const { QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0); - if (!table || !length) + if (!table) return false; CFIndex tableLength = CFDataGetLength(table); - int availableLength = *length; - *length = tableLength; - if (buffer) { - if (tableLength > availableLength) - return false; + if (buffer && int(*length) >= tableLength) CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); - } + *length = tableLength; + Q_ASSERT(int(*length) > 0); return true; } diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h index 7ef9f0dfbb..b9593b983e 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h @@ -62,6 +62,7 @@ public: QCoreTextFontEngine(CGFontRef font, const QFontDef &def); ~QCoreTextFontEngine(); + virtual glyph_t glyphIndex(uint ucs4) const; virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const; virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const; @@ -78,15 +79,11 @@ public: virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags); - virtual const char *name() const { return "QCoreTextFontEngine"; } - - virtual bool canRender(const QChar *string, int len); + virtual bool canRender(const QChar *string, int len) const; virtual int synthesized() const { return synthesisFlags; } virtual bool supportsSubPixelPositions() const { return true; } - virtual Type type() const { return QFontEngine::Mac; } - void draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight); virtual FaceId faceId() const; @@ -104,7 +101,7 @@ public: bool supportsTransformation(const QTransform &transform) const; virtual QFontEngine *cloneWithSize(qreal pixelSize) const; - virtual int glyphMargin(QFontEngineGlyphCache::Type type) { Q_UNUSED(type); return 0; } + virtual int glyphMargin(QFontEngine::GlyphFormat format) { Q_UNUSED(format); return 0; } static bool supportsColorGlyphs() { @@ -122,7 +119,7 @@ public: } static int antialiasingThreshold; - static QFontEngineGlyphCache::Type defaultGlyphFormat; + static QFontEngine::GlyphFormat defaultGlyphFormat; private: friend class QRawFontPrivate; |