diff --git a/src/calibre/headless/fontconfig_database.cpp b/src/calibre/headless/fontconfig_database.cpp index a3730733d9..4e87b8f81b 100644 --- a/src/calibre/headless/fontconfig_database.cpp +++ b/src/calibre/headless/fontconfig_database.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** 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:LGPL21$ +** $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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** 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 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. +** 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. ** -** 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. +** 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$ ** @@ -70,12 +76,6 @@ static inline int mapToQtWeightForRange(int fcweight, int fcLower, int fcUpper, } #endif -static inline bool requiresOpenType(int writingSystem) -{ - return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala) - || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko); -} - static inline int weightFromFcWeight(int fcweight) { // Font Config uses weights from 0 to 215 (the highest enum value) while QFont ranges from @@ -146,7 +146,7 @@ static inline int stretchFromFcWidth(int fcwidth) return qtstretch; } -static const char *specialLanguages[] = { +static const char specialLanguages[][6] = { "", // Unknown "", // Inherited "", // Common @@ -289,12 +289,12 @@ static const char *specialLanguages[] = { #endif // Qt >= 5.5.0 }; -Q_STATIC_ASSERT(sizeof(specialLanguages) / sizeof(const char *) == QChar::ScriptCount); +Q_STATIC_ASSERT(sizeof specialLanguages / sizeof *specialLanguages == QChar::ScriptCount); // 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 +static const char languageForWritingSystem[][6] = { + "", // Any "en", // Latin "el", // Greek "ru", // Cyrillic @@ -324,25 +324,25 @@ static const char *languageForWritingSystem[] = { "ja", // Japanese "ko", // Korean "vi", // Vietnamese - 0, // Symbol + "", // Symbol "sga", // Ogham "non", // Runic "man" // N'Ko }; -Q_STATIC_ASSERT(sizeof(languageForWritingSystem) / sizeof(const char *) == QFontDatabase::WritingSystemsCount); +Q_STATIC_ASSERT(sizeof languageForWritingSystem / sizeof *languageForWritingSystem == QFontDatabase::WritingSystemsCount); #if FC_VERSION >= 20297 -// Newer FontConfig let's us sort out fonts that contain certain glyphs, but no -// open type tables for is directly. Do this so we don't pick some strange -// pseudo unicode font -static const char *openType[] = { - 0, // Any - 0, // Latin - 0, // Greek - 0, // Cyrillic - 0, // Armenian - 0, // Hebrew - 0, // Arabic +// Newer FontConfig let's us sort out fonts that report certain scripts support, +// but no open type tables for handling them correctly. +// Check the reported script presence in the FC_CAPABILITY's "otlayout:" section. +static const char capabilityForWritingSystem[][5] = { + "", // Any + "", // Latin + "", // Greek + "", // Cyrillic + "", // Armenian + "", // Hebrew + "", // Arabic "syrc", // Syriac "thaa", // Thaana "deva", // Devanagari @@ -359,23 +359,23 @@ static const char *openType[] = { "knda", // Kannada "mlym", // Malayalam "sinh", // Sinhala - 0, // Thai - 0, // Lao + "", // Thai + "", // Lao "tibt", // Tibetan "mymr", // Myanmar - 0, // Georgian + "", // Georgian "khmr", // Khmer - 0, // SimplifiedChinese - 0, // TraditionalChinese - 0, // Japanese - 0, // Korean - 0, // Vietnamese - 0, // Symbol - 0, // Ogham - 0, // Runic + "", // SimplifiedChinese + "", // TraditionalChinese + "", // Japanese + "", // Korean + "", // Vietnamese + "", // Symbol + "", // Ogham + "", // Runic "nko " // N'Ko }; -Q_STATIC_ASSERT(sizeof(openType) / sizeof(const char *) == QFontDatabase::WritingSystemsCount); +Q_STATIC_ASSERT(sizeof(capabilityForWritingSystem) / sizeof(*capabilityForWritingSystem) == QFontDatabase::WritingSystemsCount); #endif static const char *getFcFamilyForStyleHint(const QFont::StyleHint style) @@ -404,9 +404,18 @@ static const char *getFcFamilyForStyleHint(const QFont::StyleHint style) return stylehint; } +static inline bool requiresOpenType(int writingSystem) +{ + return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala) + || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko); +} + static void populateFromPattern(FcPattern *pattern) { QString familyName; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) + QString familyNameLang; +#endif FcChar8 *value = 0; int weight_value; int slant_value; @@ -423,7 +432,10 @@ static void populateFromPattern(FcPattern *pattern) return; familyName = QString::fromUtf8((const char *)value); - +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) + if (FcPatternGetString(pattern, FC_FAMILYLANG, 0, &value) == FcResultMatch) + familyNameLang = QString::fromUtf8((const char *)value); +#endif slant_value = FC_SLANT_ROMAN; weight_value = FC_WEIGHT_REGULAR; spacing_value = FC_PROPORTIONAL; @@ -458,11 +470,23 @@ static void populateFromPattern(FcPattern *pattern) FcResult res = FcPatternGetLangSet(pattern, FC_LANG, 0, &langset); if (res == FcResultMatch) { bool hasLang = false; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) && FC_VERSION >= 20297 + FcChar8 *cap = Q_NULLPTR; + FcResult capRes = FcResultNoMatch; +#endif for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j]; if (lang) { FcLangResult langRes = FcLangSetHasLang(langset, lang); if (langRes != FcLangDifferentLang) { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) && FC_VERSION >= 20297 + if (*capabilityForWritingSystem[j] && requiresOpenType(j)) { + if (cap == Q_NULLPTR) + capRes = FcPatternGetString(pattern, FC_CAPABILITY, 0, &cap); + if (capRes == FcResultMatch && strstr(reinterpret_cast(cap), capabilityForWritingSystem[j]) == 0) + continue; + } +#endif writingSystems.setSupported(QFontDatabase::WritingSystem(j)); hasLang = true; } @@ -478,13 +502,13 @@ static void populateFromPattern(FcPattern *pattern) writingSystems.setSupported(QFontDatabase::Other); } -#if FC_VERSION >= 20297 +#if (QT_VERSION < QT_VERSION_CHECK(5, 8, 0)) && FC_VERSION >= 20297 for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { if (writingSystems.supported(QFontDatabase::WritingSystem(j)) - && requiresOpenType(j) && openType[j]) { + && requiresOpenType(j) && capabilityForWritingSystem[j]) { FcChar8 *cap; res = FcPatternGetString (pattern, FC_CAPABILITY, 0, &cap); - if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) + if (res != FcResultMatch || !strstr((const char *)cap, capabilityForWritingSystem[j])) writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); } } @@ -513,14 +537,45 @@ static void populateFromPattern(FcPattern *pattern) QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile); // qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) + for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k) { + const QString altFamilyName = QString::fromUtf8((const char *)value); + // Extra family names can be aliases or subfamilies. + // If it is a subfamily, register it as a separate font, so only members of the subfamily are + // matched when the subfamily is requested. + QString altStyleName; + if (FcPatternGetString(pattern, FC_STYLE, k, &value) == FcResultMatch) + altStyleName = QString::fromUtf8((const char *)value); + else + altStyleName = styleName; + + QString altFamilyNameLang; + if (FcPatternGetString(pattern, FC_FAMILYLANG, k, &value) == FcResultMatch) + altFamilyNameLang = QString::fromUtf8((const char *)value); + else + altFamilyNameLang = familyNameLang; + + if (familyNameLang == altFamilyNameLang && altStyleName != styleName) { + FontFile *altFontFile = new FontFile(*fontFile); + QPlatformFontDatabase::registerFont(altFamilyName, altStyleName, QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,altFontFile); + } else { + QPlatformFontDatabase::registerAliasToFontFamily(familyName, altFamilyName); + } + } +#else for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k) QPlatformFontDatabase::registerAliasToFontFamily(familyName, QString::fromUtf8((const char *)value)); +#endif } void QFontconfigDatabase::populateFontDatabase() { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) + FcInit(); +#else FcInitReinitialize(); +#endif FcFontSet *fonts; { @@ -531,6 +586,9 @@ void QFontconfigDatabase::populateFontDatabase() FC_SPACING, FC_FILE, FC_INDEX, FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WIDTH, +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) + FC_FAMILYLANG, +#endif #if FC_VERSION >= 20297 FC_CAPABILITY, #endif @@ -584,6 +642,14 @@ void QFontconfigDatabase::populateFontDatabase() // QApplication::setFont(font); } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) +void QFontconfigDatabase::invalidate() +{ + // Clear app fonts. + FcConfigAppFontClear(0); +} +#endif + QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) { return new QFontEngineMultiFontConfig(fontEngine, script); diff --git a/src/calibre/headless/fontconfig_database.h b/src/calibre/headless/fontconfig_database.h index d4eadbca51..e2fecff724 100644 --- a/src/calibre/headless/fontconfig_database.h +++ b/src/calibre/headless/fontconfig_database.h @@ -22,6 +22,9 @@ class QFontconfigDatabase : public QBasicFontDatabase public: #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) void populateFontDatabase() Q_DECL_OVERRIDE; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) + void invalidate() Q_DECL_OVERRIDE; +#endif QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) Q_DECL_OVERRIDE; QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) Q_DECL_OVERRIDE; QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) Q_DECL_OVERRIDE; diff --git a/src/calibre/test_build.py b/src/calibre/test_build.py index 6a8ac274d9..f11c08b269 100644 --- a/src/calibre/test_build.py +++ b/src/calibre/test_build.py @@ -138,6 +138,9 @@ class BuildTest(unittest.TestCase): os.environ.pop('DISPLAY', None) app = Application([], headless=islinux) self.assertGreaterEqual(len(QFontDatabase().families()), 5, 'The QPA headless plugin is not able to locate enough system fonts via fontconfig') + if islinux: + from calibre.ebooks.covers import create_cover + create_cover('xxx', ['yyy']) na = QNetworkAccessManager() self.assertTrue(hasattr(na, 'sslErrors'), 'Qt not compiled with openssl') from PyQt5.QtWebKitWidgets import QWebView