diff options
Diffstat (limited to 'src/platformsupport/fontdatabases')
9 files changed, 1300 insertions, 0 deletions
diff --git a/src/platformsupport/fontdatabases/basicunix/basicunix.pri b/src/platformsupport/fontdatabases/basicunix/basicunix.pri new file mode 100644 index 0000000000..f83b89063b --- /dev/null +++ b/src/platformsupport/fontdatabases/basicunix/basicunix.pri @@ -0,0 +1,84 @@ +DEFINES += QT_NO_FONTCONFIG +QT += gui-private core-private + +HEADERS += \ + $$PWD/qbasicunixfontdatabase_p.h \ + $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft_p.h + +SOURCES += \ + $$PWD/qbasicunixfontdatabase.cpp \ + $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft.cpp + +CONFIG += opentype + +contains(QT_CONFIG, freetype) { + QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype + SOURCES += \ + $$QT_FREETYPE_DIR/src/base/ftbase.c \ + $$QT_FREETYPE_DIR/src/base/ftbbox.c \ + $$QT_FREETYPE_DIR/src/base/ftdebug.c \ + $$QT_FREETYPE_DIR/src/base/ftglyph.c \ + $$QT_FREETYPE_DIR/src/base/ftinit.c \ + $$QT_FREETYPE_DIR/src/base/ftmm.c \ + $$QT_FREETYPE_DIR/src/base/fttype1.c \ + $$QT_FREETYPE_DIR/src/base/ftsynth.c \ + $$QT_FREETYPE_DIR/src/base/ftbitmap.c \ + $$QT_FREETYPE_DIR/src/bdf/bdf.c \ + $$QT_FREETYPE_DIR/src/cache/ftcache.c \ + $$QT_FREETYPE_DIR/src/cff/cff.c \ + $$QT_FREETYPE_DIR/src/cid/type1cid.c \ + $$QT_FREETYPE_DIR/src/gzip/ftgzip.c \ + $$QT_FREETYPE_DIR/src/pcf/pcf.c \ + $$QT_FREETYPE_DIR/src/pfr/pfr.c \ + $$QT_FREETYPE_DIR/src/psaux/psaux.c \ + $$QT_FREETYPE_DIR/src/pshinter/pshinter.c \ + $$QT_FREETYPE_DIR/src/psnames/psmodule.c \ + $$QT_FREETYPE_DIR/src/raster/raster.c \ + $$QT_FREETYPE_DIR/src/sfnt/sfnt.c \ + $$QT_FREETYPE_DIR/src/smooth/smooth.c \ + $$QT_FREETYPE_DIR/src/truetype/truetype.c \ + $$QT_FREETYPE_DIR/src/type1/type1.c \ + $$QT_FREETYPE_DIR/src/type42/type42.c \ + $$QT_FREETYPE_DIR/src/winfonts/winfnt.c \ + $$QT_FREETYPE_DIR/src/lzw/ftlzw.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvalid.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvbase.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvgdef.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvjstf.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvcommn.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvgpos.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvgsub.c\ + $$QT_FREETYPE_DIR/src/otvalid/otvmod.c\ + $$QT_FREETYPE_DIR/src/autofit/afangles.c\ + $$QT_FREETYPE_DIR/src/autofit/afglobal.c\ + $$QT_FREETYPE_DIR/src/autofit/aflatin.c\ + $$QT_FREETYPE_DIR/src/autofit/afmodule.c\ + $$QT_FREETYPE_DIR/src/autofit/afdummy.c\ + $$QT_FREETYPE_DIR/src/autofit/afhints.c\ + $$QT_FREETYPE_DIR/src/autofit/afloader.c\ + $$QT_FREETYPE_DIR/src/autofit/autofit.c + + symbian { + SOURCES += \ + $$QT_FREETYPE_DIR/src/base/ftsystem.c + } else { + SOURCES += \ + $$QT_FREETYPE_DIR/builds/unix/ftsystem.c + INCLUDEPATH += \ + $$QT_FREETYPE_DIR/builds/unix + } + + INCLUDEPATH += \ + $$QT_FREETYPE_DIR/src \ + $$QT_FREETYPE_DIR/include + + DEFINES += FT2_BUILD_LIBRARY + contains(QT_CONFIG, system-zlib) { + DEFINES += FT_CONFIG_OPTION_SYSTEM_ZLIB + } + +} else:contains(QT_CONFIG, system-freetype) { + # pull in the proper freetype2 include directory + include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri) +} + diff --git a/src/platformsupport/fontdatabases/basicunix/qbasicunixfontdatabase.cpp b/src/platformsupport/fontdatabases/basicunix/qbasicunixfontdatabase.cpp new file mode 100644 index 0000000000..8012f84797 --- /dev/null +++ b/src/platformsupport/fontdatabases/basicunix/qbasicunixfontdatabase.cpp @@ -0,0 +1,422 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qbasicunixfontdatabase_p.h" + +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/QPlatformScreen> + +#include <QtCore/QFile> +#include <QtCore/QLibraryInfo> +#include <QtCore/QDir> +#include <QtCore/QUuid> + +#undef QT_NO_FREETYPE +#include <QtGui/private/qfontengine_ft_p.h> +#include <QtGui/private/qfontengine_p.h> + +#include <ft2build.h> +#include FT_TRUETYPE_TABLES_H + +#define SimplifiedChineseCsbBit 18 +#define TraditionalChineseCsbBit 20 +#define JapaneseCsbBit 17 +#define KoreanCsbBit 21 + +static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { + // Any, + { 127, 127 }, + // Latin, + { 0, 127 }, + // Greek, + { 7, 127 }, + // Cyrillic, + { 9, 127 }, + // Armenian, + { 10, 127 }, + // Hebrew, + { 11, 127 }, + // Arabic, + { 13, 127 }, + // Syriac, + { 71, 127 }, + //Thaana, + { 72, 127 }, + //Devanagari, + { 15, 127 }, + //Bengali, + { 16, 127 }, + //Gurmukhi, + { 17, 127 }, + //Gujarati, + { 18, 127 }, + //Oriya, + { 19, 127 }, + //Tamil, + { 20, 127 }, + //Telugu, + { 21, 127 }, + //Kannada, + { 22, 127 }, + //Malayalam, + { 23, 127 }, + //Sinhala, + { 73, 127 }, + //Thai, + { 24, 127 }, + //Lao, + { 25, 127 }, + //Tibetan, + { 70, 127 }, + //Myanmar, + { 74, 127 }, + // Georgian, + { 26, 127 }, + // Khmer, + { 80, 127 }, + // SimplifiedChinese, + { 126, 127 }, + // TraditionalChinese, + { 126, 127 }, + // Japanese, + { 126, 127 }, + // Korean, + { 56, 127 }, + // Vietnamese, + { 0, 127 }, // same as latin1 + // Other, + { 126, 127 }, + // Ogham, + { 78, 127 }, + // Runic, + { 79, 127 }, + // Nko, + { 14, 127 }, +}; + +static QSupportedWritingSystems determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]) +{ + QSupportedWritingSystems writingSystems; + bool hasScript = false; + + int i; + for(i = 0; i < QFontDatabase::WritingSystemsCount; i++) { + int bit = requiredUnicodeBits[i][0]; + int index = bit/32; + int flag = 1 << (bit&31); + if (bit != 126 && unicodeRange[index] & flag) { + bit = requiredUnicodeBits[i][1]; + index = bit/32; + + flag = 1 << (bit&31); + if (bit == 127 || unicodeRange[index] & flag) { + writingSystems.setSupported(QFontDatabase::WritingSystem(i)); + hasScript = true; + // qDebug("font %s: index=%d, flag=%8x supports script %d", familyName.latin1(), index, flag, i); + } + } + } + if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) { + writingSystems.setSupported(QFontDatabase::SimplifiedChinese); + hasScript = true; + //qDebug("font %s supports Simplified Chinese", familyName.latin1()); + } + if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) { + writingSystems.setSupported(QFontDatabase::TraditionalChinese); + hasScript = true; + //qDebug("font %s supports Traditional Chinese", familyName.latin1()); + } + if(codePageRange[0] & (1 << JapaneseCsbBit)) { + writingSystems.setSupported(QFontDatabase::Japanese); + hasScript = true; + //qDebug("font %s supports Japanese", familyName.latin1()); + } + if(codePageRange[0] & (1 << KoreanCsbBit)) { + writingSystems.setSupported(QFontDatabase::Korean); + hasScript = true; + //qDebug("font %s supports Korean", familyName.latin1()); + } + if (!hasScript) + writingSystems.setSupported(QFontDatabase::Symbol); + + return writingSystems; +} + +static inline bool scriptRequiresOpenType(int script) +{ + return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) + || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); +} + +void QBasicUnixFontDatabase::populateFontDatabase() +{ + QPlatformFontDatabase::populateFontDatabase(); + QString fontpath = fontDir(); + + if(!QFile::exists(fontpath)) { + qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?", + qPrintable(fontpath)); + } + + QDir dir(fontpath); + dir.setNameFilters(QStringList() << QLatin1String("*.ttf") + << QLatin1String("*.ttc") << QLatin1String("*.pfa") + << QLatin1String("*.pfb")); + dir.refresh(); + for (int i = 0; i < int(dir.count()); ++i) { + const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i])); +// qDebug() << "looking at" << file; + addTTFile(QByteArray(), file); + } +} + +QFontEngine *QBasicUnixFontDatabase::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *usrPtr) +{ + QFontEngineFT *engine; + FontFile *fontfile = static_cast<FontFile *> (usrPtr); + QFontEngine::FaceId fid; + fid.filename = fontfile->fileName.toLocal8Bit(); + fid.index = fontfile->indexValue; + engine = new QFontEngineFT(fontDef); + + bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); + QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; + if (!engine->init(fid,antialias,format)) { + delete engine; + engine = 0; + return engine; + } + if (engine->invalid()) { + delete engine; + engine = 0; + } else if (scriptRequiresOpenType(script)) { + HB_Face hbFace = engine->harfbuzzFace(); + if (!hbFace || !hbFace->supported_scripts[script]) { + delete engine; + engine = 0; + } + } + + return engine; +} + +namespace { + + class QFontEngineFTRawData: public QFontEngineFT + { + public: + QFontEngineFTRawData(const QFontDef &fontDef) : QFontEngineFT(fontDef) + { + } + + void updateFamilyNameAndStyle() + { + fontDef.family = QString::fromAscii(freetype->face->family_name); + + if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC) + fontDef.style = QFont::StyleItalic; + + if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD) + fontDef.weight = QFont::Bold; + } + + bool initFromData(const QByteArray &fontData) + { + FaceId faceId; + faceId.filename = ""; + faceId.index = 0; + faceId.uuid = QUuid::createUuid().toByteArray(); + + return init(faceId, true, Format_None, fontData); + } + }; + +} + +QFontEngine *QBasicUnixFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, + QFont::HintingPreference hintingPreference) +{ + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + + QFontEngineFTRawData *fe = new QFontEngineFTRawData(fontDef); + if (!fe->initFromData(fontData)) { + delete fe; + return 0; + } + + fe->updateFamilyNameAndStyle(); + + switch (hintingPreference) { + case QFont::PreferNoHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintNone); + break; + case QFont::PreferFullHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintFull); + break; + case QFont::PreferVerticalHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintLight); + break; + default: + // Leave it as it is + break; + } + + return fe; +} + +QStringList QBasicUnixFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const +{ + Q_UNUSED(family); + Q_UNUSED(style); + Q_UNUSED(script); + Q_UNUSED(styleHint); + return QStringList(); +} + +QStringList QBasicUnixFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) +{ + return addTTFile(fontData,fileName.toLocal8Bit()); +} + +void QBasicUnixFontDatabase::releaseHandle(void *handle) +{ + FontFile *file = static_cast<FontFile *>(handle); + delete file; +} + +QStringList QBasicUnixFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) +{ + extern FT_Library qt_getFreetype(); + FT_Library library = qt_getFreetype(); + + int index = 0; + int numFaces = 0; + QStringList families; + do { + FT_Face face; + FT_Error error; + if (!fontData.isEmpty()) { + error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); + } else { + error = FT_New_Face(library, file.constData(), index, &face); + } + if (error != FT_Err_Ok) { + qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; + break; + } + numFaces = face->num_faces; + + QFont::Weight weight = QFont::Normal; + + QFont::Style style = QFont::StyleNormal; + if (face->style_flags & FT_STYLE_FLAG_ITALIC) + style = QFont::StyleItalic; + + if (face->style_flags & FT_STYLE_FLAG_BOLD) + weight = QFont::Bold; + + QSupportedWritingSystems writingSystems; + // detect symbol fonts + for (int i = 0; i < face->num_charmaps; ++i) { + FT_CharMap cm = face->charmaps[i]; + if (cm->encoding == ft_encoding_adobe_custom + || cm->encoding == ft_encoding_symbol) { + writingSystems.setSupported(QFontDatabase::Symbol); + break; + } + } + + TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); + if (os2) { + quint32 unicodeRange[4] = { + os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4 + }; + quint32 codePageRange[2] = { + os2->ulCodePageRange1, os2->ulCodePageRange2 + }; + + writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + + if (os2->usWeightClass == 0) + ; + else if (os2->usWeightClass < 350) + weight = QFont::Light; + else if (os2->usWeightClass < 450) + weight = QFont::Normal; + else if (os2->usWeightClass < 650) + weight = QFont::DemiBold; + else if (os2->usWeightClass < 750) + weight = QFont::Bold; + else if (os2->usWeightClass < 1000) + weight = QFont::Black; + + if (os2->panose[2] >= 2) { + int w = os2->panose[2]; + if (w <= 3) + weight = QFont::Light; + else if (w <= 5) + weight = QFont::Normal; + else if (w <= 7) + weight = QFont::DemiBold; + else if (w <= 8) + weight = QFont::Bold; + else if (w <= 10) + weight = QFont::Black; + } + } + + QString family = QString::fromAscii(face->family_name); + FontFile *fontFile = new FontFile; + fontFile->fileName = QString::fromAscii(file); + fontFile->indexValue = index; + + QFont::Stretch stretch = QFont::Unstretched; + + registerFont(family,QString(),weight,style,stretch,true,true,0,writingSystems,fontFile); + + families.append(family); + + FT_Done_Face(face); + ++index; + } while (index < numFaces); + return families; +} diff --git a/src/platformsupport/fontdatabases/basicunix/qbasicunixfontdatabase_p.h b/src/platformsupport/fontdatabases/basicunix/qbasicunixfontdatabase_p.h new file mode 100644 index 0000000000..fa5fce0e20 --- /dev/null +++ b/src/platformsupport/fontdatabases/basicunix/qbasicunixfontdatabase_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBASICUNIXFONTDATABASE_H +#define QBASICUNIXFONTDATABASE_H + +#include <QPlatformFontDatabase> +#include <QtCore/QByteArray> +#include <QtCore/QString> + +struct FontFile +{ + QString fileName; + int indexValue; +}; + +class QBasicUnixFontDatabase : public QPlatformFontDatabase +{ +public: + void populateFontDatabase(); + QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); + QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); + QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const; + QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); + void releaseHandle(void *handle); + + static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file); +}; + +#endif // QBASICUNIXFONTDATABASE_H diff --git a/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri b/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri new file mode 100644 index 0000000000..2efcb4d4dc --- /dev/null +++ b/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri @@ -0,0 +1,2 @@ +HEADERS += $$PWD/qfontconfigdatabase_p.h +SOURCES += $$PWD/qfontconfigdatabase.cpp diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp new file mode 100644 index 0000000000..9726ad8119 --- /dev/null +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -0,0 +1,604 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfontconfigdatabase_p.h" + +#include <QtCore/QList> +#include <QtGui/private/qfont_p.h> + +#include <QtCore/QElapsedTimer> + +#include <QtGui/QPlatformScreen> + +#include <QtGui/private/qfontengine_ft_p.h> +#include <QtGui/private/qfontengine_p.h> + + + +#include <ft2build.h> +#include FT_TRUETYPE_TABLES_H + +#include <fontconfig/fontconfig.h> + +#define SimplifiedChineseCsbBit 18 +#define TraditionalChineseCsbBit 20 +#define JapaneseCsbBit 17 +#define KoreanCsbBit 21 + +static inline bool requiresOpenType(int writingSystem) +{ + return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala) + || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko); +} +static inline bool scriptRequiresOpenType(int script) +{ + return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) + || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); +} + +static int getFCWeight(int fc_weight) +{ + int qtweight = QFont::Black; + if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2) + qtweight = QFont::Light; + else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) + qtweight = QFont::Normal; + else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) + qtweight = QFont::DemiBold; + else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2) + qtweight = QFont::Bold; + + return qtweight; +} + +static const char *specialLanguages[] = { + "en", // Common + "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 + "ko", // Hangul + "", // Ogham + "", // Runic + "km", // Khmer + "" // N'Ko +}; +enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) }; + +static const ushort specialChars[] = { + 0, // English + 0, // Greek + 0, // Cyrillic + 0, // Armenian + 0, // Hebrew + 0, // Arabic + 0, // Syriac + 0, // Thaana + 0, // Devanagari + 0, // Bengali + 0, // Gurmukhi + 0, // Gujarati + 0, // Oriya + 0, // Tamil + 0xc15, // Telugu + 0xc95, // Kannada + 0xd15, // Malayalam + 0xd9a, // Sinhala + 0, // Thai + 0, // Lao + 0, // Tibetan + 0x1000, // Myanmar + 0, // Georgian + 0, // Hangul + 0x1681, // Ogham + 0x16a0, // Runic + 0, // Khmer + 0x7ca // N'Ko +}; +enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) }; + +// 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-cn", // SimplifiedChinese + "zh-tw", // TraditionalChinese + "ja", // Japanese + "ko", // Korean + "vi", // Vietnamese + 0, // Symbol + 0, // Ogham + 0, // Runic + 0 // N'Ko +}; +enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) }; + +// Unfortunately FontConfig doesn't know about some languages. We have to test these through the +// charset. The lists below contain the systems where we need to do this. +static const ushort sampleCharForWritingSystem[] = { + 0, // Any + 0, // Latin + 0, // Greek + 0, // Cyrillic + 0, // Armenian + 0, // Hebrew + 0, // Arabic + 0, // Syriac + 0, // Thaana + 0, // Devanagari + 0, // Bengali + 0, // Gurmukhi + 0, // Gujarati + 0, // Oriya + 0, // Tamil + 0xc15, // Telugu + 0xc95, // Kannada + 0xd15, // Malayalam + 0xd9a, // Sinhala + 0, // Thai + 0, // Lao + 0, // Tibetan + 0x1000, // Myanmar + 0, // Georgian + 0, // Khmer + 0, // SimplifiedChinese + 0, // TraditionalChinese + 0, // Japanese + 0, // Korean + 0, // Vietnamese + 0, // Symbol + 0x1681, // Ogham + 0x16a0, // Runic + 0x7ca // N'Ko +}; +enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) }; + +// 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 + "syrc", // Syriac + "thaa", // Thaana + "deva", // Devanagari + "beng", // Bengali + "guru", // Gurmukhi + "gurj", // Gujarati + "orya", // Oriya + "taml", // Tamil + "telu", // Telugu + "knda", // Kannada + "mlym", // Malayalam + "sinh", // Sinhala + 0, // Thai + 0, // Lao + "tibt", // Tibetan + "mymr", // Myanmar + 0, // Georgian + "khmr", // Khmer + 0, // SimplifiedChinese + 0, // TraditionalChinese + 0, // Japanese + 0, // Korean + 0, // Vietnamese + 0, // Symbol + 0, // Ogham + 0, // Runic + "nko " // N'Ko +}; + +static const char *getFcFamilyForStyleHint(const QFont::StyleHint style) +{ + const char *stylehint = 0; + switch (style) { + case QFont::SansSerif: + stylehint = "sans-serif"; + break; + case QFont::Serif: + stylehint = "serif"; + break; + case QFont::TypeWriter: + stylehint = "monospace"; + break; + default: + break; + } + return stylehint; +} + +void QFontconfigDatabase::populateFontDatabase() +{ + FcFontSet *fonts; + + QString familyName; + FcChar8 *value = 0; + int weight_value; + int slant_value; + int spacing_value; + FcChar8 *file_value; + int indexValue; + FcChar8 *foundry_value; + FcBool scalable; + FcBool antialias; + + { + FcObjectSet *os = FcObjectSetCreate(); + FcPattern *pattern = FcPatternCreate(); + const char *properties [] = { + FC_FAMILY, FC_WEIGHT, FC_SLANT, + FC_SPACING, FC_FILE, FC_INDEX, + FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT, + FC_WIDTH, +#if FC_VERSION >= 20297 + FC_CAPABILITY, +#endif + (const char *)0 + }; + const char **p = properties; + while (*p) { + FcObjectSetAdd(os, *p); + ++p; + } + fonts = FcFontList(0, pattern, os); + FcObjectSetDestroy(os); + FcPatternDestroy(pattern); + } + + for (int i = 0; i < fonts->nfont; i++) { + if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) + continue; + // capitalize(value); + familyName = QString::fromUtf8((const char *)value); + slant_value = FC_SLANT_ROMAN; + weight_value = FC_WEIGHT_MEDIUM; + spacing_value = FC_PROPORTIONAL; + file_value = 0; + indexValue = 0; + scalable = FcTrue; + + + if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch) + slant_value = FC_SLANT_ROMAN; + if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch) + weight_value = FC_WEIGHT_MEDIUM; + if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch) + spacing_value = FC_PROPORTIONAL; + if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch) + file_value = 0; + if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch) + indexValue = 0; + if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch) + scalable = FcTrue; + if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) + foundry_value = 0; + if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch) + antialias = true; + + QSupportedWritingSystems writingSystems; + FcLangSet *langset = 0; + FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset); + if (res == FcResultMatch) { + for (int i = 1; i < LanguageCount; ++i) { + const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i]; + if (lang) { + FcLangResult langRes = FcLangSetHasLang(langset, lang); + if (langRes != FcLangDifferentLang) + writingSystems.setSupported(QFontDatabase::WritingSystem(i)); + } + } + } else { + // we set Other to supported for symbol fonts. It makes no + // sense to merge these with other ones, as they are + // special in a way. + writingSystems.setSupported(QFontDatabase::Other); + } + + FcCharSet *cs = 0; + res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs); + if (res == FcResultMatch) { + // some languages are not supported by FontConfig, we rather check the + // charset to detect these + for (int i = 1; i < SampleCharCount; ++i) { + if (!sampleCharForWritingSystem[i]) + continue; + if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i])) + writingSystems.setSupported(QFontDatabase::WritingSystem(i)); + } + } + +#if FC_VERSION >= 20297 + for (int j = 1; j < LanguageCount; ++j) { + if (writingSystems.supported(QFontDatabase::WritingSystem(j)) + && requiresOpenType(j) && openType[j]) { + FcChar8 *cap; + res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap); + if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) + writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); + } + } +#endif + + FontFile *fontFile = new FontFile; + fontFile->fileName = QLatin1String((const char *)file_value); + fontFile->indexValue = indexValue; + + QFont::Style style = (slant_value == FC_SLANT_ITALIC) + ? QFont::StyleItalic + : ((slant_value == FC_SLANT_OBLIQUE) + ? QFont::StyleOblique + : QFont::StyleNormal); + QFont::Weight weight = QFont::Weight(getFCWeight(weight_value)); + + double pixel_size = 0; + if (!scalable) { + int width = 100; + FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width); + FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size); + } + + QFont::Stretch stretch = QFont::Unstretched; + QPlatformFontDatabase::registerFont(familyName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,writingSystems,fontFile); +// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; + } + + FcFontSetDestroy (fonts); + + struct FcDefaultFont { + const char *qtname; + const char *rawname; + bool fixed; + }; + const FcDefaultFont defaults[] = { + { "Serif", "serif", false }, + { "Sans Serif", "sans-serif", false }, + { "Monospace", "monospace", true }, + { 0, 0, false } + }; + const FcDefaultFont *f = defaults; + // aliases only make sense for 'common', not for any of the specials + QSupportedWritingSystems ws; + ws.setSupported(QFontDatabase::Latin); + + + QString familyQtName = QString::fromLatin1(f->qtname); + while (f->qtname) { + registerFont(familyQtName,QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,ws,0); + registerFont(familyQtName,QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,ws,0); + registerFont(familyQtName,QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,ws,0); + ++f; + } + + //Lighthouse has very lazy population of the font db. We want it to be initialized when + //QApplication is constructed, so that the population procedure can do something like this to + //set the default font +// const FcDefaultFont *s = defaults; +// QFont font("Sans Serif"); +// font.setPointSize(9); +// QApplication::setFont(font); +} + +QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QUnicodeTables::Script script, void *usrPtr) +{ + if (!usrPtr) + return 0; + QFontDef fontDef = f; + + QFontEngineFT *engine; + FontFile *fontfile = static_cast<FontFile *> (usrPtr); + QFontEngine::FaceId fid; + fid.filename = fontfile->fileName.toLocal8Bit(); + fid.index = fontfile->indexValue; + + bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); + QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; + + engine = new QFontEngineFT(fontDef); + + // try and get the pattern + FcPattern *pattern = FcPatternCreate(); + + FcValue value; + value.type = FcTypeString; + QByteArray cs = fontDef.family.toUtf8(); + value.u.s = (const FcChar8 *)cs.data(); + FcPatternAdd(pattern,FC_FAMILY,value,true); + + + value.u.s = (const FcChar8 *)fid.filename.data(); + FcPatternAdd(pattern,FC_FILE,value,true); + + value.type = FcTypeInteger; + value.u.i = fid.index; + FcPatternAdd(pattern,FC_INDEX,value,true); + + if (FcConfigSubstitute(0,pattern,FcMatchPattern)) { + QFontEngineFT::HintStyle default_hint_style; + + //hinting + int hint_style = 0; + if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch) + hint_style = QFontEngineFT::HintFull; + switch (hint_style) { + case FC_HINT_NONE: + default_hint_style = QFontEngineFT::HintNone; + break; + case FC_HINT_SLIGHT: + default_hint_style = QFontEngineFT::HintLight; + break; + case FC_HINT_MEDIUM: + default_hint_style = QFontEngineFT::HintMedium; + break; + default: + default_hint_style = QFontEngineFT::HintFull; + break; + } + engine->setDefaultHintStyle(default_hint_style); + } + FcPatternDestroy(pattern); + + if (!engine->init(fid,antialias,format)) { + delete engine; + engine = 0; + return engine; + } + if (engine->invalid()) { + delete engine; + engine = 0; + } else if (scriptRequiresOpenType(script)) { + HB_Face hbFace = engine->harfbuzzFace(); + if (!hbFace || !hbFace->supported_scripts[script]) { + delete engine; + engine = 0; + } + } + + return engine; +} + +QStringList QFontconfigDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const +{ + QStringList fallbackFamilies; + FcPattern *pattern = FcPatternCreate(); + if (!pattern) + return fallbackFamilies; + + FcValue value; + value.type = FcTypeString; + QByteArray cs = family.toUtf8(); + value.u.s = (const FcChar8 *)cs.data(); + FcPatternAdd(pattern,FC_FAMILY,value,true); + + int slant_value = FC_SLANT_ROMAN; + if (style == QFont::StyleItalic) + slant_value = FC_SLANT_ITALIC; + else if (style == QFont::StyleOblique) + slant_value = FC_SLANT_OBLIQUE; + FcPatternAddInteger(pattern, FC_SLANT, slant_value); + + if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') { + Q_ASSERT(script < QUnicodeTables::ScriptCount); + FcLangSet *ls = FcLangSetCreate(); + FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]); + FcPatternAddLangSet(pattern, FC_LANG, ls); + FcLangSetDestroy(ls); + } + + const char *stylehint = getFcFamilyForStyleHint(styleHint); + if (stylehint) { + value.u.s = (const FcChar8 *)stylehint; + FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue); + } + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result = FcResultMatch; + FcFontSet *fontSet = FcFontSort(0,pattern,FcFalse,0,&result); + FcPatternDestroy(pattern); + + if (fontSet) { + if (result == FcResultMatch) { + for (int i = 0; i < fontSet->nfont; i++) { + FcChar8 *value = 0; + if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) + continue; + // capitalize(value); + QString familyName = QString::fromUtf8((const char *)value); + if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive) && + familyName.compare(family, Qt::CaseInsensitive)) { + fallbackFamilies << familyName; + } + } + } + FcFontSetDestroy(fontSet); + } +// qDebug() << "fallbackFamilies for:" << family << style << styleHint << script << fallbackFamilies; + + return fallbackFamilies; +} diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h new file mode 100644 index 0000000000..5a5e4b670f --- /dev/null +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFONTCONFIGDATABASE_H +#define QFONTCONFIGDATABASE_H + +#include <QPlatformFontDatabase> +#include <QtPlatformSupport/private/qbasicunixfontdatabase_p.h> + +class QFontconfigDatabase : public QBasicUnixFontDatabase +{ +public: + void populateFontDatabase(); + QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); + QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const; +}; + +#endif // QFONTCONFIGDATABASE_H diff --git a/src/platformsupport/fontdatabases/fontdatabases.pri b/src/platformsupport/fontdatabases/fontdatabases.pri new file mode 100644 index 0000000000..0e282d97dd --- /dev/null +++ b/src/platformsupport/fontdatabases/fontdatabases.pri @@ -0,0 +1,10 @@ +DEFINES += QT_COMPILES_IN_HARFBUZZ +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src + +unix { + include($$PWD/basicunix/basicunix.pri) + include($$PWD/genericunix/genericunix.pri) + contains(QT_CONFIG,fontconfig) { + include($$PWD/fontconfig/fontconfig.pri) + } +} diff --git a/src/platformsupport/fontdatabases/genericunix/genericunix.pri b/src/platformsupport/fontdatabases/genericunix/genericunix.pri new file mode 100644 index 0000000000..e9db6c07e2 --- /dev/null +++ b/src/platformsupport/fontdatabases/genericunix/genericunix.pri @@ -0,0 +1 @@ +HEADERS += $$PWD/qgenericunixfontdatabase_p.h diff --git a/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h b/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h new file mode 100644 index 0000000000..63f214df54 --- /dev/null +++ b/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt 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 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGENERICUNIXFONTDATABASE_H +#define QGENERICUNIXFONTDATABASE_H + +#ifdef Q_FONTCONFIGDATABASE +#include <QtPlatformSupport/private/qfontconfigdatabase_p.h> +typedef QFontconfigDatabase QGenericUnixFontDatabase; +#else +#include <QtPlatformSupport/private/qbasicunixfontdatabase_p.h> +typedef QBasicUnixFontDatabase QGenericUnixFontDatabase; +#endif //Q_FONTCONFIGDATABASE + +#endif // QGENERICUNIXFONTDATABASE_H |