mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Port the macOS headless plugin to work with Qt 5.12
This commit is contained in:
parent
13eb6795e6
commit
cb524b7cc1
763
src/calibre/headless/coretext_fontdatabase-new.mm
Normal file
763
src/calibre/headless/coretext_fontdatabase-new.mm
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the plugins of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 3 requirements
|
||||||
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 2.0 or (at your option) the GNU General
|
||||||
|
** Public license version 3 or any later version approved by the KDE Free
|
||||||
|
** Qt Foundation. The licenses are as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||||
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#if defined(Q_OS_OSX)
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#import <IOKit/graphics/IOGraphicsLib.h>
|
||||||
|
#elif defined(QT_PLATFORM_UIKIT)
|
||||||
|
#import <UIKit/UIFont.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
|
||||||
|
#include <QtFontDatabaseSupport/private/qfontengine_coretext_p.h>
|
||||||
|
#if QT_CONFIG(settings)
|
||||||
|
#include <QtCore/QSettings>
|
||||||
|
#endif
|
||||||
|
#include <QtCore/QtEndian>
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
#include <QtFontDatabaseSupport/private/qfontengine_ft_p.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
// this could become a list of all languages used for each writing
|
||||||
|
// system, instead of using the single most common language.
|
||||||
|
static const char *languageForWritingSystem[] = {
|
||||||
|
0, // Any
|
||||||
|
"en", // Latin
|
||||||
|
"el", // Greek
|
||||||
|
"ru", // Cyrillic
|
||||||
|
"hy", // Armenian
|
||||||
|
"he", // Hebrew
|
||||||
|
"ar", // Arabic
|
||||||
|
"syr", // Syriac
|
||||||
|
"div", // Thaana
|
||||||
|
"hi", // Devanagari
|
||||||
|
"bn", // Bengali
|
||||||
|
"pa", // Gurmukhi
|
||||||
|
"gu", // Gujarati
|
||||||
|
"or", // Oriya
|
||||||
|
"ta", // Tamil
|
||||||
|
"te", // Telugu
|
||||||
|
"kn", // Kannada
|
||||||
|
"ml", // Malayalam
|
||||||
|
"si", // Sinhala
|
||||||
|
"th", // Thai
|
||||||
|
"lo", // Lao
|
||||||
|
"bo", // Tibetan
|
||||||
|
"my", // Myanmar
|
||||||
|
"ka", // Georgian
|
||||||
|
"km", // Khmer
|
||||||
|
"zh-Hans", // SimplifiedChinese
|
||||||
|
"zh-Hant", // TraditionalChinese
|
||||||
|
"ja", // Japanese
|
||||||
|
"ko", // Korean
|
||||||
|
"vi", // Vietnamese
|
||||||
|
0, // Symbol
|
||||||
|
"sga", // Ogham
|
||||||
|
"non", // Runic
|
||||||
|
"man" // N'Ko
|
||||||
|
};
|
||||||
|
enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) };
|
||||||
|
|
||||||
|
#ifdef Q_OS_OSX
|
||||||
|
static NSInteger languageMapSort(id obj1, id obj2, void *context)
|
||||||
|
{
|
||||||
|
NSArray<NSString *> *map1 = reinterpret_cast<NSArray<NSString *> *>(obj1);
|
||||||
|
NSArray<NSString *> *map2 = reinterpret_cast<NSArray<NSString *> *>(obj2);
|
||||||
|
NSArray<NSString *> *languages = reinterpret_cast<NSArray<NSString *> *>(context);
|
||||||
|
|
||||||
|
NSString *lang1 = [map1 objectAtIndex:0];
|
||||||
|
NSString *lang2 = [map2 objectAtIndex:0];
|
||||||
|
|
||||||
|
return [languages indexOfObject:lang1] - [languages indexOfObject:lang2];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QCoreTextFontDatabase::QCoreTextFontDatabase()
|
||||||
|
: m_hasPopulatedAliases(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QCoreTextFontDatabase::~QCoreTextFontDatabase()
|
||||||
|
{
|
||||||
|
for (CTFontDescriptorRef ref : qAsConst(m_systemFontDescriptors))
|
||||||
|
CFRelease(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::populateFontDatabase()
|
||||||
|
{
|
||||||
|
QCFType<CFArrayRef> familyNames = CTFontManagerCopyAvailableFontFamilyNames();
|
||||||
|
for (NSString *familyName in familyNames.as<const NSArray *>())
|
||||||
|
QPlatformFontDatabase::registerFontFamily(QString::fromNSString(familyName));
|
||||||
|
|
||||||
|
// Force creating the theme fonts to get the descriptors in m_systemFontDescriptors
|
||||||
|
if (m_themeFonts.isEmpty())
|
||||||
|
(void)themeFonts();
|
||||||
|
|
||||||
|
Q_FOREACH (CTFontDescriptorRef fontDesc, m_systemFontDescriptors)
|
||||||
|
populateFromDescriptor(fontDesc);
|
||||||
|
|
||||||
|
Q_ASSERT(!m_hasPopulatedAliases);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QCoreTextFontDatabase::populateFamilyAliases()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_MACOS)
|
||||||
|
if (m_hasPopulatedAliases)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QCFType<CFArrayRef> familyNames = CTFontManagerCopyAvailableFontFamilyNames();
|
||||||
|
for (NSString *familyName in familyNames.as<const NSArray *>()) {
|
||||||
|
NSFontManager *fontManager = [NSFontManager sharedFontManager];
|
||||||
|
NSString *localizedFamilyName = [fontManager localizedNameForFamily:familyName face:nil];
|
||||||
|
if (![localizedFamilyName isEqual:familyName]) {
|
||||||
|
QPlatformFontDatabase::registerAliasToFontFamily(
|
||||||
|
QString::fromNSString(familyName),
|
||||||
|
QString::fromNSString(localizedFamilyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_hasPopulatedAliases = true;
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::populateFamily(const QString &familyName)
|
||||||
|
{
|
||||||
|
QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||||
|
CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, QCFString(familyName));
|
||||||
|
QCFType<CTFontDescriptorRef> nameOnlyDescriptor = CTFontDescriptorCreateWithAttributes(attributes);
|
||||||
|
|
||||||
|
// A single family might match several different fonts with different styles eg.
|
||||||
|
QCFType<CFArrayRef> matchingFonts = (CFArrayRef) CTFontDescriptorCreateMatchingFontDescriptors(nameOnlyDescriptor, 0);
|
||||||
|
if (!matchingFonts) {
|
||||||
|
qWarning() << "QCoreTextFontDatabase: Found no matching fonts for family" << familyName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int numFonts = CFArrayGetCount(matchingFonts);
|
||||||
|
for (int i = 0; i < numFonts; ++i)
|
||||||
|
populateFromDescriptor(CTFontDescriptorRef(CFArrayGetValueAtIndex(matchingFonts, i)), familyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::invalidate()
|
||||||
|
{
|
||||||
|
m_hasPopulatedAliases = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FontDescription {
|
||||||
|
QCFString familyName;
|
||||||
|
QCFString styleName;
|
||||||
|
QString foundryName;
|
||||||
|
QFont::Weight weight;
|
||||||
|
QFont::Style style;
|
||||||
|
QFont::Stretch stretch;
|
||||||
|
qreal pointSize;
|
||||||
|
bool fixedPitch;
|
||||||
|
QSupportedWritingSystems writingSystems;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
|
Q_DECL_UNUSED static inline QDebug operator<<(QDebug debug, const FontDescription &fd)
|
||||||
|
{
|
||||||
|
QDebugStateSaver saver(debug);
|
||||||
|
return debug.nospace() << "FontDescription("
|
||||||
|
<< "familyName=" << QString(fd.familyName)
|
||||||
|
<< ", styleName=" << QString(fd.styleName)
|
||||||
|
<< ", foundry=" << fd.foundryName
|
||||||
|
<< ", weight=" << fd.weight
|
||||||
|
<< ", style=" << fd.style
|
||||||
|
<< ", stretch=" << fd.stretch
|
||||||
|
<< ", pointSize=" << fd.pointSize
|
||||||
|
<< ", fixedPitch=" << fd.fixedPitch
|
||||||
|
<< ", writingSystems=" << fd.writingSystems
|
||||||
|
<< ")";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
|
||||||
|
{
|
||||||
|
QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
|
||||||
|
|
||||||
|
fd->foundryName = QStringLiteral("CoreText");
|
||||||
|
fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
|
||||||
|
fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
|
||||||
|
fd->weight = QFont::Normal;
|
||||||
|
fd->style = QFont::StyleNormal;
|
||||||
|
fd->stretch = QFont::Unstretched;
|
||||||
|
fd->fixedPitch = false;
|
||||||
|
|
||||||
|
if (QCFType<CTFontRef> tempFont = CTFontCreateWithFontDescriptor(font, 0.0, 0)) {
|
||||||
|
uint tag = MAKE_TAG('O', 'S', '/', '2');
|
||||||
|
CTFontRef tempFontRef = tempFont;
|
||||||
|
void *userData = reinterpret_cast<void *>(&tempFontRef);
|
||||||
|
uint length = 128;
|
||||||
|
QVarLengthArray<uchar, 128> os2Table(length);
|
||||||
|
if (QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length) && length >= 86) {
|
||||||
|
if (length > uint(os2Table.length())) {
|
||||||
|
os2Table.resize(length);
|
||||||
|
if (!QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length))
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
Q_ASSERT(length >= 86);
|
||||||
|
}
|
||||||
|
quint32 unicodeRange[4] = {
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 42),
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 46),
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 50),
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 54)
|
||||||
|
};
|
||||||
|
quint32 codePageRange[2] = {
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 78),
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 82)
|
||||||
|
};
|
||||||
|
fd->writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styles) {
|
||||||
|
if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) {
|
||||||
|
double normalizedWeight;
|
||||||
|
if (CFNumberGetValue(weightValue, kCFNumberFloat64Type, &normalizedWeight))
|
||||||
|
fd->weight = QCoreTextFontEngine::qtWeightFromCFWeight(float(normalizedWeight));
|
||||||
|
}
|
||||||
|
if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
|
||||||
|
double d;
|
||||||
|
if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) {
|
||||||
|
if (d > 0.0)
|
||||||
|
fd->style = QFont::StyleItalic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) {
|
||||||
|
int d;
|
||||||
|
if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) {
|
||||||
|
if (d & kCTFontMonoSpaceTrait)
|
||||||
|
fd->fixedPitch = true;
|
||||||
|
if (d & kCTFontExpandedTrait)
|
||||||
|
fd->stretch = QFont::Expanded;
|
||||||
|
else if (d & kCTFontCondensedTrait)
|
||||||
|
fd->stretch = QFont::Condensed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QCFType<CFNumberRef> size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) {
|
||||||
|
if (CFNumberIsFloatType(size)) {
|
||||||
|
double d;
|
||||||
|
CFNumberGetValue(size, kCFNumberDoubleType, &d);
|
||||||
|
fd->pointSize = d;
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
CFNumberGetValue(size, kCFNumberIntType, &i);
|
||||||
|
fd->pointSize = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) {
|
||||||
|
CFIndex length = CFArrayGetCount(languages);
|
||||||
|
for (int i = 1; i < LanguageCount; ++i) {
|
||||||
|
if (!languageForWritingSystem[i])
|
||||||
|
continue;
|
||||||
|
QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII);
|
||||||
|
if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang))
|
||||||
|
fd->writingSystems.setSupported(QFontDatabase::WritingSystem(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font, const QString &familyName)
|
||||||
|
{
|
||||||
|
FontDescription fd;
|
||||||
|
getFontDescription(font, &fd);
|
||||||
|
|
||||||
|
// Note: The familyName we are registering, and the family name of the font descriptor, may not
|
||||||
|
// match, as CTFontDescriptorCreateMatchingFontDescriptors will return descriptors for replacement
|
||||||
|
// fonts if a font family does not have any fonts available on the system.
|
||||||
|
QString family = !familyName.isNull() ? familyName : static_cast<QString>(fd.familyName);
|
||||||
|
|
||||||
|
CFRetain(font);
|
||||||
|
QPlatformFontDatabase::registerFont(family, fd.styleName, fd.foundryName, fd.weight, fd.style, fd.stretch,
|
||||||
|
true /* antialiased */, true /* scalable */, 0 /* pixelSize, ignored as font is scalable */,
|
||||||
|
fd.fixedPitch, fd.writingSystems, (void *)font);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSString * const kQtFontDataAttribute = @"QtFontDataAttribute";
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T *descriptorAttribute(CTFontDescriptorRef descriptor, CFStringRef name)
|
||||||
|
{
|
||||||
|
return [static_cast<T *>(CTFontDescriptorCopyAttribute(descriptor, name)) autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::releaseHandle(void *handle)
|
||||||
|
{
|
||||||
|
CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(handle);
|
||||||
|
if (NSValue *fontDataValue = descriptorAttribute<NSValue>(descriptor, (CFStringRef)kQtFontDataAttribute)) {
|
||||||
|
QByteArray *fontData = static_cast<QByteArray *>(fontDataValue.pointerValue);
|
||||||
|
delete fontData;
|
||||||
|
}
|
||||||
|
CFRelease(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef);
|
||||||
|
|
||||||
|
template <>
|
||||||
|
QFontEngine *QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::fontEngine(const QFontDef &fontDef, void *usrPtr)
|
||||||
|
{
|
||||||
|
QCFType<CTFontDescriptorRef> descriptor = QCFType<CTFontDescriptorRef>::constructFromGet(
|
||||||
|
static_cast<CTFontDescriptorRef>(usrPtr));
|
||||||
|
|
||||||
|
// CoreText will sometimes invalidate information in font descriptors that refer
|
||||||
|
// to system fonts in certain function calls or application states. While the descriptor
|
||||||
|
// looks the same from the outside, some internal plumbing is different, causing the results
|
||||||
|
// of creating CTFonts from those descriptors unreliable. The work-around for this
|
||||||
|
// is to copy the attributes of those descriptors each time we make a new CTFont
|
||||||
|
// from them instead of referring to the original, as that may trigger the CoreText bug.
|
||||||
|
if (m_systemFontDescriptors.contains(descriptor)) {
|
||||||
|
QCFType<CFDictionaryRef> attributes = CTFontDescriptorCopyAttributes(descriptor);
|
||||||
|
descriptor = CTFontDescriptorCreateWithAttributes(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we do not pass in the destination DPI to CoreText when making
|
||||||
|
// the font, we need to pass in a point size which is scaled to include
|
||||||
|
// the DPI. The default DPI for the screen is 72, thus the scale factor
|
||||||
|
// is destinationDpi / 72, but since pixelSize = pointSize / 72 * dpi,
|
||||||
|
// the pixelSize is actually the scaled point size for the destination
|
||||||
|
// DPI, and we can use that directly.
|
||||||
|
qreal scaledPointSize = fontDef.pixelSize;
|
||||||
|
|
||||||
|
CGAffineTransform matrix = qt_transform_from_fontdef(fontDef);
|
||||||
|
if (QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix))
|
||||||
|
return new QCoreTextFontEngine(font, fontDef);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
template <>
|
||||||
|
QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const QFontDef &fontDef, void *usrPtr)
|
||||||
|
{
|
||||||
|
CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(usrPtr);
|
||||||
|
|
||||||
|
if (NSValue *fontDataValue = descriptorAttribute<NSValue>(descriptor, (CFStringRef)kQtFontDataAttribute)) {
|
||||||
|
QByteArray *fontData = static_cast<QByteArray *>(fontDataValue.pointerValue);
|
||||||
|
return QFontEngineFT::create(*fontData, fontDef.pixelSize,
|
||||||
|
static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
|
||||||
|
} else if (NSURL *url = descriptorAttribute<NSURL>(descriptor, kCTFontURLAttribute)) {
|
||||||
|
Q_ASSERT(url.fileURL);
|
||||||
|
QFontEngine::FaceId faceId;
|
||||||
|
faceId.filename = QString::fromNSString(url.path).toUtf8();
|
||||||
|
return QFontEngineFT::create(fontDef, faceId);
|
||||||
|
}
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
QFontEngine *QCoreTextFontDatabaseEngineFactory<T>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
|
||||||
|
{
|
||||||
|
return T::create(fontData, pixelSize, hintingPreference);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicitly instantiate so that we don't need the plugin to involve FreeType
|
||||||
|
template class QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>;
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
template class QCoreTextFontDatabaseEngineFactory<QFontEngineFT>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QFont::StyleHint styleHintFromNSString(NSString *style)
|
||||||
|
{
|
||||||
|
if ([style isEqual: @"sans-serif"])
|
||||||
|
return QFont::SansSerif;
|
||||||
|
else if ([style isEqual: @"monospace"])
|
||||||
|
return QFont::Monospace;
|
||||||
|
else if ([style isEqual: @"cursive"])
|
||||||
|
return QFont::Cursive;
|
||||||
|
else if ([style isEqual: @"serif"])
|
||||||
|
return QFont::Serif;
|
||||||
|
else if ([style isEqual: @"fantasy"])
|
||||||
|
return QFont::Fantasy;
|
||||||
|
else // if ([style isEqual: @"default"])
|
||||||
|
return QFont::AnyStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_OSX
|
||||||
|
static QString familyNameFromPostScriptName(NSString *psName)
|
||||||
|
{
|
||||||
|
QCFType<CTFontDescriptorRef> fontDescriptor = (CTFontDescriptorRef) CTFontDescriptorCreateWithNameAndSize((CFStringRef)psName, 12.0);
|
||||||
|
QCFString familyName = (CFStringRef) CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute);
|
||||||
|
QString name = QString::fromCFString(familyName);
|
||||||
|
if (name.isEmpty())
|
||||||
|
qWarning() << "QCoreTextFontDatabase: Failed to resolve family name for PostScript name " << QString::fromCFString((CFStringRef)psName);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void addExtraFallbacks(QStringList *fallbackList)
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_MACOS)
|
||||||
|
// Since we are only returning a list of default fonts for the current language, we do not
|
||||||
|
// cover all unicode completely. This was especially an issue for some of the common script
|
||||||
|
// symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk
|
||||||
|
// of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most
|
||||||
|
// of Unicode 2.1.
|
||||||
|
if (!fallbackList->contains(QStringLiteral("Arial Unicode MS")))
|
||||||
|
fallbackList->append(QStringLiteral("Arial Unicode MS"));
|
||||||
|
// Since some symbols (specifically Braille) are not in Arial Unicode MS, we
|
||||||
|
// add Apple Symbols to cover those too.
|
||||||
|
if (!fallbackList->contains(QStringLiteral("Apple Symbols")))
|
||||||
|
fallbackList->append(QStringLiteral("Apple Symbols"));
|
||||||
|
#else
|
||||||
|
Q_UNUSED(fallbackList)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(style);
|
||||||
|
Q_UNUSED(script);
|
||||||
|
|
||||||
|
QMacAutoReleasePool pool;
|
||||||
|
|
||||||
|
static QHash<QString, QStringList> fallbackLists;
|
||||||
|
|
||||||
|
if (!family.isEmpty()) {
|
||||||
|
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(QString::fromCFString(fallbackFamilyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
addExtraFallbacks(&fallbackList);
|
||||||
|
extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &);
|
||||||
|
fallbackList = qt_sort_families_by_writing_system(script, fallbackList);
|
||||||
|
|
||||||
|
return fallbackList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We were not able to find a fallback for the specific family,
|
||||||
|
// so we fall back to the stylehint.
|
||||||
|
|
||||||
|
static const QString styleLookupKey = QString::fromLatin1(".QFontStyleHint_%1");
|
||||||
|
|
||||||
|
static bool didPopulateStyleFallbacks = false;
|
||||||
|
if (!didPopulateStyleFallbacks) {
|
||||||
|
#if defined(Q_OS_MACX)
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSArray<NSString *> *languages = [defaults stringArrayForKey:@"AppleLanguages"];
|
||||||
|
|
||||||
|
NSDictionary<NSString *, id> *fallbackDict = [NSDictionary<NSString *, id> dictionaryWithContentsOfFile:@"/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreText.framework/Resources/DefaultFontFallbacks.plist"];
|
||||||
|
|
||||||
|
for (NSString *style in [fallbackDict allKeys]) {
|
||||||
|
NSArray *list = [fallbackDict valueForKey:style];
|
||||||
|
QFont::StyleHint fallbackStyleHint = styleHintFromNSString(style);
|
||||||
|
QStringList fallbackList;
|
||||||
|
for (id item in list) {
|
||||||
|
// sort the array based on system language preferences
|
||||||
|
if ([item isKindOfClass:[NSArray class]]) {
|
||||||
|
NSArray *langs = [reinterpret_cast<NSArray *>(item)
|
||||||
|
sortedArrayUsingFunction:languageMapSort context:languages];
|
||||||
|
for (NSArray<NSString *> *map in langs)
|
||||||
|
fallbackList.append(familyNameFromPostScriptName([map objectAtIndex:1]));
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass: [NSString class]])
|
||||||
|
fallbackList.append(familyNameFromPostScriptName(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackList.append(QLatin1String("Apple Color Emoji"));
|
||||||
|
|
||||||
|
addExtraFallbacks(&fallbackList);
|
||||||
|
fallbackLists[styleLookupKey.arg(fallbackStyleHint)] = fallbackList;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
QStringList staticFallbackList;
|
||||||
|
staticFallbackList << QString::fromLatin1("Helvetica,Apple Color Emoji,Geeza Pro,Arial Hebrew,Thonburi,Kailasa"
|
||||||
|
"Hiragino Kaku Gothic ProN,.Heiti J,Apple SD Gothic Neo,.Heiti K,Heiti SC,Heiti TC"
|
||||||
|
"Bangla Sangam MN,Devanagari Sangam MN,Gujarati Sangam MN,Gurmukhi MN,Kannada Sangam MN"
|
||||||
|
"Malayalam Sangam MN,Oriya Sangam MN,Sinhala Sangam MN,Tamil Sangam MN,Telugu Sangam MN"
|
||||||
|
"Euphemia UCAS,.PhoneFallback").split(QLatin1String(","));
|
||||||
|
|
||||||
|
for (int i = QFont::Helvetica; i <= QFont::Fantasy; ++i)
|
||||||
|
fallbackLists[styleLookupKey.arg(i)] = staticFallbackList;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
didPopulateStyleFallbacks = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(!fallbackLists.isEmpty());
|
||||||
|
return fallbackLists[styleLookupKey.arg(styleHint)];
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
|
||||||
|
{
|
||||||
|
QCFType<CFArrayRef> fonts;
|
||||||
|
|
||||||
|
if (!fontData.isEmpty()) {
|
||||||
|
QCFType<CFDataRef> fontDataReference = fontData.toRawCFData();
|
||||||
|
if (QCFType<CTFontDescriptorRef> descriptor = CTFontManagerCreateFontDescriptorFromData(fontDataReference)) {
|
||||||
|
// There's no way to get the data back out of a font descriptor created with
|
||||||
|
// CTFontManagerCreateFontDescriptorFromData, so we attach the data manually.
|
||||||
|
NSDictionary *attributes = @{ kQtFontDataAttribute : [NSValue valueWithPointer:new QByteArray(fontData)] };
|
||||||
|
descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, (CFDictionaryRef)attributes);
|
||||||
|
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||||
|
CFArrayAppendValue(array, descriptor);
|
||||||
|
fonts = array;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QCFType<CFURLRef> fontURL = QUrl::fromLocalFile(fileName).toCFURL();
|
||||||
|
fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fonts)
|
||||||
|
return QStringList();
|
||||||
|
|
||||||
|
QStringList families;
|
||||||
|
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(QString::fromCFString(familyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: We don't do font matching via CoreText for application fonts, so we don't
|
||||||
|
// need to enable font matching for them via CTFontManagerEnableFontDescriptors.
|
||||||
|
|
||||||
|
return families;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QCoreTextFontDatabase::isPrivateFontFamily(const QString &family) const
|
||||||
|
{
|
||||||
|
if (family.startsWith(QLatin1Char('.')) || family == QLatin1String("LastResort"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return QPlatformFontDatabase::isPrivateFontFamily(family);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f)
|
||||||
|
{
|
||||||
|
switch (f) {
|
||||||
|
case QPlatformTheme::SystemFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::MenuFont:
|
||||||
|
case QPlatformTheme::MenuBarFont:
|
||||||
|
case QPlatformTheme::MenuItemFont:
|
||||||
|
return kCTFontUIFontMenuItem;
|
||||||
|
|
||||||
|
case QPlatformTheme::MessageBoxFont:
|
||||||
|
return kCTFontUIFontEmphasizedSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::LabelFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::TipLabelFont:
|
||||||
|
return kCTFontUIFontToolTip;
|
||||||
|
|
||||||
|
case QPlatformTheme::StatusBarFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::TitleBarFont:
|
||||||
|
return kCTFontUIFontWindowTitle;
|
||||||
|
|
||||||
|
case QPlatformTheme::MdiSubWindowTitleFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::DockWidgetTitleFont:
|
||||||
|
return kCTFontUIFontSmallSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::PushButtonFont:
|
||||||
|
return kCTFontUIFontPushButton;
|
||||||
|
|
||||||
|
case QPlatformTheme::CheckBoxFont:
|
||||||
|
case QPlatformTheme::RadioButtonFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::ToolButtonFont:
|
||||||
|
return kCTFontUIFontSmallToolbar;
|
||||||
|
|
||||||
|
case QPlatformTheme::ItemViewFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::ListViewFont:
|
||||||
|
return kCTFontUIFontViews;
|
||||||
|
|
||||||
|
case QPlatformTheme::HeaderViewFont:
|
||||||
|
return kCTFontUIFontSmallSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::ListBoxFont:
|
||||||
|
return kCTFontUIFontViews;
|
||||||
|
|
||||||
|
case QPlatformTheme::ComboMenuItemFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::ComboLineEditFont:
|
||||||
|
return kCTFontUIFontViews;
|
||||||
|
|
||||||
|
case QPlatformTheme::SmallFont:
|
||||||
|
return kCTFontUIFontSmallSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::MiniFont:
|
||||||
|
return kCTFontUIFontMiniSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::FixedFont:
|
||||||
|
return kCTFontUIFontUserFixedPitch;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CTFontDescriptorRef fontDescriptorFromTheme(QPlatformTheme::Font f)
|
||||||
|
{
|
||||||
|
#if defined(QT_PLATFORM_UIKIT)
|
||||||
|
// Use Dynamic Type to resolve theme fonts if possible, to get
|
||||||
|
// correct font sizes and style based on user configuration.
|
||||||
|
NSString *textStyle = 0;
|
||||||
|
switch (f) {
|
||||||
|
case QPlatformTheme::TitleBarFont:
|
||||||
|
case QPlatformTheme::HeaderViewFont:
|
||||||
|
textStyle = UIFontTextStyleHeadline;
|
||||||
|
break;
|
||||||
|
case QPlatformTheme::MdiSubWindowTitleFont:
|
||||||
|
textStyle = UIFontTextStyleSubheadline;
|
||||||
|
break;
|
||||||
|
case QPlatformTheme::TipLabelFont:
|
||||||
|
case QPlatformTheme::SmallFont:
|
||||||
|
textStyle = UIFontTextStyleFootnote;
|
||||||
|
break;
|
||||||
|
case QPlatformTheme::MiniFont:
|
||||||
|
textStyle = UIFontTextStyleCaption2;
|
||||||
|
break;
|
||||||
|
case QPlatformTheme::FixedFont:
|
||||||
|
// Fall back to regular code path, as iOS doesn't provide
|
||||||
|
// an appropriate text style for this theme font.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
textStyle = UIFontTextStyleBody;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textStyle) {
|
||||||
|
UIFontDescriptor *desc = [UIFontDescriptor preferredFontDescriptorWithTextStyle:textStyle];
|
||||||
|
return static_cast<CTFontDescriptorRef>(CFBridgingRetain(desc));
|
||||||
|
}
|
||||||
|
#endif // Q_OS_IOS, Q_OS_TVOS, Q_OS_WATCHOS
|
||||||
|
|
||||||
|
// OSX default case and iOS fallback case
|
||||||
|
CTFontUIFontType fontType = fontTypeFromTheme(f);
|
||||||
|
QCFType<CTFontRef> ctFont = CTFontCreateUIFontForLanguage(fontType, 0.0, NULL);
|
||||||
|
return CTFontCopyFontDescriptor(ctFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QHash<QPlatformTheme::Font, QFont *> &QCoreTextFontDatabase::themeFonts() const
|
||||||
|
{
|
||||||
|
if (m_themeFonts.isEmpty()) {
|
||||||
|
for (long f = QPlatformTheme::SystemFont; f < QPlatformTheme::NFonts; f++) {
|
||||||
|
QPlatformTheme::Font ft = static_cast<QPlatformTheme::Font>(f);
|
||||||
|
m_themeFonts.insert(ft, themeFont(ft));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_themeFonts;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const
|
||||||
|
{
|
||||||
|
CTFontDescriptorRef fontDesc = fontDescriptorFromTheme(f);
|
||||||
|
FontDescription fd;
|
||||||
|
getFontDescription(fontDesc, &fd);
|
||||||
|
|
||||||
|
if (!m_systemFontDescriptors.contains(fontDesc))
|
||||||
|
m_systemFontDescriptors.insert(fontDesc);
|
||||||
|
else
|
||||||
|
CFRelease(fontDesc);
|
||||||
|
|
||||||
|
QFont *font = new QFont(fd.familyName, fd.pointSize, fd.weight, fd.style == QFont::StyleItalic);
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont QCoreTextFontDatabase::defaultFont() const
|
||||||
|
{
|
||||||
|
if (defaultFontName.isEmpty()) {
|
||||||
|
QCFType<CTFontRef> font = CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, 12.0, NULL);
|
||||||
|
defaultFontName = (QString) QCFString(CTFontCopyFullName(font));
|
||||||
|
}
|
||||||
|
|
||||||
|
return QFont(defaultFontName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QCoreTextFontDatabase::fontsAlwaysScalable() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<int> QCoreTextFontDatabase::standardSizes() const
|
||||||
|
{
|
||||||
|
QList<int> ret;
|
||||||
|
static const unsigned short standard[] =
|
||||||
|
{ 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288, 0 };
|
||||||
|
ret.reserve(int(sizeof(standard) / sizeof(standard[0])));
|
||||||
|
const unsigned short *sizes = standard;
|
||||||
|
while (*sizes) ret << *sizes++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
949
src/calibre/headless/coretext_fontdatabase-old.mm
Normal file
949
src/calibre/headless/coretext_fontdatabase-old.mm
Normal file
@ -0,0 +1,949 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2015 The Qt Company Ltd.
|
||||||
|
** Contact: http://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the plugins of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL21$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at http://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 or version 3 as published by the Free
|
||||||
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||||
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||||
|
** following information to ensure the GNU Lesser General Public License
|
||||||
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||||
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** As a special exception, The Qt Company gives you certain additional
|
||||||
|
** rights. These rights are described in The Qt Company LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "qglobal.h"
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#if defined(Q_OS_MACX)
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <IOKit/graphics/IOGraphicsLib.h>
|
||||||
|
#elif defined(Q_OS_IOS)
|
||||||
|
#import <UIKit/UIFont.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
|
||||||
|
#include <QtPlatformSupport/private/qfontengine_coretext_p.h>
|
||||||
|
#include <QtCore/QSettings>
|
||||||
|
#include <QtCore/QtEndian>
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
#include <QtGui/private/qfontengine_ft_p.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
// this could become a list of all languages used for each writing
|
||||||
|
// system, instead of using the single most common language.
|
||||||
|
static const char *languageForWritingSystem[] = {
|
||||||
|
0, // Any
|
||||||
|
"en", // Latin
|
||||||
|
"el", // Greek
|
||||||
|
"ru", // Cyrillic
|
||||||
|
"hy", // Armenian
|
||||||
|
"he", // Hebrew
|
||||||
|
"ar", // Arabic
|
||||||
|
"syr", // Syriac
|
||||||
|
"div", // Thaana
|
||||||
|
"hi", // Devanagari
|
||||||
|
"bn", // Bengali
|
||||||
|
"pa", // Gurmukhi
|
||||||
|
"gu", // Gujarati
|
||||||
|
"or", // Oriya
|
||||||
|
"ta", // Tamil
|
||||||
|
"te", // Telugu
|
||||||
|
"kn", // Kannada
|
||||||
|
"ml", // Malayalam
|
||||||
|
"si", // Sinhala
|
||||||
|
"th", // Thai
|
||||||
|
"lo", // Lao
|
||||||
|
"bo", // Tibetan
|
||||||
|
"my", // Myanmar
|
||||||
|
"ka", // Georgian
|
||||||
|
"km", // Khmer
|
||||||
|
"zh-Hans", // SimplifiedChinese
|
||||||
|
"zh-Hant", // TraditionalChinese
|
||||||
|
"ja", // Japanese
|
||||||
|
"ko", // Korean
|
||||||
|
"vi", // Vietnamese
|
||||||
|
0, // Symbol
|
||||||
|
"sga", // Ogham
|
||||||
|
"non", // Runic
|
||||||
|
"man" // N'Ko
|
||||||
|
};
|
||||||
|
enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) };
|
||||||
|
|
||||||
|
#ifdef Q_OS_OSX
|
||||||
|
static NSInteger languageMapSort(id obj1, id obj2, void *context)
|
||||||
|
{
|
||||||
|
NSArray *map1 = (NSArray *) obj1;
|
||||||
|
NSArray *map2 = (NSArray *) obj2;
|
||||||
|
NSArray *languages = (NSArray *) context;
|
||||||
|
|
||||||
|
NSString *lang1 = [map1 objectAtIndex: 0];
|
||||||
|
NSString *lang2 = [map2 objectAtIndex: 0];
|
||||||
|
|
||||||
|
return [languages indexOfObject: lang1] - [languages indexOfObject: lang2];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QCoreTextFontDatabase::QCoreTextFontDatabase(bool useFreeType)
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
: m_useFreeType(useFreeType)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
Q_UNUSED(useFreeType)
|
||||||
|
QCoreTextFontEngine::defaultGlyphFormat = QFontEngine::Format_A8;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCoreTextFontDatabase::~QCoreTextFontDatabase()
|
||||||
|
{
|
||||||
|
foreach (CTFontDescriptorRef ref, m_systemFontDescriptors)
|
||||||
|
CFRelease(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CFArrayRef availableFamilyNames()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_OSX)
|
||||||
|
return CTFontManagerCopyAvailableFontFamilyNames();
|
||||||
|
#elif defined(Q_OS_IOS)
|
||||||
|
return (CFArrayRef) [[UIFont familyNames] retain];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::populateFontDatabase()
|
||||||
|
{
|
||||||
|
// The caller (QFontDB) expects the db to be populate only with system fonts, so we need
|
||||||
|
// to make sure that any previously registered app fonts become invisible.
|
||||||
|
removeApplicationFonts();
|
||||||
|
|
||||||
|
QCFType<CFArrayRef> familyNames = availableFamilyNames();
|
||||||
|
const int numberOfFamilies = CFArrayGetCount(familyNames);
|
||||||
|
for (int i = 0; i < numberOfFamilies; ++i) {
|
||||||
|
CFStringRef familyNameRef = (CFStringRef) CFArrayGetValueAtIndex(familyNames, i);
|
||||||
|
QString familyName = QCFString::toQString(familyNameRef);
|
||||||
|
|
||||||
|
// Don't populate internal fonts
|
||||||
|
if (familyName.startsWith(QLatin1Char('.')) || familyName == QLatin1String("LastResort"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
||||||
|
// Skip font families with no corresponding fonts
|
||||||
|
if (![UIFont fontNamesForFamilyName:(NSString*)familyNameRef].count)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QPlatformFontDatabase::registerFontFamily(familyName);
|
||||||
|
|
||||||
|
#if defined(Q_OS_OSX)
|
||||||
|
QString localizedFamilyName = QString::fromNSString([[NSFontManager sharedFontManager] localizedNameForFamily:(NSString*)familyNameRef face:nil]);
|
||||||
|
if (familyName != localizedFamilyName)
|
||||||
|
QPlatformFontDatabase::registerAliasToFontFamily(familyName, localizedFamilyName);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force creating the theme fonts to get the descriptors in m_systemFontDescriptors
|
||||||
|
if (m_themeFonts.isEmpty())
|
||||||
|
(void)themeFonts();
|
||||||
|
|
||||||
|
Q_FOREACH (CTFontDescriptorRef fontDesc, m_systemFontDescriptors)
|
||||||
|
populateFromDescriptor(fontDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::populateFamily(const QString &familyName)
|
||||||
|
{
|
||||||
|
QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||||
|
CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, QCFString(familyName));
|
||||||
|
QCFType<CTFontDescriptorRef> nameOnlyDescriptor = CTFontDescriptorCreateWithAttributes(attributes);
|
||||||
|
|
||||||
|
// A single family might match several different fonts with different styles eg.
|
||||||
|
QCFType<CFArrayRef> matchingFonts = (CFArrayRef) CTFontDescriptorCreateMatchingFontDescriptors(nameOnlyDescriptor, 0);
|
||||||
|
if (!matchingFonts) {
|
||||||
|
qWarning() << "QCoreTextFontDatabase: Found no matching fonts for family" << familyName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int numFonts = CFArrayGetCount(matchingFonts);
|
||||||
|
for (int i = 0; i < numFonts; ++i)
|
||||||
|
populateFromDescriptor(CTFontDescriptorRef(CFArrayGetValueAtIndex(matchingFonts, i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FontDescription {
|
||||||
|
QCFString familyName;
|
||||||
|
QCFString styleName;
|
||||||
|
QString foundryName;
|
||||||
|
QFont::Weight weight;
|
||||||
|
QFont::Style style;
|
||||||
|
QFont::Stretch stretch;
|
||||||
|
int pixelSize;
|
||||||
|
bool fixedPitch;
|
||||||
|
QSupportedWritingSystems writingSystems;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
|
||||||
|
{
|
||||||
|
QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
|
||||||
|
|
||||||
|
fd->foundryName = QStringLiteral("CoreText");
|
||||||
|
fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
|
||||||
|
fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
|
||||||
|
fd->weight = QFont::Normal;
|
||||||
|
fd->style = QFont::StyleNormal;
|
||||||
|
fd->stretch = QFont::Unstretched;
|
||||||
|
fd->fixedPitch = false;
|
||||||
|
|
||||||
|
if (QCFType<CTFontRef> tempFont = CTFontCreateWithFontDescriptor(font, 0.0, 0)) {
|
||||||
|
uint tag = MAKE_TAG('O', 'S', '/', '2');
|
||||||
|
CTFontRef tempFontRef = tempFont;
|
||||||
|
void *userData = reinterpret_cast<void *>(&tempFontRef);
|
||||||
|
uint length = 128;
|
||||||
|
QVarLengthArray<uchar, 128> os2Table(length);
|
||||||
|
if (QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length) && length >= 86) {
|
||||||
|
if (length > uint(os2Table.length())) {
|
||||||
|
os2Table.resize(length);
|
||||||
|
if (!QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length))
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
Q_ASSERT(length >= 86);
|
||||||
|
}
|
||||||
|
quint32 unicodeRange[4] = {
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 42),
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 46),
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 50),
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 54)
|
||||||
|
};
|
||||||
|
quint32 codePageRange[2] = {
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 78),
|
||||||
|
qFromBigEndian<quint32>(os2Table.data() + 82)
|
||||||
|
};
|
||||||
|
fd->writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styles) {
|
||||||
|
if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) {
|
||||||
|
double normalizedWeight;
|
||||||
|
if (CFNumberGetValue(weightValue, kCFNumberFloat64Type, &normalizedWeight))
|
||||||
|
fd->weight = QCoreTextFontEngine::qtWeightFromCFWeight(float(normalizedWeight));
|
||||||
|
}
|
||||||
|
if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
|
||||||
|
double d;
|
||||||
|
if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) {
|
||||||
|
if (d > 0.0)
|
||||||
|
fd->style = QFont::StyleItalic;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) {
|
||||||
|
int d;
|
||||||
|
if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) {
|
||||||
|
if (d & kCTFontMonoSpaceTrait)
|
||||||
|
fd->fixedPitch = true;
|
||||||
|
if (d & kCTFontExpandedTrait)
|
||||||
|
fd->stretch = QFont::Expanded;
|
||||||
|
else if (d & kCTFontCondensedTrait)
|
||||||
|
fd->stretch = QFont::Condensed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QCFType<CFNumberRef> size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) {
|
||||||
|
if (CFNumberIsFloatType(size)) {
|
||||||
|
double d;
|
||||||
|
CFNumberGetValue(size, kCFNumberDoubleType, &d);
|
||||||
|
fd->pixelSize = d;
|
||||||
|
} else {
|
||||||
|
CFNumberGetValue(size, kCFNumberIntType, &fd->pixelSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) {
|
||||||
|
CFIndex length = CFArrayGetCount(languages);
|
||||||
|
for (int i = 1; i < LanguageCount; ++i) {
|
||||||
|
if (!languageForWritingSystem[i])
|
||||||
|
continue;
|
||||||
|
QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII);
|
||||||
|
if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang))
|
||||||
|
fd->writingSystems.setSupported(QFontDatabase::WritingSystem(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
|
||||||
|
{
|
||||||
|
FontDescription fd;
|
||||||
|
getFontDescription(font, &fd);
|
||||||
|
|
||||||
|
CFRetain(font);
|
||||||
|
QPlatformFontDatabase::registerFont(fd.familyName, fd.styleName, fd.foundryName, fd.weight, fd.style, fd.stretch,
|
||||||
|
true /* antialiased */, true /* scalable */,
|
||||||
|
fd.pixelSize, fd.fixedPitch, fd.writingSystems, (void *) font);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::releaseHandle(void *handle)
|
||||||
|
{
|
||||||
|
CFRelease(CTFontDescriptorRef(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
static QByteArray filenameForCFUrl(CFURLRef url)
|
||||||
|
{
|
||||||
|
// The on-stack buffer prevents that a QByteArray allocated for the worst case (MAXPATHLEN)
|
||||||
|
// stays around for the lifetime of the font. Additionally, it helps to move the char
|
||||||
|
// signedness cast to an acceptable place.
|
||||||
|
uchar buffer[MAXPATHLEN];
|
||||||
|
QByteArray filename;
|
||||||
|
|
||||||
|
if (!CFURLGetFileSystemRepresentation(url, true, buffer, sizeof(buffer))) {
|
||||||
|
qWarning("QCoreTextFontDatabase::filenameForCFUrl: could not resolve file for URL %s",
|
||||||
|
url ? qPrintable(QString::fromCFString(CFURLGetString(url))) : "(null)");
|
||||||
|
} else {
|
||||||
|
QCFType<CFStringRef> scheme = CFURLCopyScheme(url);
|
||||||
|
if (QString::fromCFString(scheme) == QLatin1String("qrc"))
|
||||||
|
filename = ":";
|
||||||
|
|
||||||
|
filename += reinterpret_cast<char *>(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef);
|
||||||
|
|
||||||
|
QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr)
|
||||||
|
{
|
||||||
|
CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(usrPtr);
|
||||||
|
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
if (m_useFreeType) {
|
||||||
|
QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute)));
|
||||||
|
|
||||||
|
QByteArray filename;
|
||||||
|
if (url)
|
||||||
|
filename = filenameForCFUrl(url);
|
||||||
|
|
||||||
|
return freeTypeFontEngine(f, filename);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Since we do not pass in the destination DPI to CoreText when making
|
||||||
|
// the font, we need to pass in a point size which is scaled to include
|
||||||
|
// the DPI. The default DPI for the screen is 72, thus the scale factor
|
||||||
|
// is destinationDpi / 72, but since pixelSize = pointSize / 72 * dpi,
|
||||||
|
// the pixelSize is actually the scaled point size for the destination
|
||||||
|
// DPI, and we can use that directly.
|
||||||
|
qreal scaledPointSize = f.pixelSize;
|
||||||
|
|
||||||
|
CGAffineTransform matrix = qt_transform_from_fontdef(f);
|
||||||
|
CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix);
|
||||||
|
if (font) {
|
||||||
|
QFontEngine *engine = new QCoreTextFontEngine(font, f);
|
||||||
|
engine->fontDef = f;
|
||||||
|
CFRelease(font);
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void releaseFontData(void* info, const void* data, size_t size)
|
||||||
|
{
|
||||||
|
Q_UNUSED(data);
|
||||||
|
Q_UNUSED(size);
|
||||||
|
delete (QByteArray*)info;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFontEngine *QCoreTextFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
|
||||||
|
{
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
if (m_useFreeType) {
|
||||||
|
QByteArray *fontDataCopy = new QByteArray(fontData);
|
||||||
|
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
|
||||||
|
fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
|
||||||
|
QCFType<CGFontRef> cgFont(CGFontCreateWithDataProvider(dataProvider));
|
||||||
|
|
||||||
|
if (!cgFont) {
|
||||||
|
qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed");
|
||||||
|
return Q_NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFontDef fontDef;
|
||||||
|
fontDef.pixelSize = pixelSize;
|
||||||
|
fontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi();
|
||||||
|
fontDef.hintingPreference = hintingPreference;
|
||||||
|
CGAffineTransform transform = qt_transform_from_fontdef(fontDef);
|
||||||
|
QCFType<CTFontRef> ctFont(CTFontCreateWithGraphicsFont(cgFont, fontDef.pixelSize, &transform, Q_NULLPTR));
|
||||||
|
QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontCopyAttribute(ctFont, kCTFontURLAttribute)));
|
||||||
|
return freeTypeFontEngine(fontDef, filenameForCFUrl(url), fontData);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Q_UNUSED(hintingPreference);
|
||||||
|
|
||||||
|
QByteArray* fontDataCopy = new QByteArray(fontData);
|
||||||
|
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
|
||||||
|
fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
|
||||||
|
|
||||||
|
CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider);
|
||||||
|
|
||||||
|
QFontEngine *fontEngine = NULL;
|
||||||
|
if (cgFont == NULL) {
|
||||||
|
qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed");
|
||||||
|
} else {
|
||||||
|
QFontDef def;
|
||||||
|
def.pixelSize = pixelSize;
|
||||||
|
def.pointSize = pixelSize * 72.0 / qt_defaultDpi();
|
||||||
|
fontEngine = new QCoreTextFontEngine(cgFont, def);
|
||||||
|
CFRelease(cgFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fontEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont::StyleHint styleHintFromNSString(NSString *style)
|
||||||
|
{
|
||||||
|
if ([style isEqual: @"sans-serif"])
|
||||||
|
return QFont::SansSerif;
|
||||||
|
else if ([style isEqual: @"monospace"])
|
||||||
|
return QFont::Monospace;
|
||||||
|
else if ([style isEqual: @"cursive"])
|
||||||
|
return QFont::Cursive;
|
||||||
|
else if ([style isEqual: @"serif"])
|
||||||
|
return QFont::Serif;
|
||||||
|
else if ([style isEqual: @"fantasy"])
|
||||||
|
return QFont::Fantasy;
|
||||||
|
else // if ([style isEqual: @"default"])
|
||||||
|
return QFont::AnyStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_OSX
|
||||||
|
static QString familyNameFromPostScriptName(NSString *psName)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
Q_UNUSED(style);
|
||||||
|
Q_UNUSED(script);
|
||||||
|
|
||||||
|
QMacAutoReleasePool pool;
|
||||||
|
|
||||||
|
static QHash<QString, QStringList> fallbackLists;
|
||||||
|
|
||||||
|
if (!family.isEmpty()) {
|
||||||
|
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_8, __IPHONE_6_0)
|
||||||
|
// CTFontCopyDefaultCascadeListForLanguages is available in the SDK
|
||||||
|
#if QT_MAC_DEPLOYMENT_TARGET_BELOW(__MAC_10_8, __IPHONE_6_0)
|
||||||
|
// But we have to feature check at runtime
|
||||||
|
if (&CTFontCopyDefaultCascadeListForLanguages)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_OSX)
|
||||||
|
// Since we are only returning a list of default fonts for the current language, we do not
|
||||||
|
// cover all unicode completely. This was especially an issue for some of the common script
|
||||||
|
// symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk
|
||||||
|
// of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most
|
||||||
|
// of Unicode 2.1.
|
||||||
|
if (!fallbackList.contains(QStringLiteral("Arial Unicode MS")))
|
||||||
|
fallbackList.append(QStringLiteral("Arial Unicode MS"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return fallbackList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// We were not able to find a fallback for the specific family,
|
||||||
|
// so we fall back to the stylehint.
|
||||||
|
|
||||||
|
static const QString styleLookupKey = QString::fromLatin1(".QFontStyleHint_%1");
|
||||||
|
|
||||||
|
static bool didPopulateStyleFallbacks = false;
|
||||||
|
if (!didPopulateStyleFallbacks) {
|
||||||
|
#if defined(Q_OS_MACX)
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"];
|
||||||
|
|
||||||
|
NSDictionary *fallbackDict = [NSDictionary dictionaryWithContentsOfFile: @"/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreText.framework/Resources/DefaultFontFallbacks.plist"];
|
||||||
|
|
||||||
|
for (NSString *style in [fallbackDict allKeys]) {
|
||||||
|
NSArray *list = [fallbackDict valueForKey: style];
|
||||||
|
QFont::StyleHint fallbackStyleHint = styleHintFromNSString(style);
|
||||||
|
QStringList fallbackList;
|
||||||
|
for (id item in list) {
|
||||||
|
// sort the array based on system language preferences
|
||||||
|
if ([item isKindOfClass: [NSArray class]]) {
|
||||||
|
NSArray *langs = [(NSArray *) item sortedArrayUsingFunction: languageMapSort
|
||||||
|
context: languages];
|
||||||
|
for (NSArray *map in langs)
|
||||||
|
fallbackList.append(familyNameFromPostScriptName([map objectAtIndex: 1]));
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass: [NSString class]])
|
||||||
|
fallbackList.append(familyNameFromPostScriptName(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
fallbackList.append(QLatin1String("Apple Color Emoji"));
|
||||||
|
|
||||||
|
// Since we are only returning a list of default fonts for the current language, we do not
|
||||||
|
// cover all unicode completely. This was especially an issue for some of the common script
|
||||||
|
// symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk
|
||||||
|
// of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most
|
||||||
|
// of Unicode 2.1.
|
||||||
|
if (!fallbackList.contains(QStringLiteral("Arial Unicode MS")))
|
||||||
|
fallbackList.append(QStringLiteral("Arial Unicode MS"));
|
||||||
|
|
||||||
|
fallbackLists[styleLookupKey.arg(fallbackStyleHint)] = fallbackList;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
QStringList staticFallbackList;
|
||||||
|
staticFallbackList << QString::fromLatin1("Helvetica,Apple Color Emoji,Geeza Pro,Arial Hebrew,Thonburi,Kailasa"
|
||||||
|
"Hiragino Kaku Gothic ProN,.Heiti J,Apple SD Gothic Neo,.Heiti K,Heiti SC,Heiti TC"
|
||||||
|
"Bangla Sangam MN,Devanagari Sangam MN,Gujarati Sangam MN,Gurmukhi MN,Kannada Sangam MN"
|
||||||
|
"Malayalam Sangam MN,Oriya Sangam MN,Sinhala Sangam MN,Tamil Sangam MN,Telugu Sangam MN"
|
||||||
|
"Euphemia UCAS,.PhoneFallback").split(QLatin1String(","));
|
||||||
|
|
||||||
|
for (int i = QFont::Helvetica; i <= QFont::Fantasy; ++i)
|
||||||
|
fallbackLists[styleLookupKey.arg(i)] = staticFallbackList;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
didPopulateStyleFallbacks = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(!fallbackLists.isEmpty());
|
||||||
|
return fallbackLists[styleLookupKey.arg(styleHint)];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_CORETEXT
|
||||||
|
static CFArrayRef createDescriptorArrayForFont(CTFontRef font, const QString &fileName = QString())
|
||||||
|
{
|
||||||
|
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||||
|
QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font);
|
||||||
|
|
||||||
|
Q_UNUSED(fileName)
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
// The physical font source URL (usually a local file or Qt resource) is only required for
|
||||||
|
// FreeType, when using non-system fonts, and needs some hackery to attach in a format
|
||||||
|
// agreeable to OSX.
|
||||||
|
if (!fileName.isEmpty()) {
|
||||||
|
QCFType<CFURLRef> fontURL;
|
||||||
|
|
||||||
|
if (fileName.startsWith(QLatin1String(":/"))) {
|
||||||
|
// QUrl::fromLocalFile() doesn't accept qrc pseudo-paths like ":/fonts/myfont.ttf".
|
||||||
|
// Therefore construct from QString with the qrc:// scheme -> "qrc:///fonts/myfont.ttf".
|
||||||
|
fontURL = QUrl(QStringLiteral("qrc://") + fileName.mid(1)).toCFURL();
|
||||||
|
} else if (!fileName.isEmpty()) {
|
||||||
|
// At this point we hope that filename is in a format that QUrl can handle.
|
||||||
|
fontURL = QUrl::fromLocalFile(fileName).toCFURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 1,
|
||||||
|
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||||
|
CFDictionaryAddValue(attributes, kCTFontURLAttribute, fontURL);
|
||||||
|
descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, attributes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CFArrayAppendValue(array, descriptor);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider);
|
||||||
|
if (cgFont) {
|
||||||
|
if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) {
|
||||||
|
QCFType<CTFontRef> font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL);
|
||||||
|
fonts = createDescriptorArrayForFont(font
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
, m_useFreeType ? fileName : QString()
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
m_applicationFonts.append(QVariant::fromValue(QCFType<CGFontRef>::constructFromGet(cgFont)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QCFType<CFURLRef> fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false);
|
||||||
|
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 (error) {
|
||||||
|
NSLog(@"Unable to register font: %@", error);
|
||||||
|
CFRelease(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if HAVE_CORETEXT && HAVE_ATS
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
#if HAVE_ATS
|
||||||
|
{
|
||||||
|
ATSFontContainerRef fontContainer;
|
||||||
|
OSStatus e;
|
||||||
|
|
||||||
|
if (!fontData.isEmpty()) {
|
||||||
|
e = ATSFontActivateFromMemory((void *) fontData.constData(), fontData.size(),
|
||||||
|
kATSFontContextLocal, kATSFontFormatUnspecified, NULL,
|
||||||
|
kATSOptionFlagsDefault, &fontContainer);
|
||||||
|
} else {
|
||||||
|
FSRef ref;
|
||||||
|
if (FSPathMakeRef(reinterpret_cast<const UInt8 *>(fileName.toUtf8().constData()),
|
||||||
|
&ref, 0) != 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();
|
||||||
|
|
||||||
|
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 families;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QCoreTextFontDatabase::isPrivateFontFamily(const QString &family) const
|
||||||
|
{
|
||||||
|
if (family.startsWith(QLatin1Char('.')))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return QPlatformFontDatabase::isPrivateFontFamily(family);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f)
|
||||||
|
{
|
||||||
|
switch (f) {
|
||||||
|
case QPlatformTheme::SystemFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::MenuFont:
|
||||||
|
case QPlatformTheme::MenuBarFont:
|
||||||
|
case QPlatformTheme::MenuItemFont:
|
||||||
|
return kCTFontUIFontMenuItem;
|
||||||
|
|
||||||
|
case QPlatformTheme::MessageBoxFont:
|
||||||
|
return kCTFontUIFontEmphasizedSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::LabelFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::TipLabelFont:
|
||||||
|
return kCTFontToolTipFontType;
|
||||||
|
|
||||||
|
case QPlatformTheme::StatusBarFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::TitleBarFont:
|
||||||
|
return kCTFontUIFontWindowTitle;
|
||||||
|
|
||||||
|
case QPlatformTheme::MdiSubWindowTitleFont:
|
||||||
|
case QPlatformTheme::DockWidgetTitleFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::PushButtonFont:
|
||||||
|
return kCTFontUIFontPushButton;
|
||||||
|
|
||||||
|
case QPlatformTheme::CheckBoxFont:
|
||||||
|
case QPlatformTheme::RadioButtonFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::ToolButtonFont:
|
||||||
|
return kCTFontUIFontSmallToolbar;
|
||||||
|
|
||||||
|
case QPlatformTheme::ItemViewFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::ListViewFont:
|
||||||
|
return kCTFontUIFontViews;
|
||||||
|
|
||||||
|
case QPlatformTheme::HeaderViewFont:
|
||||||
|
return kCTFontUIFontSmallSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::ListBoxFont:
|
||||||
|
return kCTFontUIFontViews;
|
||||||
|
|
||||||
|
case QPlatformTheme::ComboMenuItemFont:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::ComboLineEditFont:
|
||||||
|
return kCTFontUIFontViews;
|
||||||
|
|
||||||
|
case QPlatformTheme::SmallFont:
|
||||||
|
return kCTFontUIFontSmallSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::MiniFont:
|
||||||
|
return kCTFontUIFontMiniSystem;
|
||||||
|
|
||||||
|
case QPlatformTheme::FixedFont:
|
||||||
|
return kCTFontUIFontUserFixedPitch;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return kCTFontUIFontSystem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CTFontDescriptorRef fontDescriptorFromTheme(QPlatformTheme::Font f)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0) {
|
||||||
|
// Use Dynamic Type to resolve theme fonts if possible, to get
|
||||||
|
// correct font sizes and style based on user configuration.
|
||||||
|
NSString *textStyle = 0;
|
||||||
|
switch (f) {
|
||||||
|
case QPlatformTheme::TitleBarFont:
|
||||||
|
case QPlatformTheme::HeaderViewFont:
|
||||||
|
textStyle = UIFontTextStyleHeadline;
|
||||||
|
break;
|
||||||
|
case QPlatformTheme::MdiSubWindowTitleFont:
|
||||||
|
textStyle = UIFontTextStyleSubheadline;
|
||||||
|
break;
|
||||||
|
case QPlatformTheme::TipLabelFont:
|
||||||
|
case QPlatformTheme::SmallFont:
|
||||||
|
textStyle = UIFontTextStyleFootnote;
|
||||||
|
break;
|
||||||
|
case QPlatformTheme::MiniFont:
|
||||||
|
textStyle = UIFontTextStyleCaption2;
|
||||||
|
break;
|
||||||
|
case QPlatformTheme::FixedFont:
|
||||||
|
// Fall back to regular code path, as iOS doesn't provide
|
||||||
|
// an appropriate text style for this theme font.
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
textStyle = UIFontTextStyleBody;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textStyle) {
|
||||||
|
UIFontDescriptor *desc = [UIFontDescriptor preferredFontDescriptorWithTextStyle:textStyle];
|
||||||
|
return static_cast<CTFontDescriptorRef>(CFBridgingRetain(desc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // Q_OS_IOS
|
||||||
|
|
||||||
|
// OSX default case and iOS fallback case
|
||||||
|
CTFontUIFontType fontType = fontTypeFromTheme(f);
|
||||||
|
QCFType<CTFontRef> ctFont = CTFontCreateUIFontForLanguage(fontType, 0.0, NULL);
|
||||||
|
return CTFontCopyFontDescriptor(ctFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QHash<QPlatformTheme::Font, QFont *> &QCoreTextFontDatabase::themeFonts() const
|
||||||
|
{
|
||||||
|
if (m_themeFonts.isEmpty()) {
|
||||||
|
for (long f = QPlatformTheme::SystemFont; f < QPlatformTheme::NFonts; f++) {
|
||||||
|
QPlatformTheme::Font ft = static_cast<QPlatformTheme::Font>(f);
|
||||||
|
m_themeFonts.insert(ft, themeFont(ft));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_themeFonts;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const
|
||||||
|
{
|
||||||
|
CTFontDescriptorRef fontDesc = fontDescriptorFromTheme(f);
|
||||||
|
FontDescription fd;
|
||||||
|
getFontDescription(fontDesc, &fd);
|
||||||
|
|
||||||
|
if (!m_systemFontDescriptors.contains(fontDesc))
|
||||||
|
m_systemFontDescriptors.insert(fontDesc);
|
||||||
|
else
|
||||||
|
CFRelease(fontDesc);
|
||||||
|
|
||||||
|
QFont *font = new QFont(fd.familyName, fd.pixelSize, fd.weight, fd.style == QFont::StyleItalic);
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont QCoreTextFontDatabase::defaultFont() const
|
||||||
|
{
|
||||||
|
if (defaultFontName.isEmpty()) {
|
||||||
|
QCFType<CTFontRef> font = CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, 12.0, NULL);
|
||||||
|
defaultFontName = (QString) QCFString(CTFontCopyFullName(font));
|
||||||
|
}
|
||||||
|
|
||||||
|
return QFont(defaultFontName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QCoreTextFontDatabase::fontsAlwaysScalable() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<int> QCoreTextFontDatabase::standardSizes() const
|
||||||
|
{
|
||||||
|
QList<int> ret;
|
||||||
|
static const unsigned short standard[] =
|
||||||
|
{ 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288, 0 };
|
||||||
|
ret.reserve(int(sizeof(standard) / sizeof(standard[0])));
|
||||||
|
const unsigned short *sizes = standard;
|
||||||
|
while (*sizes) ret << *sizes++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QCoreTextFontDatabase::removeApplicationFonts()
|
||||||
|
{
|
||||||
|
if (m_applicationFonts.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
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
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
|
QFontEngine *QCoreTextFontDatabase::freeTypeFontEngine(const QFontDef &fontDef, const QByteArray &filename,
|
||||||
|
const QByteArray &fontData)
|
||||||
|
{
|
||||||
|
QFontEngine::FaceId faceId;
|
||||||
|
faceId.filename = filename;
|
||||||
|
const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
|
||||||
|
|
||||||
|
QScopedPointer<QFontEngineFT> engine(new QFontEngineFT(fontDef));
|
||||||
|
QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono;
|
||||||
|
if (antialias) {
|
||||||
|
QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint();
|
||||||
|
if (subpixelType == QFontEngine::Subpixel_None || (fontDef.styleStrategy & QFont::NoSubpixelAntialias)) {
|
||||||
|
format = QFontEngineFT::Format_A8;
|
||||||
|
engine->subpixelType = QFontEngine::Subpixel_None;
|
||||||
|
} else {
|
||||||
|
format = QFontEngineFT::Format_A32;
|
||||||
|
engine->subpixelType = subpixelType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) {
|
||||||
|
qWarning() << "QCoreTextFontDatabase::freeTypefontEngine Failed to create engine";
|
||||||
|
return Q_NULLPTR;
|
||||||
|
}
|
||||||
|
engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
|
||||||
|
|
||||||
|
return engine.take();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
@ -1,949 +1,14 @@
|
|||||||
/****************************************************************************
|
/*
|
||||||
**
|
* coretext_fontdatabase.mm
|
||||||
** Copyright (C) 2015 The Qt Company Ltd.
|
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
** Contact: http://www.qt.io/licensing/
|
*
|
||||||
**
|
* Distributed under terms of the GPL3 license.
|
||||||
** This file is part of the plugins of the Qt Toolkit.
|
*/
|
||||||
**
|
|
||||||
** $QT_BEGIN_LICENSE:LGPL21$
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and The Qt Company. For licensing terms
|
|
||||||
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
||||||
** information use the contact form at http://www.qt.io/contact-us.
|
|
||||||
**
|
|
||||||
** GNU Lesser General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
||||||
** General Public License version 2.1 or version 3 as published by the Free
|
|
||||||
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
||||||
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
||||||
** following information to ensure the GNU Lesser General Public License
|
|
||||||
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
||||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
||||||
**
|
|
||||||
** As a special exception, The Qt Company gives you certain additional
|
|
||||||
** rights. These rights are described in The Qt Company LGPL Exception
|
|
||||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
||||||
**
|
|
||||||
** $QT_END_LICENSE$
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "qglobal.h"
|
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <QtGlobal>
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||||
#if defined(Q_OS_MACX)
|
#include "coretext_fontdatabase-new.mm"
|
||||||
#import <Cocoa/Cocoa.h>
|
|
||||||
#import <IOKit/graphics/IOGraphicsLib.h>
|
|
||||||
#elif defined(Q_OS_IOS)
|
|
||||||
#import <UIKit/UIFont.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
|
|
||||||
#include <QtPlatformSupport/private/qfontengine_coretext_p.h>
|
|
||||||
#include <QtCore/QSettings>
|
|
||||||
#include <QtCore/QtEndian>
|
|
||||||
#ifndef QT_NO_FREETYPE
|
|
||||||
#include <QtGui/private/qfontengine_ft_p.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
// this could become a list of all languages used for each writing
|
|
||||||
// system, instead of using the single most common language.
|
|
||||||
static const char *languageForWritingSystem[] = {
|
|
||||||
0, // Any
|
|
||||||
"en", // Latin
|
|
||||||
"el", // Greek
|
|
||||||
"ru", // Cyrillic
|
|
||||||
"hy", // Armenian
|
|
||||||
"he", // Hebrew
|
|
||||||
"ar", // Arabic
|
|
||||||
"syr", // Syriac
|
|
||||||
"div", // Thaana
|
|
||||||
"hi", // Devanagari
|
|
||||||
"bn", // Bengali
|
|
||||||
"pa", // Gurmukhi
|
|
||||||
"gu", // Gujarati
|
|
||||||
"or", // Oriya
|
|
||||||
"ta", // Tamil
|
|
||||||
"te", // Telugu
|
|
||||||
"kn", // Kannada
|
|
||||||
"ml", // Malayalam
|
|
||||||
"si", // Sinhala
|
|
||||||
"th", // Thai
|
|
||||||
"lo", // Lao
|
|
||||||
"bo", // Tibetan
|
|
||||||
"my", // Myanmar
|
|
||||||
"ka", // Georgian
|
|
||||||
"km", // Khmer
|
|
||||||
"zh-Hans", // SimplifiedChinese
|
|
||||||
"zh-Hant", // TraditionalChinese
|
|
||||||
"ja", // Japanese
|
|
||||||
"ko", // Korean
|
|
||||||
"vi", // Vietnamese
|
|
||||||
0, // Symbol
|
|
||||||
"sga", // Ogham
|
|
||||||
"non", // Runic
|
|
||||||
"man" // N'Ko
|
|
||||||
};
|
|
||||||
enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) };
|
|
||||||
|
|
||||||
#ifdef Q_OS_OSX
|
|
||||||
static NSInteger languageMapSort(id obj1, id obj2, void *context)
|
|
||||||
{
|
|
||||||
NSArray *map1 = (NSArray *) obj1;
|
|
||||||
NSArray *map2 = (NSArray *) obj2;
|
|
||||||
NSArray *languages = (NSArray *) context;
|
|
||||||
|
|
||||||
NSString *lang1 = [map1 objectAtIndex: 0];
|
|
||||||
NSString *lang2 = [map2 objectAtIndex: 0];
|
|
||||||
|
|
||||||
return [languages indexOfObject: lang1] - [languages indexOfObject: lang2];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QCoreTextFontDatabase::QCoreTextFontDatabase(bool useFreeType)
|
|
||||||
#ifndef QT_NO_FREETYPE
|
|
||||||
: m_useFreeType(useFreeType)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
Q_UNUSED(useFreeType)
|
|
||||||
QCoreTextFontEngine::defaultGlyphFormat = QFontEngine::Format_A8;
|
|
||||||
}
|
|
||||||
|
|
||||||
QCoreTextFontDatabase::~QCoreTextFontDatabase()
|
|
||||||
{
|
|
||||||
foreach (CTFontDescriptorRef ref, m_systemFontDescriptors)
|
|
||||||
CFRelease(ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CFArrayRef availableFamilyNames()
|
|
||||||
{
|
|
||||||
#if defined(Q_OS_OSX)
|
|
||||||
return CTFontManagerCopyAvailableFontFamilyNames();
|
|
||||||
#elif defined(Q_OS_IOS)
|
|
||||||
return (CFArrayRef) [[UIFont familyNames] retain];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void QCoreTextFontDatabase::populateFontDatabase()
|
|
||||||
{
|
|
||||||
// The caller (QFontDB) expects the db to be populate only with system fonts, so we need
|
|
||||||
// to make sure that any previously registered app fonts become invisible.
|
|
||||||
removeApplicationFonts();
|
|
||||||
|
|
||||||
QCFType<CFArrayRef> familyNames = availableFamilyNames();
|
|
||||||
const int numberOfFamilies = CFArrayGetCount(familyNames);
|
|
||||||
for (int i = 0; i < numberOfFamilies; ++i) {
|
|
||||||
CFStringRef familyNameRef = (CFStringRef) CFArrayGetValueAtIndex(familyNames, i);
|
|
||||||
QString familyName = QCFString::toQString(familyNameRef);
|
|
||||||
|
|
||||||
// Don't populate internal fonts
|
|
||||||
if (familyName.startsWith(QLatin1Char('.')) || familyName == QLatin1String("LastResort"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
|
|
||||||
// Skip font families with no corresponding fonts
|
|
||||||
if (![UIFont fontNamesForFamilyName:(NSString*)familyNameRef].count)
|
|
||||||
continue;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QPlatformFontDatabase::registerFontFamily(familyName);
|
|
||||||
|
|
||||||
#if defined(Q_OS_OSX)
|
|
||||||
QString localizedFamilyName = QString::fromNSString([[NSFontManager sharedFontManager] localizedNameForFamily:(NSString*)familyNameRef face:nil]);
|
|
||||||
if (familyName != localizedFamilyName)
|
|
||||||
QPlatformFontDatabase::registerAliasToFontFamily(familyName, localizedFamilyName);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force creating the theme fonts to get the descriptors in m_systemFontDescriptors
|
|
||||||
if (m_themeFonts.isEmpty())
|
|
||||||
(void)themeFonts();
|
|
||||||
|
|
||||||
Q_FOREACH (CTFontDescriptorRef fontDesc, m_systemFontDescriptors)
|
|
||||||
populateFromDescriptor(fontDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QCoreTextFontDatabase::populateFamily(const QString &familyName)
|
|
||||||
{
|
|
||||||
QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
||||||
CFDictionaryAddValue(attributes, kCTFontFamilyNameAttribute, QCFString(familyName));
|
|
||||||
QCFType<CTFontDescriptorRef> nameOnlyDescriptor = CTFontDescriptorCreateWithAttributes(attributes);
|
|
||||||
|
|
||||||
// A single family might match several different fonts with different styles eg.
|
|
||||||
QCFType<CFArrayRef> matchingFonts = (CFArrayRef) CTFontDescriptorCreateMatchingFontDescriptors(nameOnlyDescriptor, 0);
|
|
||||||
if (!matchingFonts) {
|
|
||||||
qWarning() << "QCoreTextFontDatabase: Found no matching fonts for family" << familyName;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int numFonts = CFArrayGetCount(matchingFonts);
|
|
||||||
for (int i = 0; i < numFonts; ++i)
|
|
||||||
populateFromDescriptor(CTFontDescriptorRef(CFArrayGetValueAtIndex(matchingFonts, i)));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FontDescription {
|
|
||||||
QCFString familyName;
|
|
||||||
QCFString styleName;
|
|
||||||
QString foundryName;
|
|
||||||
QFont::Weight weight;
|
|
||||||
QFont::Style style;
|
|
||||||
QFont::Stretch stretch;
|
|
||||||
int pixelSize;
|
|
||||||
bool fixedPitch;
|
|
||||||
QSupportedWritingSystems writingSystems;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
|
|
||||||
{
|
|
||||||
QCFType<CFDictionaryRef> styles = (CFDictionaryRef) CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
|
|
||||||
|
|
||||||
fd->foundryName = QStringLiteral("CoreText");
|
|
||||||
fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute);
|
|
||||||
fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute);
|
|
||||||
fd->weight = QFont::Normal;
|
|
||||||
fd->style = QFont::StyleNormal;
|
|
||||||
fd->stretch = QFont::Unstretched;
|
|
||||||
fd->fixedPitch = false;
|
|
||||||
|
|
||||||
if (QCFType<CTFontRef> tempFont = CTFontCreateWithFontDescriptor(font, 0.0, 0)) {
|
|
||||||
uint tag = MAKE_TAG('O', 'S', '/', '2');
|
|
||||||
CTFontRef tempFontRef = tempFont;
|
|
||||||
void *userData = reinterpret_cast<void *>(&tempFontRef);
|
|
||||||
uint length = 128;
|
|
||||||
QVarLengthArray<uchar, 128> os2Table(length);
|
|
||||||
if (QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length) && length >= 86) {
|
|
||||||
if (length > uint(os2Table.length())) {
|
|
||||||
os2Table.resize(length);
|
|
||||||
if (!QCoreTextFontEngine::ct_getSfntTable(userData, tag, os2Table.data(), &length))
|
|
||||||
Q_UNREACHABLE();
|
|
||||||
Q_ASSERT(length >= 86);
|
|
||||||
}
|
|
||||||
quint32 unicodeRange[4] = {
|
|
||||||
qFromBigEndian<quint32>(os2Table.data() + 42),
|
|
||||||
qFromBigEndian<quint32>(os2Table.data() + 46),
|
|
||||||
qFromBigEndian<quint32>(os2Table.data() + 50),
|
|
||||||
qFromBigEndian<quint32>(os2Table.data() + 54)
|
|
||||||
};
|
|
||||||
quint32 codePageRange[2] = {
|
|
||||||
qFromBigEndian<quint32>(os2Table.data() + 78),
|
|
||||||
qFromBigEndian<quint32>(os2Table.data() + 82)
|
|
||||||
};
|
|
||||||
fd->writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (styles) {
|
|
||||||
if (CFNumberRef weightValue = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontWeightTrait)) {
|
|
||||||
double normalizedWeight;
|
|
||||||
if (CFNumberGetValue(weightValue, kCFNumberFloat64Type, &normalizedWeight))
|
|
||||||
fd->weight = QCoreTextFontEngine::qtWeightFromCFWeight(float(normalizedWeight));
|
|
||||||
}
|
|
||||||
if (CFNumberRef italic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSlantTrait)) {
|
|
||||||
double d;
|
|
||||||
if (CFNumberGetValue(italic, kCFNumberDoubleType, &d)) {
|
|
||||||
if (d > 0.0)
|
|
||||||
fd->style = QFont::StyleItalic;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (CFNumberRef symbolic = (CFNumberRef) CFDictionaryGetValue(styles, kCTFontSymbolicTrait)) {
|
|
||||||
int d;
|
|
||||||
if (CFNumberGetValue(symbolic, kCFNumberSInt32Type, &d)) {
|
|
||||||
if (d & kCTFontMonoSpaceTrait)
|
|
||||||
fd->fixedPitch = true;
|
|
||||||
if (d & kCTFontExpandedTrait)
|
|
||||||
fd->stretch = QFont::Expanded;
|
|
||||||
else if (d & kCTFontCondensedTrait)
|
|
||||||
fd->stretch = QFont::Condensed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QCFType<CFNumberRef> size = (CFNumberRef) CTFontDescriptorCopyAttribute(font, kCTFontSizeAttribute)) {
|
|
||||||
if (CFNumberIsFloatType(size)) {
|
|
||||||
double d;
|
|
||||||
CFNumberGetValue(size, kCFNumberDoubleType, &d);
|
|
||||||
fd->pixelSize = d;
|
|
||||||
} else {
|
|
||||||
CFNumberGetValue(size, kCFNumberIntType, &fd->pixelSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QCFType<CFArrayRef> languages = (CFArrayRef) CTFontDescriptorCopyAttribute(font, kCTFontLanguagesAttribute)) {
|
|
||||||
CFIndex length = CFArrayGetCount(languages);
|
|
||||||
for (int i = 1; i < LanguageCount; ++i) {
|
|
||||||
if (!languageForWritingSystem[i])
|
|
||||||
continue;
|
|
||||||
QCFString lang = CFStringCreateWithCString(NULL, languageForWritingSystem[i], kCFStringEncodingASCII);
|
|
||||||
if (CFArrayContainsValue(languages, CFRangeMake(0, length), lang))
|
|
||||||
fd->writingSystems.setSupported(QFontDatabase::WritingSystem(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font)
|
|
||||||
{
|
|
||||||
FontDescription fd;
|
|
||||||
getFontDescription(font, &fd);
|
|
||||||
|
|
||||||
CFRetain(font);
|
|
||||||
QPlatformFontDatabase::registerFont(fd.familyName, fd.styleName, fd.foundryName, fd.weight, fd.style, fd.stretch,
|
|
||||||
true /* antialiased */, true /* scalable */,
|
|
||||||
fd.pixelSize, fd.fixedPitch, fd.writingSystems, (void *) font);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QCoreTextFontDatabase::releaseHandle(void *handle)
|
|
||||||
{
|
|
||||||
CFRelease(CTFontDescriptorRef(handle));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef QT_NO_FREETYPE
|
|
||||||
static QByteArray filenameForCFUrl(CFURLRef url)
|
|
||||||
{
|
|
||||||
// The on-stack buffer prevents that a QByteArray allocated for the worst case (MAXPATHLEN)
|
|
||||||
// stays around for the lifetime of the font. Additionally, it helps to move the char
|
|
||||||
// signedness cast to an acceptable place.
|
|
||||||
uchar buffer[MAXPATHLEN];
|
|
||||||
QByteArray filename;
|
|
||||||
|
|
||||||
if (!CFURLGetFileSystemRepresentation(url, true, buffer, sizeof(buffer))) {
|
|
||||||
qWarning("QCoreTextFontDatabase::filenameForCFUrl: could not resolve file for URL %s",
|
|
||||||
url ? qPrintable(QString::fromCFString(CFURLGetString(url))) : "(null)");
|
|
||||||
} else {
|
|
||||||
QCFType<CFStringRef> scheme = CFURLCopyScheme(url);
|
|
||||||
if (QString::fromCFString(scheme) == QLatin1String("qrc"))
|
|
||||||
filename = ":";
|
|
||||||
|
|
||||||
filename += reinterpret_cast<char *>(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef);
|
|
||||||
|
|
||||||
QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr)
|
|
||||||
{
|
|
||||||
CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(usrPtr);
|
|
||||||
|
|
||||||
#ifndef QT_NO_FREETYPE
|
|
||||||
if (m_useFreeType) {
|
|
||||||
QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute)));
|
|
||||||
|
|
||||||
QByteArray filename;
|
|
||||||
if (url)
|
|
||||||
filename = filenameForCFUrl(url);
|
|
||||||
|
|
||||||
return freeTypeFontEngine(f, filename);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Since we do not pass in the destination DPI to CoreText when making
|
|
||||||
// the font, we need to pass in a point size which is scaled to include
|
|
||||||
// the DPI. The default DPI for the screen is 72, thus the scale factor
|
|
||||||
// is destinationDpi / 72, but since pixelSize = pointSize / 72 * dpi,
|
|
||||||
// the pixelSize is actually the scaled point size for the destination
|
|
||||||
// DPI, and we can use that directly.
|
|
||||||
qreal scaledPointSize = f.pixelSize;
|
|
||||||
|
|
||||||
CGAffineTransform matrix = qt_transform_from_fontdef(f);
|
|
||||||
CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix);
|
|
||||||
if (font) {
|
|
||||||
QFontEngine *engine = new QCoreTextFontEngine(font, f);
|
|
||||||
engine->fontDef = f;
|
|
||||||
CFRelease(font);
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void releaseFontData(void* info, const void* data, size_t size)
|
|
||||||
{
|
|
||||||
Q_UNUSED(data);
|
|
||||||
Q_UNUSED(size);
|
|
||||||
delete (QByteArray*)info;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFontEngine *QCoreTextFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
|
|
||||||
{
|
|
||||||
#ifndef QT_NO_FREETYPE
|
|
||||||
if (m_useFreeType) {
|
|
||||||
QByteArray *fontDataCopy = new QByteArray(fontData);
|
|
||||||
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
|
|
||||||
fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
|
|
||||||
QCFType<CGFontRef> cgFont(CGFontCreateWithDataProvider(dataProvider));
|
|
||||||
|
|
||||||
if (!cgFont) {
|
|
||||||
qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed");
|
|
||||||
return Q_NULLPTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFontDef fontDef;
|
|
||||||
fontDef.pixelSize = pixelSize;
|
|
||||||
fontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi();
|
|
||||||
fontDef.hintingPreference = hintingPreference;
|
|
||||||
CGAffineTransform transform = qt_transform_from_fontdef(fontDef);
|
|
||||||
QCFType<CTFontRef> ctFont(CTFontCreateWithGraphicsFont(cgFont, fontDef.pixelSize, &transform, Q_NULLPTR));
|
|
||||||
QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontCopyAttribute(ctFont, kCTFontURLAttribute)));
|
|
||||||
return freeTypeFontEngine(fontDef, filenameForCFUrl(url), fontData);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Q_UNUSED(hintingPreference);
|
|
||||||
|
|
||||||
QByteArray* fontDataCopy = new QByteArray(fontData);
|
|
||||||
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
|
|
||||||
fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
|
|
||||||
|
|
||||||
CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider);
|
|
||||||
|
|
||||||
QFontEngine *fontEngine = NULL;
|
|
||||||
if (cgFont == NULL) {
|
|
||||||
qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed");
|
|
||||||
} else {
|
|
||||||
QFontDef def;
|
|
||||||
def.pixelSize = pixelSize;
|
|
||||||
def.pointSize = pixelSize * 72.0 / qt_defaultDpi();
|
|
||||||
fontEngine = new QCoreTextFontEngine(cgFont, def);
|
|
||||||
CFRelease(cgFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fontEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFont::StyleHint styleHintFromNSString(NSString *style)
|
|
||||||
{
|
|
||||||
if ([style isEqual: @"sans-serif"])
|
|
||||||
return QFont::SansSerif;
|
|
||||||
else if ([style isEqual: @"monospace"])
|
|
||||||
return QFont::Monospace;
|
|
||||||
else if ([style isEqual: @"cursive"])
|
|
||||||
return QFont::Cursive;
|
|
||||||
else if ([style isEqual: @"serif"])
|
|
||||||
return QFont::Serif;
|
|
||||||
else if ([style isEqual: @"fantasy"])
|
|
||||||
return QFont::Fantasy;
|
|
||||||
else // if ([style isEqual: @"default"])
|
|
||||||
return QFont::AnyStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_OS_OSX
|
|
||||||
static QString familyNameFromPostScriptName(NSString *psName)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
|
||||||
Q_UNUSED(style);
|
|
||||||
Q_UNUSED(script);
|
|
||||||
|
|
||||||
QMacAutoReleasePool pool;
|
|
||||||
|
|
||||||
static QHash<QString, QStringList> fallbackLists;
|
|
||||||
|
|
||||||
if (!family.isEmpty()) {
|
|
||||||
#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_8, __IPHONE_6_0)
|
|
||||||
// CTFontCopyDefaultCascadeListForLanguages is available in the SDK
|
|
||||||
#if QT_MAC_DEPLOYMENT_TARGET_BELOW(__MAC_10_8, __IPHONE_6_0)
|
|
||||||
// But we have to feature check at runtime
|
|
||||||
if (&CTFontCopyDefaultCascadeListForLanguages)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(Q_OS_OSX)
|
|
||||||
// Since we are only returning a list of default fonts for the current language, we do not
|
|
||||||
// cover all unicode completely. This was especially an issue for some of the common script
|
|
||||||
// symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk
|
|
||||||
// of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most
|
|
||||||
// of Unicode 2.1.
|
|
||||||
if (!fallbackList.contains(QStringLiteral("Arial Unicode MS")))
|
|
||||||
fallbackList.append(QStringLiteral("Arial Unicode MS"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return fallbackList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// We were not able to find a fallback for the specific family,
|
|
||||||
// so we fall back to the stylehint.
|
|
||||||
|
|
||||||
static const QString styleLookupKey = QString::fromLatin1(".QFontStyleHint_%1");
|
|
||||||
|
|
||||||
static bool didPopulateStyleFallbacks = false;
|
|
||||||
if (!didPopulateStyleFallbacks) {
|
|
||||||
#if defined(Q_OS_MACX)
|
|
||||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
||||||
NSArray *languages = [defaults stringArrayForKey: @"AppleLanguages"];
|
|
||||||
|
|
||||||
NSDictionary *fallbackDict = [NSDictionary dictionaryWithContentsOfFile: @"/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreText.framework/Resources/DefaultFontFallbacks.plist"];
|
|
||||||
|
|
||||||
for (NSString *style in [fallbackDict allKeys]) {
|
|
||||||
NSArray *list = [fallbackDict valueForKey: style];
|
|
||||||
QFont::StyleHint fallbackStyleHint = styleHintFromNSString(style);
|
|
||||||
QStringList fallbackList;
|
|
||||||
for (id item in list) {
|
|
||||||
// sort the array based on system language preferences
|
|
||||||
if ([item isKindOfClass: [NSArray class]]) {
|
|
||||||
NSArray *langs = [(NSArray *) item sortedArrayUsingFunction: languageMapSort
|
|
||||||
context: languages];
|
|
||||||
for (NSArray *map in langs)
|
|
||||||
fallbackList.append(familyNameFromPostScriptName([map objectAtIndex: 1]));
|
|
||||||
}
|
|
||||||
else if ([item isKindOfClass: [NSString class]])
|
|
||||||
fallbackList.append(familyNameFromPostScriptName(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
fallbackList.append(QLatin1String("Apple Color Emoji"));
|
|
||||||
|
|
||||||
// Since we are only returning a list of default fonts for the current language, we do not
|
|
||||||
// cover all unicode completely. This was especially an issue for some of the common script
|
|
||||||
// symbols such as mathematical symbols, currency or geometric shapes. To minimize the risk
|
|
||||||
// of missing glyphs, we add Arial Unicode MS as a final fail safe, since this covers most
|
|
||||||
// of Unicode 2.1.
|
|
||||||
if (!fallbackList.contains(QStringLiteral("Arial Unicode MS")))
|
|
||||||
fallbackList.append(QStringLiteral("Arial Unicode MS"));
|
|
||||||
|
|
||||||
fallbackLists[styleLookupKey.arg(fallbackStyleHint)] = fallbackList;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
QStringList staticFallbackList;
|
#include "coretext_fontdatabase-old.mm"
|
||||||
staticFallbackList << QString::fromLatin1("Helvetica,Apple Color Emoji,Geeza Pro,Arial Hebrew,Thonburi,Kailasa"
|
|
||||||
"Hiragino Kaku Gothic ProN,.Heiti J,Apple SD Gothic Neo,.Heiti K,Heiti SC,Heiti TC"
|
|
||||||
"Bangla Sangam MN,Devanagari Sangam MN,Gujarati Sangam MN,Gurmukhi MN,Kannada Sangam MN"
|
|
||||||
"Malayalam Sangam MN,Oriya Sangam MN,Sinhala Sangam MN,Tamil Sangam MN,Telugu Sangam MN"
|
|
||||||
"Euphemia UCAS,.PhoneFallback").split(QLatin1String(","));
|
|
||||||
|
|
||||||
for (int i = QFont::Helvetica; i <= QFont::Fantasy; ++i)
|
|
||||||
fallbackLists[styleLookupKey.arg(i)] = staticFallbackList;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
didPopulateStyleFallbacks = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_ASSERT(!fallbackLists.isEmpty());
|
|
||||||
return fallbackLists[styleLookupKey.arg(styleHint)];
|
|
||||||
}
|
|
||||||
|
|
||||||
#if HAVE_CORETEXT
|
|
||||||
static CFArrayRef createDescriptorArrayForFont(CTFontRef font, const QString &fileName = QString())
|
|
||||||
{
|
|
||||||
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
|
||||||
QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font);
|
|
||||||
|
|
||||||
Q_UNUSED(fileName)
|
|
||||||
#ifndef QT_NO_FREETYPE
|
|
||||||
// The physical font source URL (usually a local file or Qt resource) is only required for
|
|
||||||
// FreeType, when using non-system fonts, and needs some hackery to attach in a format
|
|
||||||
// agreeable to OSX.
|
|
||||||
if (!fileName.isEmpty()) {
|
|
||||||
QCFType<CFURLRef> fontURL;
|
|
||||||
|
|
||||||
if (fileName.startsWith(QLatin1String(":/"))) {
|
|
||||||
// QUrl::fromLocalFile() doesn't accept qrc pseudo-paths like ":/fonts/myfont.ttf".
|
|
||||||
// Therefore construct from QString with the qrc:// scheme -> "qrc:///fonts/myfont.ttf".
|
|
||||||
fontURL = QUrl(QStringLiteral("qrc://") + fileName.mid(1)).toCFURL();
|
|
||||||
} else if (!fileName.isEmpty()) {
|
|
||||||
// At this point we hope that filename is in a format that QUrl can handle.
|
|
||||||
fontURL = QUrl::fromLocalFile(fileName).toCFURL();
|
|
||||||
}
|
|
||||||
|
|
||||||
QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 1,
|
|
||||||
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
||||||
CFDictionaryAddValue(attributes, kCTFontURLAttribute, fontURL);
|
|
||||||
descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, attributes);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CFArrayAppendValue(array, descriptor);
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider);
|
|
||||||
if (cgFont) {
|
|
||||||
if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) {
|
|
||||||
QCFType<CTFontRef> font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL);
|
|
||||||
fonts = createDescriptorArrayForFont(font
|
|
||||||
#ifndef QT_NO_FREETYPE
|
|
||||||
, m_useFreeType ? fileName : QString()
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
m_applicationFonts.append(QVariant::fromValue(QCFType<CGFontRef>::constructFromGet(cgFont)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QCFType<CFURLRef> fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false);
|
|
||||||
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 (error) {
|
|
||||||
NSLog(@"Unable to register font: %@", error);
|
|
||||||
CFRelease(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if HAVE_CORETEXT && HAVE_ATS
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
#if HAVE_ATS
|
|
||||||
{
|
|
||||||
ATSFontContainerRef fontContainer;
|
|
||||||
OSStatus e;
|
|
||||||
|
|
||||||
if (!fontData.isEmpty()) {
|
|
||||||
e = ATSFontActivateFromMemory((void *) fontData.constData(), fontData.size(),
|
|
||||||
kATSFontContextLocal, kATSFontFormatUnspecified, NULL,
|
|
||||||
kATSOptionFlagsDefault, &fontContainer);
|
|
||||||
} else {
|
|
||||||
FSRef ref;
|
|
||||||
if (FSPathMakeRef(reinterpret_cast<const UInt8 *>(fileName.toUtf8().constData()),
|
|
||||||
&ref, 0) != 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();
|
|
||||||
|
|
||||||
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 families;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QCoreTextFontDatabase::isPrivateFontFamily(const QString &family) const
|
|
||||||
{
|
|
||||||
if (family.startsWith(QLatin1Char('.')))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return QPlatformFontDatabase::isPrivateFontFamily(family);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f)
|
|
||||||
{
|
|
||||||
switch (f) {
|
|
||||||
case QPlatformTheme::SystemFont:
|
|
||||||
return kCTFontUIFontSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::MenuFont:
|
|
||||||
case QPlatformTheme::MenuBarFont:
|
|
||||||
case QPlatformTheme::MenuItemFont:
|
|
||||||
return kCTFontUIFontMenuItem;
|
|
||||||
|
|
||||||
case QPlatformTheme::MessageBoxFont:
|
|
||||||
return kCTFontUIFontEmphasizedSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::LabelFont:
|
|
||||||
return kCTFontUIFontSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::TipLabelFont:
|
|
||||||
return kCTFontToolTipFontType;
|
|
||||||
|
|
||||||
case QPlatformTheme::StatusBarFont:
|
|
||||||
return kCTFontUIFontSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::TitleBarFont:
|
|
||||||
return kCTFontUIFontWindowTitle;
|
|
||||||
|
|
||||||
case QPlatformTheme::MdiSubWindowTitleFont:
|
|
||||||
case QPlatformTheme::DockWidgetTitleFont:
|
|
||||||
return kCTFontUIFontSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::PushButtonFont:
|
|
||||||
return kCTFontUIFontPushButton;
|
|
||||||
|
|
||||||
case QPlatformTheme::CheckBoxFont:
|
|
||||||
case QPlatformTheme::RadioButtonFont:
|
|
||||||
return kCTFontUIFontSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::ToolButtonFont:
|
|
||||||
return kCTFontUIFontSmallToolbar;
|
|
||||||
|
|
||||||
case QPlatformTheme::ItemViewFont:
|
|
||||||
return kCTFontUIFontSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::ListViewFont:
|
|
||||||
return kCTFontUIFontViews;
|
|
||||||
|
|
||||||
case QPlatformTheme::HeaderViewFont:
|
|
||||||
return kCTFontUIFontSmallSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::ListBoxFont:
|
|
||||||
return kCTFontUIFontViews;
|
|
||||||
|
|
||||||
case QPlatformTheme::ComboMenuItemFont:
|
|
||||||
return kCTFontUIFontSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::ComboLineEditFont:
|
|
||||||
return kCTFontUIFontViews;
|
|
||||||
|
|
||||||
case QPlatformTheme::SmallFont:
|
|
||||||
return kCTFontUIFontSmallSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::MiniFont:
|
|
||||||
return kCTFontUIFontMiniSystem;
|
|
||||||
|
|
||||||
case QPlatformTheme::FixedFont:
|
|
||||||
return kCTFontUIFontUserFixedPitch;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return kCTFontUIFontSystem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CTFontDescriptorRef fontDescriptorFromTheme(QPlatformTheme::Font f)
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_IOS
|
|
||||||
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_7_0) {
|
|
||||||
// Use Dynamic Type to resolve theme fonts if possible, to get
|
|
||||||
// correct font sizes and style based on user configuration.
|
|
||||||
NSString *textStyle = 0;
|
|
||||||
switch (f) {
|
|
||||||
case QPlatformTheme::TitleBarFont:
|
|
||||||
case QPlatformTheme::HeaderViewFont:
|
|
||||||
textStyle = UIFontTextStyleHeadline;
|
|
||||||
break;
|
|
||||||
case QPlatformTheme::MdiSubWindowTitleFont:
|
|
||||||
textStyle = UIFontTextStyleSubheadline;
|
|
||||||
break;
|
|
||||||
case QPlatformTheme::TipLabelFont:
|
|
||||||
case QPlatformTheme::SmallFont:
|
|
||||||
textStyle = UIFontTextStyleFootnote;
|
|
||||||
break;
|
|
||||||
case QPlatformTheme::MiniFont:
|
|
||||||
textStyle = UIFontTextStyleCaption2;
|
|
||||||
break;
|
|
||||||
case QPlatformTheme::FixedFont:
|
|
||||||
// Fall back to regular code path, as iOS doesn't provide
|
|
||||||
// an appropriate text style for this theme font.
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
textStyle = UIFontTextStyleBody;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (textStyle) {
|
|
||||||
UIFontDescriptor *desc = [UIFontDescriptor preferredFontDescriptorWithTextStyle:textStyle];
|
|
||||||
return static_cast<CTFontDescriptorRef>(CFBridgingRetain(desc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // Q_OS_IOS
|
|
||||||
|
|
||||||
// OSX default case and iOS fallback case
|
|
||||||
CTFontUIFontType fontType = fontTypeFromTheme(f);
|
|
||||||
QCFType<CTFontRef> ctFont = CTFontCreateUIFontForLanguage(fontType, 0.0, NULL);
|
|
||||||
return CTFontCopyFontDescriptor(ctFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QHash<QPlatformTheme::Font, QFont *> &QCoreTextFontDatabase::themeFonts() const
|
|
||||||
{
|
|
||||||
if (m_themeFonts.isEmpty()) {
|
|
||||||
for (long f = QPlatformTheme::SystemFont; f < QPlatformTheme::NFonts; f++) {
|
|
||||||
QPlatformTheme::Font ft = static_cast<QPlatformTheme::Font>(f);
|
|
||||||
m_themeFonts.insert(ft, themeFont(ft));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_themeFonts;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const
|
|
||||||
{
|
|
||||||
CTFontDescriptorRef fontDesc = fontDescriptorFromTheme(f);
|
|
||||||
FontDescription fd;
|
|
||||||
getFontDescription(fontDesc, &fd);
|
|
||||||
|
|
||||||
if (!m_systemFontDescriptors.contains(fontDesc))
|
|
||||||
m_systemFontDescriptors.insert(fontDesc);
|
|
||||||
else
|
|
||||||
CFRelease(fontDesc);
|
|
||||||
|
|
||||||
QFont *font = new QFont(fd.familyName, fd.pixelSize, fd.weight, fd.style == QFont::StyleItalic);
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFont QCoreTextFontDatabase::defaultFont() const
|
|
||||||
{
|
|
||||||
if (defaultFontName.isEmpty()) {
|
|
||||||
QCFType<CTFontRef> font = CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, 12.0, NULL);
|
|
||||||
defaultFontName = (QString) QCFString(CTFontCopyFullName(font));
|
|
||||||
}
|
|
||||||
|
|
||||||
return QFont(defaultFontName);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QCoreTextFontDatabase::fontsAlwaysScalable() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<int> QCoreTextFontDatabase::standardSizes() const
|
|
||||||
{
|
|
||||||
QList<int> ret;
|
|
||||||
static const unsigned short standard[] =
|
|
||||||
{ 9, 10, 11, 12, 13, 14, 18, 24, 36, 48, 64, 72, 96, 144, 288, 0 };
|
|
||||||
ret.reserve(int(sizeof(standard) / sizeof(standard[0])));
|
|
||||||
const unsigned short *sizes = standard;
|
|
||||||
while (*sizes) ret << *sizes++;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QCoreTextFontDatabase::removeApplicationFonts()
|
|
||||||
{
|
|
||||||
if (m_applicationFonts.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
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
|
|
||||||
#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
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef QT_NO_FREETYPE
|
|
||||||
QFontEngine *QCoreTextFontDatabase::freeTypeFontEngine(const QFontDef &fontDef, const QByteArray &filename,
|
|
||||||
const QByteArray &fontData)
|
|
||||||
{
|
|
||||||
QFontEngine::FaceId faceId;
|
|
||||||
faceId.filename = filename;
|
|
||||||
const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
|
|
||||||
|
|
||||||
QScopedPointer<QFontEngineFT> engine(new QFontEngineFT(fontDef));
|
|
||||||
QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono;
|
|
||||||
if (antialias) {
|
|
||||||
QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint();
|
|
||||||
if (subpixelType == QFontEngine::Subpixel_None || (fontDef.styleStrategy & QFont::NoSubpixelAntialias)) {
|
|
||||||
format = QFontEngineFT::Format_A8;
|
|
||||||
engine->subpixelType = QFontEngine::Subpixel_None;
|
|
||||||
} else {
|
|
||||||
format = QFontEngineFT::Format_A32;
|
|
||||||
engine->subpixelType = subpixelType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) {
|
|
||||||
qWarning() << "QCoreTextFontDatabase::freeTypefontEngine Failed to create engine";
|
|
||||||
return Q_NULLPTR;
|
|
||||||
}
|
|
||||||
engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
|
|
||||||
|
|
||||||
return engine.take();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
|
@ -2,7 +2,11 @@
|
|||||||
#include "headless_integration.h"
|
#include "headless_integration.h"
|
||||||
#include "headless_backingstore.h"
|
#include "headless_backingstore.h"
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
|
||||||
|
#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
|
||||||
|
#else
|
||||||
#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
|
#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
|
||||||
|
#endif
|
||||||
#include <qpa/qplatformservices.h>
|
#include <qpa/qplatformservices.h>
|
||||||
#include <QtCore/private/qeventdispatcher_unix_p.h>
|
#include <QtCore/private/qeventdispatcher_unix_p.h>
|
||||||
#else
|
#else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user