Fix crash when generating covers with Qt 5.8 on linux

This commit is contained in:
Kovid Goyal 2017-01-30 22:16:38 +05:30
parent 73e9043976
commit 4e5287e923
3 changed files with 125 additions and 53 deletions

View File

@ -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<const char *>(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);

View File

@ -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;

View File

@ -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