diff options
Diffstat (limited to 'src/platformsupport/fontdatabases')
32 files changed, 0 insertions, 12573 deletions
diff --git a/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri b/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri deleted file mode 100644 index 671d6be237..0000000000 --- a/src/platformsupport/fontdatabases/fontconfig/fontconfig.pri +++ /dev/null @@ -1,6 +0,0 @@ -HEADERS += $$PWD/qfontconfigdatabase_p.h \ - $$PWD/qfontenginemultifontconfig_p.h -SOURCES += $$PWD/qfontconfigdatabase.cpp \ - $$PWD/qfontenginemultifontconfig.cpp - -QMAKE_USE_PRIVATE += fontconfig diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp deleted file mode 100644 index 7af5490963..0000000000 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ /dev/null @@ -1,1013 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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 "qfontconfigdatabase_p.h" -#include "qfontenginemultifontconfig_p.h" - -#include <QtFontDatabaseSupport/private/qfontengine_ft_p.h> - -#include <QtCore/QList> -#include <QtCore/QElapsedTimer> -#include <QtCore/QFile> - -#include <qpa/qplatformnativeinterface.h> -#include <qpa/qplatformscreen.h> -#include <qpa/qplatformintegration.h> -#include <qpa/qplatformservices.h> - -#include <QtGui/private/qguiapplication_p.h> -#include <QtGui/private/qhighdpiscaling_p.h> - -#include <QtGui/qguiapplication.h> - -#include <fontconfig/fontconfig.h> -#if FC_VERSION >= 20402 -#include <fontconfig/fcfreetype.h> -#endif - -QT_BEGIN_NAMESPACE - -static const int maxWeight = 99; - -static inline int mapToQtWeightForRange(int fcweight, int fcLower, int fcUpper, int qtLower, int qtUpper) -{ - return qtLower + ((fcweight - fcLower) * (qtUpper - qtLower)) / (fcUpper - fcLower); -} - -static inline int weightFromFcWeight(int fcweight) -{ - // Font Config uses weights from 0 to 215 (the highest enum value) while QFont ranges from - // 0 to 99. The spacing between the values for the enums are uneven so a linear mapping from - // Font Config values to Qt would give surprising results. So, we do a piecewise linear - // mapping. This ensures that where there is a corresponding enum on both sides (for example - // FC_WEIGHT_DEMIBOLD and QFont::DemiBold) we map one to the other but other values map - // to intermediate Qt weights. - - if (fcweight <= FC_WEIGHT_THIN) - return QFont::Thin; - if (fcweight <= FC_WEIGHT_ULTRALIGHT) - return mapToQtWeightForRange(fcweight, FC_WEIGHT_THIN, FC_WEIGHT_ULTRALIGHT, QFont::Thin, QFont::ExtraLight); - if (fcweight <= FC_WEIGHT_LIGHT) - return mapToQtWeightForRange(fcweight, FC_WEIGHT_ULTRALIGHT, FC_WEIGHT_LIGHT, QFont::ExtraLight, QFont::Light); - if (fcweight <= FC_WEIGHT_NORMAL) - return mapToQtWeightForRange(fcweight, FC_WEIGHT_LIGHT, FC_WEIGHT_NORMAL, QFont::Light, QFont::Normal); - if (fcweight <= FC_WEIGHT_MEDIUM) - return mapToQtWeightForRange(fcweight, FC_WEIGHT_NORMAL, FC_WEIGHT_MEDIUM, QFont::Normal, QFont::Medium); - if (fcweight <= FC_WEIGHT_DEMIBOLD) - return mapToQtWeightForRange(fcweight, FC_WEIGHT_MEDIUM, FC_WEIGHT_DEMIBOLD, QFont::Medium, QFont::DemiBold); - if (fcweight <= FC_WEIGHT_BOLD) - return mapToQtWeightForRange(fcweight, FC_WEIGHT_DEMIBOLD, FC_WEIGHT_BOLD, QFont::DemiBold, QFont::Bold); - if (fcweight <= FC_WEIGHT_ULTRABOLD) - return mapToQtWeightForRange(fcweight, FC_WEIGHT_BOLD, FC_WEIGHT_ULTRABOLD, QFont::Bold, QFont::ExtraBold); - if (fcweight <= FC_WEIGHT_BLACK) - return mapToQtWeightForRange(fcweight, FC_WEIGHT_ULTRABOLD, FC_WEIGHT_BLACK, QFont::ExtraBold, QFont::Black); - if (fcweight <= FC_WEIGHT_ULTRABLACK) - return mapToQtWeightForRange(fcweight, FC_WEIGHT_BLACK, FC_WEIGHT_ULTRABLACK, QFont::Black, maxWeight); - return maxWeight; -} - -static inline int stretchFromFcWidth(int fcwidth) -{ - // Font Config enums for width match pretty closely with those used by Qt so just use - // Font Config values directly while enforcing the same limits imposed by QFont. - const int maxStretch = 4000; - int qtstretch; - if (fcwidth < 1) - qtstretch = 1; - else if (fcwidth > maxStretch) - qtstretch = maxStretch; - else - qtstretch = fcwidth; - - return qtstretch; -} - -static const char specialLanguages[][6] = { - "", // Unknown - "", // Inherited - "", // Common - "en", // Latin - "el", // Greek - "ru", // Cyrillic - "hy", // Armenian - "he", // Hebrew - "ar", // Arabic - "syr", // Syriac - "dv", // 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 - "am", // Ethiopic - "chr", // Cherokee - "cr", // CanadianAboriginal - "sga", // Ogham - "non", // Runic - "km", // Khmer - "mn", // Mongolian - "ja", // Hiragana - "ja", // Katakana - "zh-TW", // Bopomofo - "", // Han - "ii", // Yi - "ett", // OldItalic - "got", // Gothic - "en", // Deseret - "fil", // Tagalog - "hnn", // Hanunoo - "bku", // Buhid - "tbw", // Tagbanwa - "cop", // Coptic - "lif", // Limbu - "tdd", // TaiLe - "grc", // LinearB - "uga", // Ugaritic - "en", // Shavian - "so", // Osmanya - "grc", // Cypriot - "", // Braille - "bug", // Buginese - "khb", // NewTaiLue - "cu", // Glagolitic - "shi", // Tifinagh - "syl", // SylotiNagri - "peo", // OldPersian - "pra", // Kharoshthi - "ban", // Balinese - "akk", // Cuneiform - "phn", // Phoenician - "lzh", // PhagsPa - "man", // Nko - "su", // Sundanese - "lep", // Lepcha - "sat", // OlChiki - "vai", // Vai - "saz", // Saurashtra - "eky", // KayahLi - "rej", // Rejang - "xlc", // Lycian - "xcr", // Carian - "xld", // Lydian - "cjm", // Cham - "nod", // TaiTham - "blt", // TaiViet - "ae", // Avestan - "egy", // EgyptianHieroglyphs - "smp", // Samaritan - "lis", // Lisu - "bax", // Bamum - "jv", // Javanese - "mni", // MeeteiMayek - "arc", // ImperialAramaic - "xsa", // OldSouthArabian - "xpr", // InscriptionalParthian - "pal", // InscriptionalPahlavi - "otk", // OldTurkic - "bh", // Kaithi - "bbc", // Batak - "pra", // Brahmi - "myz", // Mandaic - "ccp", // Chakma - "xmr", // MeroiticCursive - "xmr", // MeroiticHieroglyphs - "hmd", // Miao - "sa", // Sharada - "srb", // SoraSompeng - "doi", // Takri - "lez", // CaucasianAlbanian - "bsq", // BassaVah - "fr", // Duployan - "sq", // Elbasan - "sa", // Grantha - "hnj", // PahawhHmong - "sd", // Khojki - "lab", // LinearA - "hi", // Mahajani - "xmn", // Manichaean - "men", // MendeKikakui - "mr", // Modi - "mru", // Mro - "xna", // OldNorthArabian - "arc", // Nabataean - "arc", // Palmyrene - "ctd", // PauCinHau - "kv", // OldPermic - "pal", // PsalterPahlavi - "sa", // Siddham - "sd", // Khudawadi - "mai", // Tirhuta - "hoc", // WarangCiti - "", // Ahom - "", // AnatolianHieroglyphs - "", // Hatran - "", // Multani - "", // OldHungarian - "", // SignWriting - "", // Adlam - "", // Bhaiksuki - "", // Marchen - "", // Newa - "", // Osage - "", // Tangut - "", // MasaramGondi - "", // Nushu - "", // Soyombo - "", // ZanabazarSquare - "", // Dogra - "", // GunjalaGondi - "", // HanifiRohingya - "", // Makasar - "", // Medefaidrin - "", // OldSogdian - "", // Sogdian - "", // Elymaic - "", // Nandinagari - "", // NyiakengPuachueHmong - "" // Wancho -}; -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[][6] = { - "", // 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 - "", // Symbol - "sga", // Ogham - "non", // Runic - "man" // N'Ko -}; -Q_STATIC_ASSERT(sizeof languageForWritingSystem / sizeof *languageForWritingSystem == QFontDatabase::WritingSystemsCount); - -#if FC_VERSION >= 20297 -// 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 - "beng", // Bengali - "guru", // Gurmukhi - "gujr", // Gujarati - "orya", // Oriya - "taml", // Tamil - "telu", // Telugu - "knda", // Kannada - "mlym", // Malayalam - "sinh", // Sinhala - "", // Thai - "", // Lao - "tibt", // Tibetan - "mymr", // Myanmar - "", // Georgian - "khmr", // Khmer - "", // SimplifiedChinese - "", // TraditionalChinese - "", // Japanese - "", // Korean - "", // Vietnamese - "", // Symbol - "", // Ogham - "", // Runic - "nko " // N'Ko -}; -Q_STATIC_ASSERT(sizeof(capabilityForWritingSystem) / sizeof(*capabilityForWritingSystem) == QFontDatabase::WritingSystemsCount); -#endif - -static const char *getFcFamilyForStyleHint(const QFont::StyleHint style) -{ - const char *stylehint = nullptr; - switch (style) { - case QFont::SansSerif: - stylehint = "sans-serif"; - break; - case QFont::Serif: - stylehint = "serif"; - break; - case QFont::TypeWriter: - case QFont::Monospace: - stylehint = "monospace"; - break; - case QFont::Cursive: - stylehint = "cursive"; - break; - case QFont::Fantasy: - stylehint = "fantasy"; - break; - default: - break; - } - 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; - QString familyNameLang; - FcChar8 *value = nullptr; - int weight_value; - int slant_value; - int spacing_value; - int width_value; - FcChar8 *file_value; - int indexValue; - FcChar8 *foundry_value; - FcChar8 *style_value; - FcBool scalable; - FcBool antialias; - - if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) != FcResultMatch) - return; - - familyName = QString::fromUtf8((const char *)value); - - if (FcPatternGetString(pattern, FC_FAMILYLANG, 0, &value) == FcResultMatch) - familyNameLang = QString::fromUtf8((const char *)value); - - slant_value = FC_SLANT_ROMAN; - weight_value = FC_WEIGHT_REGULAR; - spacing_value = FC_PROPORTIONAL; - file_value = nullptr; - indexValue = 0; - scalable = FcTrue; - - - if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant_value) != FcResultMatch) - slant_value = FC_SLANT_ROMAN; - if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight_value) != FcResultMatch) - weight_value = FC_WEIGHT_REGULAR; - if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width_value) != FcResultMatch) - width_value = FC_WIDTH_NORMAL; - if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing_value) != FcResultMatch) - spacing_value = FC_PROPORTIONAL; - if (FcPatternGetString(pattern, FC_FILE, 0, &file_value) != FcResultMatch) - file_value = nullptr; - if (FcPatternGetInteger(pattern, FC_INDEX, 0, &indexValue) != FcResultMatch) - indexValue = 0; - if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch) - scalable = FcTrue; - if (FcPatternGetString(pattern, FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) - foundry_value = nullptr; - if (FcPatternGetString(pattern, FC_STYLE, 0, &style_value) != FcResultMatch) - style_value = nullptr; - if (FcPatternGetBool(pattern,FC_ANTIALIAS,0,&antialias) != FcResultMatch) - antialias = true; - - QSupportedWritingSystems writingSystems; - FcLangSet *langset = nullptr; - FcResult res = FcPatternGetLangSet(pattern, FC_LANG, 0, &langset); - if (res == FcResultMatch) { - bool hasLang = false; -#if FC_VERSION >= 20297 - FcChar8 *cap = 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 FC_VERSION >= 20297 - if (*capabilityForWritingSystem[j] && requiresOpenType(j)) { - if (cap == nullptr) - capRes = FcPatternGetString(pattern, FC_CAPABILITY, 0, &cap); - if (capRes == FcResultMatch && strstr(reinterpret_cast<const char *>(cap), capabilityForWritingSystem[j]) == nullptr) - continue; - } -#endif - writingSystems.setSupported(QFontDatabase::WritingSystem(j)); - hasLang = true; - } - } - } - if (!hasLang) - // none of our known languages, add it to the other set - writingSystems.setSupported(QFontDatabase::Other); - } 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); - } - - FontFile *fontFile = new FontFile; - fontFile->fileName = QString::fromLocal8Bit((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); - // Note: weight should really be an int but registerFont incorrectly uses an enum - QFont::Weight weight = QFont::Weight(weightFromFcWeight(weight_value)); - - double pixel_size = 0; - if (!scalable) - FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &pixel_size); - - bool fixedPitch = spacing_value >= FC_MONO; - // Note: stretch should really be an int but registerFont incorrectly uses an enum - QFont::Stretch stretch = QFont::Stretch(stretchFromFcWidth(width_value)); - QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString(); - QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile); -// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; - - 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); - } - } - -} - -void QFontconfigDatabase::populateFontDatabase() -{ - FcInit(); - FcFontSet *fonts; - - { - FcObjectSet *os = FcObjectSetCreate(); - FcPattern *pattern = FcPatternCreate(); - const char *properties [] = { - FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT, - FC_SPACING, FC_FILE, FC_INDEX, - FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, - FC_WIDTH, FC_FAMILYLANG, -#if FC_VERSION >= 20297 - FC_CAPABILITY, -#endif - (const char *)nullptr - }; - const char **p = properties; - while (*p) { - FcObjectSetAdd(os, *p); - ++p; - } - fonts = FcFontList(nullptr, pattern, os); - FcObjectSetDestroy(os); - FcPatternDestroy(pattern); - } - - for (int i = 0; i < fonts->nfont; i++) - populateFromPattern(fonts->fonts[i]); - - 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 }, - { nullptr, nullptr, false } - }; - const FcDefaultFont *f = defaults; - // aliases only make sense for 'common', not for any of the specials - QSupportedWritingSystems ws; - ws.setSupported(QFontDatabase::Latin); - - while (f->qtname) { - QString familyQtName = QString::fromLatin1(f->qtname); - registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,f->fixed,ws,nullptr); - registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,f->fixed,ws,nullptr); - registerFont(familyQtName,QString(),QString(),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,f->fixed,ws,nullptr); - ++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); -} - -void QFontconfigDatabase::invalidate() -{ - // Clear app fonts. - FcConfigAppFontClear(nullptr); -} - -QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) -{ - return new QFontEngineMultiFontConfig(fontEngine, script); -} - -namespace { -QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match, bool useXftConf) -{ - switch (hintingPreference) { - case QFont::PreferNoHinting: - return QFontEngine::HintNone; - case QFont::PreferVerticalHinting: - return QFontEngine::HintLight; - case QFont::PreferFullHinting: - return QFontEngine::HintFull; - case QFont::PreferDefaultHinting: - break; - } - - if (QHighDpiScaling::isActive()) - return QFontEngine::HintNone; - - int hint_style = 0; - if (FcPatternGetInteger (match, FC_HINT_STYLE, 0, &hint_style) == FcResultMatch) { - switch (hint_style) { - case FC_HINT_NONE: - return QFontEngine::HintNone; - case FC_HINT_SLIGHT: - return QFontEngine::HintLight; - case FC_HINT_MEDIUM: - return QFontEngine::HintMedium; - case FC_HINT_FULL: - return QFontEngine::HintFull; - default: - Q_UNREACHABLE(); - break; - } - } - - if (useXftConf) { - void *hintStyleResource = - QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle", - QGuiApplication::primaryScreen()); - int hintStyle = int(reinterpret_cast<qintptr>(hintStyleResource)); - if (hintStyle > 0) - return QFontEngine::HintStyle(hintStyle - 1); - } - - return QFontEngine::HintFull; -} - -QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bool useXftConf) -{ - int subpixel = FC_RGBA_UNKNOWN; - if (FcPatternGetInteger(match, FC_RGBA, 0, &subpixel) == FcResultMatch) { - switch (subpixel) { - case FC_RGBA_UNKNOWN: - case FC_RGBA_NONE: - return QFontEngine::Subpixel_None; - case FC_RGBA_RGB: - return QFontEngine::Subpixel_RGB; - case FC_RGBA_BGR: - return QFontEngine::Subpixel_BGR; - case FC_RGBA_VRGB: - return QFontEngine::Subpixel_VRGB; - case FC_RGBA_VBGR: - return QFontEngine::Subpixel_VBGR; - default: - Q_UNREACHABLE(); - break; - } - } - - if (useXftConf) { - void *subpixelTypeResource = - QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype", - QGuiApplication::primaryScreen()); - int subpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource)); - if (subpixelType > 0) - return QFontEngine::SubpixelAntialiasingType(subpixelType - 1); - } - - return QFontEngine::Subpixel_None; -} -} // namespace - -QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr) -{ - if (!usrPtr) - return nullptr; - - FontFile *fontfile = static_cast<FontFile *> (usrPtr); - QFontEngine::FaceId fid; - fid.filename = QFile::encodeName(fontfile->fileName); - fid.index = fontfile->indexValue; - - // FIXME: Unify with logic in QFontEngineFT::create() - QFontEngineFT *engine = new QFontEngineFT(f); - engine->face_id = fid; - - setupFontEngine(engine, f); - - if (!engine->init(fid, engine->antialias, engine->defaultFormat) || engine->invalid()) { - delete engine; - engine = nullptr; - } - - return engine; -} - -QFontEngine *QFontconfigDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - QFontEngineFT *engine = static_cast<QFontEngineFT*>(QFreeTypeFontDatabase::fontEngine(fontData, pixelSize, hintingPreference)); - if (engine == nullptr) - return nullptr; - - setupFontEngine(engine, engine->fontDef); - - return engine; -} - -QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const -{ - QStringList fallbackFamilies; - FcPattern *pattern = FcPatternCreate(); - if (!pattern) - return fallbackFamilies; - - FcValue value; - value.type = FcTypeString; - const 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); - - Q_ASSERT(uint(script) < QChar::ScriptCount); - if (*specialLanguages[script] != '\0') { - FcLangSet *ls = FcLangSetCreate(); - FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]); - FcPatternAddLangSet(pattern, FC_LANG, ls); - FcLangSetDestroy(ls); - } else if (!family.isEmpty()) { - // If script is Common or Han, then it may include languages like CJK, - // we should attach system default language set to the pattern - // to obtain correct font fallback list (i.e. if LANG=zh_CN - // then we normally want to use a Chinese font for CJK text; - // while a Japanese font should be used for that if LANG=ja) - FcPattern *dummy = FcPatternCreate(); - FcDefaultSubstitute(dummy); - FcChar8 *lang = nullptr; - FcResult res = FcPatternGetString(dummy, FC_LANG, 0, &lang); - if (res == FcResultMatch) - FcPatternAddString(pattern, FC_LANG, lang); - FcPatternDestroy(dummy); - } - - const char *stylehint = getFcFamilyForStyleHint(styleHint); - if (stylehint) { - value.u.s = (const FcChar8 *)stylehint; - FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue); - } - - FcConfigSubstitute(nullptr, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - FcResult result = FcResultMatch; - FcFontSet *fontSet = FcFontSort(nullptr,pattern,FcFalse,nullptr,&result); - FcPatternDestroy(pattern); - - if (fontSet) { - QSet<QString> duplicates; - duplicates.reserve(fontSet->nfont + 1); - duplicates.insert(family.toCaseFolded()); - for (int i = 0; i < fontSet->nfont; i++) { - FcChar8 *value = nullptr; - if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) - continue; - // capitalize(value); - const QString familyName = QString::fromUtf8((const char *)value); - const QString familyNameCF = familyName.toCaseFolded(); - if (!duplicates.contains(familyNameCF)) { - fallbackFamilies << familyName; - duplicates.insert(familyNameCF); - } - } - FcFontSetDestroy(fontSet); - } -// qDebug() << "fallbackFamilies for:" << family << style << styleHint << script << fallbackFamilies; - - return fallbackFamilies; -} - -static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count) -{ -#if FC_VERSION < 20402 - Q_UNUSED(data) - return FcFreeTypeQuery(file, id, blanks, count); -#else - if (data.isEmpty()) - return FcFreeTypeQuery(file, id, blanks, count); - - FT_Library lib = qt_getFreetype(); - - FcPattern *pattern = nullptr; - - FT_Face face; - if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) { - *count = face->num_faces; - - pattern = FcFreeTypeQueryFace(face, file, id, blanks); - - FT_Done_Face(face); - } - - return pattern; -#endif -} - -QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) -{ - QStringList families; - - FcFontSet *set = FcConfigGetFonts(nullptr, FcSetApplication); - if (!set) { - FcConfigAppFontAddFile(nullptr, (const FcChar8 *)":/non-existent"); - set = FcConfigGetFonts(nullptr, FcSetApplication); // try again - if (!set) - return families; - } - - int id = 0; - FcBlanks *blanks = FcConfigGetBlanks(nullptr); - int count = 0; - - FcPattern *pattern; - do { - pattern = queryFont((const FcChar8 *)QFile::encodeName(fileName).constData(), - fontData, id, blanks, &count); - if (!pattern) - return families; - - FcChar8 *fam = nullptr; - if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) { - QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam)); - families << family; - } - populateFromPattern(pattern); - - FcFontSetAdd(set, pattern); - - ++id; - } while (id < count); - - return families; -} - -QString QFontconfigDatabase::resolveFontFamilyAlias(const QString &family) const -{ - QString resolved = QFreeTypeFontDatabase::resolveFontFamilyAlias(family); - if (!resolved.isEmpty() && resolved != family) - return resolved; - FcPattern *pattern = FcPatternCreate(); - if (!pattern) - return family; - - if (!family.isEmpty()) { - const QByteArray cs = family.toUtf8(); - FcPatternAddString(pattern, FC_FAMILY, (const FcChar8 *) cs.constData()); - } - FcConfigSubstitute(nullptr, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - FcChar8 *familyAfterSubstitution = nullptr; - FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution); - resolved = QString::fromUtf8((const char *) familyAfterSubstitution); - FcPatternDestroy(pattern); - - return resolved; -} - -QFont QFontconfigDatabase::defaultFont() const -{ - // Hack to get system default language until FcGetDefaultLangs() - // is exported (https://bugs.freedesktop.org/show_bug.cgi?id=32853) - // or https://bugs.freedesktop.org/show_bug.cgi?id=35482 is fixed - FcPattern *dummy = FcPatternCreate(); - FcDefaultSubstitute(dummy); - FcChar8 *lang = nullptr; - FcResult res = FcPatternGetString(dummy, FC_LANG, 0, &lang); - - FcPattern *pattern = FcPatternCreate(); - if (res == FcResultMatch) { - // Make defaultFont pattern matching locale language aware, because - // certain FC_LANG based custom rules may happen in FcConfigSubstitute() - FcPatternAddString(pattern, FC_LANG, lang); - } - FcConfigSubstitute(nullptr, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - FcChar8 *familyAfterSubstitution = nullptr; - FcPatternGetString(pattern, FC_FAMILY, 0, &familyAfterSubstitution); - QString resolved = QString::fromUtf8((const char *) familyAfterSubstitution); - FcPatternDestroy(pattern); - FcPatternDestroy(dummy); - - return QFont(resolved); -} - -void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef &fontDef) const -{ - bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); - bool forcedAntialiasSetting = !antialias || QHighDpiScaling::isActive(); - - const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services(); - bool useXftConf = false; - - if (services) { - const QList<QByteArray> desktopEnv = services->desktopEnvironment().split(':'); - useXftConf = desktopEnv.contains("GNOME") || desktopEnv.contains("UNITY") || desktopEnv.contains("XFCE"); - } - - if (useXftConf && !forcedAntialiasSetting) { - void *antialiasResource = - QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled", - QGuiApplication::primaryScreen()); - int antialiasingEnabled = int(reinterpret_cast<qintptr>(antialiasResource)); - if (antialiasingEnabled > 0) - antialias = antialiasingEnabled - 1; - } - - QFontEngine::GlyphFormat format; - // 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); - - QFontEngine::FaceId fid = engine->faceId(); - - if (!fid.filename.isEmpty()) { - 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 (fontDef.pixelSize > 0.1) - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontDef.pixelSize); - - FcResult result; - - FcConfigSubstitute(nullptr, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - FcPattern *match = FcFontMatch(nullptr, pattern, &result); - if (match) { - engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)fontDef.hintingPreference, match, useXftConf)); - - FcBool fc_autohint; - if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch) - engine->forceAutoHint = fc_autohint; - -#if defined(FT_LCD_FILTER_H) - int lcdFilter; - if (FcPatternGetInteger(match, FC_LCD_FILTER, 0, &lcdFilter) == FcResultMatch) - engine->lcdFilterType = lcdFilter; -#endif - - if (!forcedAntialiasSetting) { - FcBool fc_antialias; - if (FcPatternGetBool(match, FC_ANTIALIAS,0, &fc_antialias) == FcResultMatch) - antialias = fc_antialias; - } - - if (antialias) { - QFontEngine::SubpixelAntialiasingType subpixelType = QFontEngine::Subpixel_None; - if (!(fontDef.styleStrategy & QFont::NoSubpixelAntialias)) - subpixelType = subpixelTypeFromMatch(match, useXftConf); - engine->subpixelType = subpixelType; - - format = (subpixelType == QFontEngine::Subpixel_None) - ? QFontEngine::Format_A8 - : QFontEngine::Format_A32; - } else - format = QFontEngine::Format_Mono; - - FcPatternDestroy(match); - } else - format = antialias ? QFontEngine::Format_A8 : QFontEngine::Format_Mono; - - FcPatternDestroy(pattern); - - engine->antialias = antialias; - engine->defaultFormat = format; - engine->glyphFormat = format; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h deleted file mode 100644 index a7257c2f98..0000000000 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QFONTCONFIGDATABASE_H -#define QFONTCONFIGDATABASE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <qpa/qplatformfontdatabase.h> -#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h> - -QT_BEGIN_NAMESPACE - -class QFontEngineFT; - -class QFontconfigDatabase : public QFreeTypeFontDatabase -{ -public: - void populateFontDatabase() override; - void invalidate() override; - QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) override; - QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; - QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; - QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override; - QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) override; - QString resolveFontFamilyAlias(const QString &family) const override; - QFont defaultFont() const override; - -private: - void setupFontEngine(QFontEngineFT *engine, const QFontDef &fontDef) const; -}; - -QT_END_NAMESPACE - -#endif // QFONTCONFIGDATABASE_H diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp deleted file mode 100644 index cbf0793d75..0000000000 --- a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** 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 "qfontenginemultifontconfig_p.h" - -#include <QtFontDatabaseSupport/private/qfontengine_ft_p.h> - -QT_BEGIN_NAMESPACE - -QFontEngineMultiFontConfig::QFontEngineMultiFontConfig(QFontEngine *fe, int script) - : QFontEngineMulti(fe, script) -{ -} - -QFontEngineMultiFontConfig::~QFontEngineMultiFontConfig() -{ - for (FcPattern *pattern : qAsConst(cachedMatchPatterns)) { - if (pattern) - FcPatternDestroy(pattern); - } -} - -bool QFontEngineMultiFontConfig::shouldLoadFontEngineForCharacter(int at, uint ucs4) const -{ - bool charSetHasChar = true; - FcPattern *matchPattern = getMatchPatternForFallback(at - 1); - if (matchPattern != nullptr) { - FcCharSet *charSet; - FcPatternGetCharSet(matchPattern, FC_CHARSET, 0, &charSet); - charSetHasChar = FcCharSetHasChar(charSet, ucs4); - } - - return charSetHasChar; -} - - -FcPattern * QFontEngineMultiFontConfig::getMatchPatternForFallback(int fallBackIndex) const -{ - Q_ASSERT(fallBackIndex < fallbackFamilyCount()); - if (fallbackFamilyCount() > cachedMatchPatterns.size()) - cachedMatchPatterns.resize(fallbackFamilyCount()); - FcPattern *ret = cachedMatchPatterns.at(fallBackIndex); - if (ret) - return ret; - FcPattern *requestPattern = FcPatternCreate(); - FcValue value; - value.type = FcTypeString; - QByteArray cs = fallbackFamilyAt(fallBackIndex).toUtf8(); - value.u.s = reinterpret_cast<const FcChar8 *>(cs.data()); - FcPatternAdd(requestPattern, FC_FAMILY, value, true); - FcResult result; - ret = FcFontMatch(nullptr, requestPattern, &result); - cachedMatchPatterns.insert(fallBackIndex, ret); - FcPatternDestroy(requestPattern); - return ret; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h deleted file mode 100644 index 7f560c2d05..0000000000 --- a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QFONTENGINEMULTIFONTCONFIG_H -#define QFONTENGINEMULTIFONTCONFIG_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qfontengine_p.h> -#include <fontconfig/fontconfig.h> - -QT_BEGIN_NAMESPACE - -class QFontEngineMultiFontConfig : public QFontEngineMulti -{ -public: - explicit QFontEngineMultiFontConfig(QFontEngine *fe, int script); - - ~QFontEngineMultiFontConfig(); - - bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const override; -private: - FcPattern* getMatchPatternForFallback(int at) const; - - mutable QVector<FcPattern*> cachedMatchPatterns; -}; - -QT_END_NAMESPACE - -#endif // QFONTENGINEMULTIFONTCONFIG_H diff --git a/src/platformsupport/fontdatabases/fontdatabases.pro b/src/platformsupport/fontdatabases/fontdatabases.pro deleted file mode 100644 index c3985ed398..0000000000 --- a/src/platformsupport/fontdatabases/fontdatabases.pro +++ /dev/null @@ -1,34 +0,0 @@ -TARGET = QtFontDatabaseSupport -MODULE = fontdatabase_support - -QT = core-private gui-private -CONFIG += static internal_module - -DEFINES += QT_NO_CAST_FROM_ASCII -PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h - -darwin { - include($$PWD/mac/coretext.pri) -} - -qtConfig(freetype) { - include($$PWD/freetype/freetype.pri) -} - -unix { - include($$PWD/genericunix/genericunix.pri) -} - -qtConfig(fontconfig) { - include($$PWD/fontconfig/fontconfig.pri) -} - -win32:!winrt { - include($$PWD/windows/windows.pri) -} - -winrt { - include($$PWD/winrt/winrt.pri) -} - -load(qt_module) diff --git a/src/platformsupport/fontdatabases/freetype/freetype.pri b/src/platformsupport/fontdatabases/freetype/freetype.pri deleted file mode 100644 index 7bda687ef4..0000000000 --- a/src/platformsupport/fontdatabases/freetype/freetype.pri +++ /dev/null @@ -1,9 +0,0 @@ -HEADERS += \ - $$PWD/qfreetypefontdatabase_p.h \ - $$PWD/qfontengine_ft_p.h - -SOURCES += \ - $$PWD/qfreetypefontdatabase.cpp \ - $$PWD/qfontengine_ft.cpp - -QMAKE_USE_PRIVATE += freetype diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp deleted file mode 100644 index ca78063f08..0000000000 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp +++ /dev/null @@ -1,2122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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 "qdir.h" -#include "qmetatype.h" -#include "qtextstream.h" -#include "qvariant.h" -#include "qfontengine_ft_p.h" -#include "private/qimage_p.h" -#include <private/qstringiterator_p.h> -#include <qguiapplication.h> -#include <qscreen.h> -#include <qpa/qplatformscreen.h> -#include <QtCore/QUuid> - -#ifndef QT_NO_FREETYPE - -#include "qfile.h" -#include "qfileinfo.h" -#include <qscopedvaluerollback.h> -#include "qthreadstorage.h" -#include <qmath.h> -#include <qendian.h> - -#include <ft2build.h> -#include FT_FREETYPE_H -#include FT_OUTLINE_H -#include FT_SYNTHESIS_H -#include FT_TRUETYPE_TABLES_H -#include FT_TYPE1_TABLES_H -#include FT_GLYPH_H -#include FT_MODULE_H -#include FT_LCD_FILTER_H - -#if defined(FT_CONFIG_OPTIONS_H) -#include FT_CONFIG_OPTIONS_H -#endif - -#if defined(FT_FONT_FORMATS_H) -#include FT_FONT_FORMATS_H -#endif - -#ifdef QT_LINUXBASE -#include FT_ERRORS_H -#endif - -#if !defined(QT_MAX_CACHED_GLYPH_SIZE) -# define QT_MAX_CACHED_GLYPH_SIZE 64 -#endif - -QT_BEGIN_NAMESPACE - -#define FLOOR(x) ((x) & -64) -#define CEIL(x) (((x)+63) & -64) -#define TRUNC(x) ((x) >> 6) -#define ROUND(x) (((x)+32) & -64) - -static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length) -{ - FT_Face face = (FT_Face)user_data; - - bool result = false; - if (FT_IS_SFNT(face)) { - FT_ULong len = *length; - result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok; - *length = len; - Q_ASSERT(!result || int(*length) > 0); - } - - return result; -} - -static QFontEngineFT::Glyph emptyGlyph; - -static const QFontEngine::HintStyle ftInitialDefaultHintStyle = -#ifdef Q_OS_WIN - QFontEngineFT::HintFull; -#else - QFontEngineFT::HintNone; -#endif - -// -------------------------- Freetype support ------------------------------ - -class QtFreetypeData -{ -public: - QtFreetypeData() - : library(nullptr) - { } - ~QtFreetypeData(); - - FT_Library library; - QHash<QFontEngine::FaceId, QFreetypeFace *> faces; -}; - -QtFreetypeData::~QtFreetypeData() -{ - for (QHash<QFontEngine::FaceId, QFreetypeFace *>::ConstIterator iter = faces.cbegin(); iter != faces.cend(); ++iter) - iter.value()->cleanup(); - faces.clear(); - FT_Done_FreeType(library); - library = nullptr; -} - -Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData) - -QtFreetypeData *qt_getFreetypeData() -{ - QtFreetypeData *&freetypeData = theFreetypeData()->localData(); - if (!freetypeData) - freetypeData = new QtFreetypeData; - if (!freetypeData->library) { - FT_Init_FreeType(&freetypeData->library); -#if defined(FT_FONT_FORMATS_H) - // Freetype defaults to disabling stem-darkening on CFF, we re-enable it. - FT_Bool no_darkening = false; - FT_Property_Set(freetypeData->library, "cff", "no-stem-darkening", &no_darkening); -#endif - } - return freetypeData; -} - -FT_Library qt_getFreetype() -{ - QtFreetypeData *freetypeData = qt_getFreetypeData(); - Q_ASSERT(freetypeData->library); - return freetypeData->library; -} - -int QFreetypeFace::fsType() const -{ - int fsType = 0; - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); - if (os2) - fsType = os2->fsType; - return fsType; -} - -int QFreetypeFace::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) -{ - if (int error = FT_Load_Glyph(face, glyph, flags)) - return error; - - if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) - return Err_Invalid_SubTable; - - *nPoints = face->glyph->outline.n_points; - if (!(*nPoints)) - return Err_Ok; - - if (point > *nPoints) - return Err_Invalid_SubTable; - - *xpos = QFixed::fromFixed(face->glyph->outline.points[point].x); - *ypos = QFixed::fromFixed(face->glyph->outline.points[point].y); - - return Err_Ok; -} - -bool QFreetypeFace::isScalableBitmap() const -{ -#ifdef FT_HAS_COLOR - return !FT_IS_SCALABLE(face) && FT_HAS_COLOR(face); -#else - return false; -#endif -} - -extern QByteArray qt_fontdata_from_index(int); - -/* - * One font file can contain more than one font (bold/italic for example) - * find the right one and return it. - * - * Returns the freetype face or 0 in case of an empty file or any other problems - * (like not being able to open the file) - */ -QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, - const QByteArray &fontData) -{ - if (face_id.filename.isEmpty() && fontData.isEmpty()) - return nullptr; - - QtFreetypeData *freetypeData = qt_getFreetypeData(); - - QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0); - if (freetype) { - freetype->ref.ref(); - } else { - QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace); - FT_Face face; - if (!face_id.filename.isEmpty()) { - QString fileName = QFile::decodeName(face_id.filename); - if (face_id.filename.startsWith(":qmemoryfonts/")) { - // from qfontdatabase.cpp - QByteArray idx = face_id.filename; - idx.remove(0, 14); // remove ':qmemoryfonts/' - bool ok = false; - newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok)); - if (!ok) - newFreetype->fontData = QByteArray(); - } else if (!QFileInfo(fileName).isNativePath()) { - QFile file(fileName); - if (!file.open(QIODevice::ReadOnly)) { - return nullptr; - } - newFreetype->fontData = file.readAll(); - } - } else { - newFreetype->fontData = fontData; - } - if (!newFreetype->fontData.isEmpty()) { - if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) { - return nullptr; - } - } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) { - return nullptr; - } - newFreetype->face = face; - - newFreetype->ref.storeRelaxed(1); - newFreetype->xsize = 0; - newFreetype->ysize = 0; - newFreetype->matrix.xx = 0x10000; - newFreetype->matrix.yy = 0x10000; - newFreetype->matrix.xy = 0; - newFreetype->matrix.yx = 0; - newFreetype->unicode_map = nullptr; - newFreetype->symbol_map = nullptr; - - memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache)); - - for (int i = 0; i < newFreetype->face->num_charmaps; ++i) { - FT_CharMap cm = newFreetype->face->charmaps[i]; - switch(cm->encoding) { - case FT_ENCODING_UNICODE: - newFreetype->unicode_map = cm; - break; - case FT_ENCODING_APPLE_ROMAN: - case FT_ENCODING_ADOBE_LATIN_1: - if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE) - newFreetype->unicode_map = cm; - break; - case FT_ENCODING_ADOBE_CUSTOM: - case FT_ENCODING_MS_SYMBOL: - if (!newFreetype->symbol_map) - newFreetype->symbol_map = cm; - break; - default: - break; - } - } - - if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1) - FT_Set_Char_Size(face, newFreetype->face->available_sizes[0].x_ppem, newFreetype->face->available_sizes[0].y_ppem, 0, 0); - - FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map); - QT_TRY { - freetypeData->faces.insert(face_id, newFreetype.data()); - } QT_CATCH(...) { - newFreetype.take()->release(face_id); - // we could return null in principle instead of throwing - QT_RETHROW; - } - freetype = newFreetype.take(); - } - return freetype; -} - -void QFreetypeFace::cleanup() -{ - hbFace.reset(); - FT_Done_Face(face); - face = nullptr; -} - -void QFreetypeFace::release(const QFontEngine::FaceId &face_id) -{ - if (!ref.deref()) { - if (face) { - QtFreetypeData *freetypeData = qt_getFreetypeData(); - - cleanup(); - - auto it = freetypeData->faces.constFind(face_id); - if (it != freetypeData->faces.constEnd()) - freetypeData->faces.erase(it); - - if (freetypeData->faces.isEmpty()) { - FT_Done_FreeType(freetypeData->library); - freetypeData->library = nullptr; - } - } - - delete this; - } -} - - -void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing, QFixed *scalableBitmapScaleFactor) -{ - *ysize = qRound(fontDef.pixelSize * 64); - *xsize = *ysize * fontDef.stretch / 100; - *scalableBitmapScaleFactor = 1; - *outline_drawing = false; - - if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) { - int best = 0; - if (!isScalableBitmap()) { - /* - * Bitmap only faces must match exactly, so find the closest - * one (height dominant search) - */ - for (int i = 1; i < face->num_fixed_sizes; i++) { - if (qAbs(*ysize - face->available_sizes[i].y_ppem) < - qAbs(*ysize - face->available_sizes[best].y_ppem) || - (qAbs(*ysize - face->available_sizes[i].y_ppem) == - qAbs(*ysize - face->available_sizes[best].y_ppem) && - qAbs(*xsize - face->available_sizes[i].x_ppem) < - qAbs(*xsize - face->available_sizes[best].x_ppem))) { - best = i; - } - } - } else { - // Select the shortest bitmap strike whose height is larger than the desired height - for (int i = 1; i < face->num_fixed_sizes; i++) { - if (face->available_sizes[i].y_ppem < *ysize) { - if (face->available_sizes[i].y_ppem > face->available_sizes[best].y_ppem) - best = i; - } else if (face->available_sizes[best].y_ppem < *ysize) { - best = i; - } else if (face->available_sizes[i].y_ppem < face->available_sizes[best].y_ppem) { - best = i; - } - } - } - - // According to freetype documentation we must use FT_Select_Size - // to make sure we can select the desired bitmap strike index - if (FT_Select_Size(face, best) == 0) { - if (isScalableBitmap()) - *scalableBitmapScaleFactor = QFixed::fromReal((qreal)fontDef.pixelSize / face->available_sizes[best].height); - *xsize = face->available_sizes[best].x_ppem; - *ysize = face->available_sizes[best].y_ppem; - } else { - *xsize = *ysize = 0; - } - } else { - *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6)); - } -} - -QFontEngine::Properties QFreetypeFace::properties() const -{ - QFontEngine::Properties p; - p.postscriptName = FT_Get_Postscript_Name(face); - PS_FontInfoRec font_info; - if (FT_Get_PS_Font_Info(face, &font_info) == 0) - p.copyright = font_info.notice; - if (FT_IS_SCALABLE(face)) { - p.ascent = face->ascender; - p.descent = -face->descender; - p.leading = face->height - face->ascender + face->descender; - p.emSquare = face->units_per_EM; - p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax, - face->bbox.xMax - face->bbox.xMin, - face->bbox.yMax - face->bbox.yMin); - } else { - p.ascent = QFixed::fromFixed(face->size->metrics.ascender); - p.descent = QFixed::fromFixed(-face->size->metrics.descender); - p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender); - p.emSquare = face->size->metrics.y_ppem; -// p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.); - p.boundingBox = QRectF(0, -p.ascent.toReal(), - face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() ); - } - p.italicAngle = 0; - p.capHeight = p.ascent; - p.lineWidth = face->underline_thickness; - - return p; -} - -bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const -{ - return ft_getSfntTable(face, tag, buffer, length); -} - -/* Some fonts (such as MingLiu rely on hinting to scale different - components to their correct sizes. While this is really broken (it - should be done in the component glyph itself, not the hinter) we - will have to live with it. - - This means we can not use FT_LOAD_NO_HINTING to get the glyph - outline. All we can do is to load the unscaled glyph and scale it - down manually when required. -*/ -static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale) -{ - x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM); - y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM); - FT_Vector *p = g->outline.points; - const FT_Vector *e = p + g->outline.n_points; - while (p < e) { - p->x = FT_MulFix(p->x, x_scale); - p->y = FT_MulFix(p->y, y_scale); - ++p; - } -} - -#define GLYPH2PATH_DEBUG QT_NO_QDEBUG_MACRO // qDebug -void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale) -{ - const qreal factor = 1/64.; - scaleOutline(face, g, x_scale, y_scale); - - QPointF cp = point.toPointF(); - - // convert the outline to a painter path - int i = 0; - for (int j = 0; j < g->outline.n_contours; ++j) { - int last_point = g->outline.contours[j]; - GLYPH2PATH_DEBUG() << "contour:" << i << "to" << last_point; - QPointF start = QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor); - if (!(g->outline.tags[i] & 1)) { // start point is not on curve: - if (!(g->outline.tags[last_point] & 1)) { // end point is not on curve: - GLYPH2PATH_DEBUG() << " start and end point are not on curve"; - start = (QPointF(g->outline.points[last_point].x*factor, - -g->outline.points[last_point].y*factor) + start) / 2.0; - } else { - GLYPH2PATH_DEBUG() << " end point is on curve, start is not"; - start = QPointF(g->outline.points[last_point].x*factor, - -g->outline.points[last_point].y*factor); - } - --i; // to use original start point as control point below - } - start += cp; - GLYPH2PATH_DEBUG() << " start at" << start; - - path->moveTo(start); - QPointF c[4]; - c[0] = start; - int n = 1; - while (i < last_point) { - ++i; - c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor); - GLYPH2PATH_DEBUG() << " " << i << c[n] << "tag =" << (int)g->outline.tags[i] - << ": on curve =" << (bool)(g->outline.tags[i] & 1); - ++n; - switch (g->outline.tags[i] & 3) { - case 2: - // cubic bezier element - if (n < 4) - continue; - c[3] = (c[3] + c[2])/2; - --i; - break; - case 0: - // quadratic bezier element - if (n < 3) - continue; - c[3] = (c[1] + c[2])/2; - c[2] = (2*c[1] + c[3])/3; - c[1] = (2*c[1] + c[0])/3; - --i; - break; - case 1: - case 3: - if (n == 2) { - GLYPH2PATH_DEBUG() << " lineTo" << c[1]; - path->lineTo(c[1]); - c[0] = c[1]; - n = 1; - continue; - } else if (n == 3) { - c[3] = c[2]; - c[2] = (2*c[1] + c[3])/3; - c[1] = (2*c[1] + c[0])/3; - } - break; - } - GLYPH2PATH_DEBUG() << " cubicTo" << c[1] << c[2] << c[3]; - path->cubicTo(c[1], c[2], c[3]); - c[0] = c[3]; - n = 1; - } - - if (n == 1) { - GLYPH2PATH_DEBUG() << " closeSubpath"; - path->closeSubpath(); - } else { - c[3] = start; - if (n == 2) { - c[2] = (2*c[1] + c[3])/3; - c[1] = (2*c[1] + c[0])/3; - } - GLYPH2PATH_DEBUG() << " close cubicTo" << c[1] << c[2] << c[3]; - path->cubicTo(c[1], c[2], c[3]); - } - ++i; - } -} - -extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path); - -void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path) -{ - if (slot->format != FT_GLYPH_FORMAT_BITMAP - || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO) - return; - - QPointF cp = point.toPointF(); - qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY), - slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path); -} - -static inline void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr) -{ - const int offs = bgr ? -1 : 1; - const int w = width * 3; - while (height--) { - uint *dd = dst; - for (int x = 0; x < w; x += 3) { - uchar red = src[x + 1 - offs]; - uchar green = src[x + 1]; - uchar blue = src[x + 1 + offs]; - *dd++ = (0xFFU << 24) | (red << 16) | (green << 8) | blue; - } - dst += width; - src += src_pitch; - } -} - -static inline void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr) -{ - const int offs = bgr ? -src_pitch : src_pitch; - while (height--) { - for (int x = 0; x < width; x++) { - uchar red = src[x + src_pitch - offs]; - uchar green = src[x + src_pitch]; - uchar blue = src[x + src_pitch + offs]; - *dst++ = (0XFFU << 24) | (red << 16) | (green << 8) | blue; - } - src += 3*src_pitch; - } -} - -static QFontEngine::SubpixelAntialiasingType subpixelAntialiasingTypeHint() -{ - static int type = -1; - if (type == -1) { - if (QScreen *screen = QGuiApplication::primaryScreen()) - type = screen->handle()->subpixelAntialiasingTypeHint(); - } - return static_cast<QFontEngine::SubpixelAntialiasingType>(type); -} - -QFontEngineFT *QFontEngineFT::create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData) -{ - QScopedPointer<QFontEngineFT> engine(new QFontEngineFT(fontDef)); - - QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono; - const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); - - 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("QFontEngineFT: Failed to create FreeType font engine"); - return nullptr; - } - - engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference)); - return engine.take(); -} - -namespace { - class QFontEngineFTRawData: public QFontEngineFT - { - public: - QFontEngineFTRawData(const QFontDef &fontDef) : QFontEngineFT(fontDef) - { - } - - void updateFamilyNameAndStyle() - { - fontDef.family = QString::fromLatin1(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); - } - }; -} - -QFontEngineFT *QFontEngineFT::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - QFontDef fontDef; - fontDef.pixelSize = pixelSize; - fontDef.stretch = QFont::Unstretched; - fontDef.hintingPreference = hintingPreference; - - QFontEngineFTRawData *fe = new QFontEngineFTRawData(fontDef); - if (!fe->initFromData(fontData)) { - delete fe; - return nullptr; - } - - fe->updateFamilyNameAndStyle(); - fe->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference)); - - return fe; -} - -QFontEngineFT::QFontEngineFT(const QFontDef &fd) - : QFontEngine(Freetype) -{ - fontDef = fd; - matrix.xx = 0x10000; - matrix.yy = 0x10000; - matrix.xy = 0; - matrix.yx = 0; - cache_cost = 100 * 1024; - kerning_pairs_loaded = false; - transform = false; - embolden = false; - obliquen = false; - antialias = true; - freetype = nullptr; - default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; - default_hint_style = ftInitialDefaultHintStyle; - subpixelType = Subpixel_None; - lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT); - defaultFormat = Format_None; - embeddedbitmap = false; - const QByteArray env = qgetenv("QT_NO_FT_CACHE"); - cacheEnabled = env.isEmpty() || env.toInt() == 0; - m_subPixelPositionCount = 4; - forceAutoHint = false; - stemDarkeningDriver = false; -} - -QFontEngineFT::~QFontEngineFT() -{ - if (freetype) - freetype->release(face_id); -} - -bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, - const QByteArray &fontData) -{ - return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData)); -} - -static void dont_delete(void*) {} - -bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, - QFreetypeFace *freetypeFace) -{ - freetype = freetypeFace; - if (!freetype) { - xsize = 0; - ysize = 0; - return false; - } - defaultFormat = format; - this->antialias = antialias; - - if (!antialias) - glyphFormat = QFontEngine::Format_Mono; - else - glyphFormat = defaultFormat; - - face_id = faceId; - - symbol = freetype->symbol_map != nullptr; - PS_FontInfoRec psrec; - // don't assume that type1 fonts are symbol fonts by default - if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) { - symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive)); - } - - freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing, &scalableBitmapScaleFactor); - - FT_Face face = lockFace(); - - if (FT_IS_SCALABLE(face)) { - bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC); - if (fake_oblique) - obliquen = true; - FT_Set_Transform(face, &matrix, nullptr); - freetype->matrix = matrix; - // fake bold - if ((fontDef.weight >= QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face)) { - if (const TT_OS2 *os2 = reinterpret_cast<const TT_OS2 *>(FT_Get_Sfnt_Table(face, ft_sfnt_os2))) { - if (os2->usWeightClass < 700) - embolden = true; - } - } - // underline metrics - line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale)); - underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale)); - } else { - // ad hoc algorithm - int score = fontDef.weight * fontDef.pixelSize; - line_thickness = score / 700; - // looks better with thicker line for small pointsizes - if (line_thickness < 2 && score >= 1050) - line_thickness = 2; - underline_position = ((line_thickness * 2) + 3) / 6; - - if (isScalableBitmap()) { - glyphFormat = defaultFormat = GlyphFormat::Format_ARGB; - cacheEnabled = false; - } - } - if (line_thickness < 1) - line_thickness = 1; - - metrics = face->size->metrics; - - /* - TrueType fonts with embedded bitmaps may have a bitmap font specific - ascent/descent in the EBLC table. There is no direct public API - to extract those values. The only way we've found is to trick freetype - into thinking that it's not a scalable font in FT_SelectSize so that - the metrics are retrieved from the bitmap strikes. - */ - if (FT_IS_SCALABLE(face)) { - for (int i = 0; i < face->num_fixed_sizes; ++i) { - if (xsize == face->available_sizes[i].x_ppem && ysize == face->available_sizes[i].y_ppem) { - face->face_flags &= ~FT_FACE_FLAG_SCALABLE; - - FT_Select_Size(face, i); - if (face->size->metrics.ascender + face->size->metrics.descender > 0) { - FT_Pos leading = metrics.height - metrics.ascender + metrics.descender; - metrics.ascender = face->size->metrics.ascender; - metrics.descender = face->size->metrics.descender; - if (metrics.descender > 0 - && QString::fromUtf8(face->family_name) == QLatin1String("Courier New")) { - metrics.descender *= -1; - } - metrics.height = metrics.ascender - metrics.descender + leading; - } - FT_Set_Char_Size(face, xsize, ysize, 0, 0); - - face->face_flags |= FT_FACE_FLAG_SCALABLE; - break; - } - } - } -#if defined(FT_FONT_FORMATS_H) - const char *fmt = FT_Get_Font_Format(face); - if (fmt && qstrncmp(fmt, "CFF", 4) == 0) { - FT_Bool no_stem_darkening = true; - FT_Error err = FT_Property_Get(qt_getFreetype(), "cff", "no-stem-darkening", &no_stem_darkening); - if (err == FT_Err_Ok) - stemDarkeningDriver = !no_stem_darkening; - else - stemDarkeningDriver = false; - } -#endif - - fontDef.styleName = QString::fromUtf8(face->style_name); - - if (!freetype->hbFace) { - faceData.user_data = face; - faceData.get_font_table = ft_getSfntTable; - (void)harfbuzzFace(); // populates face_ - freetype->hbFace = std::move(face_); - } else { - Q_ASSERT(!face_); - } - // we share the HB face in QFreeTypeFace, so do not let ~QFontEngine() destroy it - face_ = Holder(freetype->hbFace.get(), dont_delete); - - unlockFace(); - - fsType = freetype->fsType(); - return true; -} - -void QFontEngineFT::setQtDefaultHintStyle(QFont::HintingPreference hintingPreference) -{ - switch (hintingPreference) { - case QFont::PreferNoHinting: - setDefaultHintStyle(HintNone); - break; - case QFont::PreferFullHinting: - setDefaultHintStyle(HintFull); - break; - case QFont::PreferVerticalHinting: - setDefaultHintStyle(HintLight); - break; - case QFont::PreferDefaultHinting: - setDefaultHintStyle(ftInitialDefaultHintStyle); - break; - } -} - -void QFontEngineFT::setDefaultHintStyle(HintStyle style) -{ - default_hint_style = style; -} - -bool QFontEngineFT::expectsGammaCorrectedBlending() const -{ - return stemDarkeningDriver; -} - -int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags, - bool &hsubpixel, int &vfactor) const -{ - int load_flags = FT_LOAD_DEFAULT | default_load_flags; - int load_target = default_hint_style == HintLight - ? FT_LOAD_TARGET_LIGHT - : FT_LOAD_TARGET_NORMAL; - - if (format == Format_Mono) { - load_target = FT_LOAD_TARGET_MONO; - } else if (format == Format_A32) { - if (subpixelType == Subpixel_RGB || subpixelType == Subpixel_BGR) - hsubpixel = true; - else if (subpixelType == Subpixel_VRGB || subpixelType == Subpixel_VBGR) - vfactor = 3; - } else if (format == Format_ARGB) { -#ifdef FT_LOAD_COLOR - load_flags |= FT_LOAD_COLOR; -#endif - } - - if (set && set->outline_drawing) - load_flags |= FT_LOAD_NO_BITMAP; - - if (default_hint_style == HintNone || (flags & DesignMetrics) || (set && set->outline_drawing)) - load_flags |= FT_LOAD_NO_HINTING; - else - load_flags |= load_target; - - if (forceAutoHint) - load_flags |= FT_LOAD_FORCE_AUTOHINT; - - return load_flags; -} - -static inline bool areMetricsTooLarge(const QFontEngineFT::GlyphInfo &info) -{ - // false if exceeds QFontEngineFT::Glyph metrics - return info.width > 0xFF || info.height > 0xFF; -} - -static inline void transformBoundingBox(int *left, int *top, int *right, int *bottom, FT_Matrix *matrix) -{ - int l, r, t, b; - FT_Vector vector; - vector.x = *left; - vector.y = *top; - FT_Vector_Transform(&vector, matrix); - l = r = vector.x; - t = b = vector.y; - vector.x = *right; - vector.y = *top; - FT_Vector_Transform(&vector, matrix); - if (l > vector.x) l = vector.x; - if (r < vector.x) r = vector.x; - if (t < vector.y) t = vector.y; - if (b > vector.y) b = vector.y; - vector.x = *right; - vector.y = *bottom; - FT_Vector_Transform(&vector, matrix); - if (l > vector.x) l = vector.x; - if (r < vector.x) r = vector.x; - if (t < vector.y) t = vector.y; - if (b > vector.y) b = vector.y; - vector.x = *left; - vector.y = *bottom; - FT_Vector_Transform(&vector, matrix); - if (l > vector.x) l = vector.x; - if (r < vector.x) r = vector.x; - if (t < vector.y) t = vector.y; - if (b > vector.y) b = vector.y; - *left = l; - *right = r; - *top = t; - *bottom = b; -} - -QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, - QFixed subPixelPosition, - GlyphFormat format, - bool fetchMetricsOnly, - bool disableOutlineDrawing) const -{ -// Q_ASSERT(freetype->lock == 1); - - if (format == Format_None) - format = defaultFormat != Format_None ? defaultFormat : Format_Mono; - Q_ASSERT(format != Format_None); - - Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : nullptr; - if (g && g->format == format && (fetchMetricsOnly || g->data)) - return g; - - if (!g && set && set->isGlyphMissing(glyph)) - return &emptyGlyph; - - - FT_Face face = freetype->face; - - FT_Matrix matrix = freetype->matrix; - - FT_Vector v; - v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.value()); - v.y = 0; - FT_Set_Transform(face, &matrix, &v); - - bool hsubpixel = false; - int vfactor = 1; - int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor); - - bool transform = matrix.xx != 0x10000 - || matrix.yy != 0x10000 - || matrix.xy != 0 - || matrix.yx != 0; - - if (transform || obliquen || (format != Format_Mono && !isScalableBitmap())) - load_flags |= FT_LOAD_NO_BITMAP; - - FT_Error err = FT_Load_Glyph(face, glyph, load_flags); - if (err && (load_flags & FT_LOAD_NO_BITMAP)) { - load_flags &= ~FT_LOAD_NO_BITMAP; - err = FT_Load_Glyph(face, glyph, load_flags); - } - if (err == FT_Err_Too_Few_Arguments) { - // this is an error in the bytecode interpreter, just try to run without it - load_flags |= FT_LOAD_FORCE_AUTOHINT; - err = FT_Load_Glyph(face, glyph, load_flags); - } else if (err == FT_Err_Execution_Too_Long) { - // This is an error in the bytecode, probably a web font made by someone who - // didn't test bytecode hinting at all so disable for it for all glyphs. - qWarning("load glyph failed due to broken hinting bytecode in font, switching to auto hinting"); - default_load_flags |= FT_LOAD_FORCE_AUTOHINT; - load_flags |= FT_LOAD_FORCE_AUTOHINT; - err = FT_Load_Glyph(face, glyph, load_flags); - } - if (err != FT_Err_Ok) { - qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph); - if (set) - set->setGlyphMissing(glyph); - return &emptyGlyph; - } - - FT_GlyphSlot slot = face->glyph; - - if (embolden) - FT_GlyphSlot_Embolden(slot); - if (obliquen) { - FT_GlyphSlot_Oblique(slot); - - // While Embolden alters the metrics of the slot, oblique does not, so we need - // to fix this ourselves. - transform = true; - FT_Matrix m; - m.xx = 0x10000; - m.yx = 0x0; - m.xy = 0x6000; - m.yy = 0x10000; - - FT_Matrix_Multiply(&m, &matrix); - } - - GlyphInfo info; - info.linearAdvance = slot->linearHoriAdvance >> 10; - info.xOff = TRUNC(ROUND(slot->advance.x)); - info.yOff = 0; - - if ((set && set->outline_drawing && !disableOutlineDrawing) || fetchMetricsOnly) { - int left = slot->metrics.horiBearingX; - int right = slot->metrics.horiBearingX + slot->metrics.width; - int top = slot->metrics.horiBearingY; - int bottom = slot->metrics.horiBearingY - slot->metrics.height; - - if (transform && slot->format != FT_GLYPH_FORMAT_BITMAP) - transformBoundingBox(&left, &top, &right, &bottom, &matrix); - - left = FLOOR(left); - right = CEIL(right); - bottom = FLOOR(bottom); - top = CEIL(top); - - info.x = TRUNC(left); - info.y = TRUNC(top); - info.width = TRUNC(right - left); - info.height = TRUNC(top - bottom); - - // If any of the metrics are too large to fit, don't cache them - if (areMetricsTooLarge(info)) - return nullptr; - - g = new Glyph; - g->data = nullptr; - g->linearAdvance = info.linearAdvance; - g->width = info.width; - g->height = info.height; - g->x = info.x; - g->y = info.y; - g->advance = info.xOff; - g->format = format; - - if (set) - set->setGlyph(glyph, subPixelPosition, g); - - return g; - } - - int glyph_buffer_size = 0; - QScopedArrayPointer<uchar> glyph_buffer; - FT_Render_Mode renderMode = (default_hint_style == HintLight) ? FT_RENDER_MODE_LIGHT : FT_RENDER_MODE_NORMAL; - switch (format) { - case Format_Mono: - renderMode = FT_RENDER_MODE_MONO; - break; - case Format_A32: - Q_ASSERT(hsubpixel || vfactor != 1); - renderMode = hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V; - break; - case Format_A8: - case Format_ARGB: - break; - default: - Q_UNREACHABLE(); - } - FT_Library_SetLcdFilter(slot->library, (FT_LcdFilter)lcdFilterType); - - err = FT_Render_Glyph(slot, renderMode); - if (err != FT_Err_Ok) - qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph); - - FT_Library_SetLcdFilter(slot->library, FT_LCD_FILTER_NONE); - - info.height = slot->bitmap.rows; - info.width = slot->bitmap.width; - info.x = slot->bitmap_left; - info.y = slot->bitmap_top; - if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) - info.width = info.width / 3; - if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) - info.height = info.height / vfactor; - - int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 : - (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4)); - - glyph_buffer_size = info.height * pitch; - glyph_buffer.reset(new uchar[glyph_buffer_size]); - - if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { - uchar *src = slot->bitmap.buffer; - uchar *dst = glyph_buffer.data(); - int h = slot->bitmap.rows; - // Some fonts return bitmaps even when we requested something else: - if (format == Format_Mono) { - int bytes = ((info.width + 7) & ~7) >> 3; - while (h--) { - memcpy (dst, src, bytes); - dst += pitch; - src += slot->bitmap.pitch; - } - } else if (format == Format_A8) { - while (h--) { - for (int x = 0; x < int{info.width}; x++) - dst[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00); - dst += pitch; - src += slot->bitmap.pitch; - } - } else { - while (h--) { - uint *dd = reinterpret_cast<uint *>(dst); - for (int x = 0; x < int{info.width}; x++) - dd[x] = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffffff : 0x00000000); - dst += pitch; - src += slot->bitmap.pitch; - } - } - } else if (slot->bitmap.pixel_mode == 7 /*FT_PIXEL_MODE_BGRA*/) { - Q_ASSERT(format == Format_ARGB); - uchar *src = slot->bitmap.buffer; - uchar *dst = glyph_buffer.data(); - int h = slot->bitmap.rows; - while (h--) { -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - const quint32 *srcPixel = (const quint32 *)src; - quint32 *dstPixel = (quint32 *)dst; - for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++, srcPixel++, dstPixel++) { - const quint32 pixel = *srcPixel; - *dstPixel = qbswap(pixel); - } -#else - memcpy(dst, src, slot->bitmap.width * 4); -#endif - dst += slot->bitmap.pitch; - src += slot->bitmap.pitch; - } - info.linearAdvance = info.xOff = slot->bitmap.width; - } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) { - Q_ASSERT(format == Format_A8); - uchar *src = slot->bitmap.buffer; - uchar *dst = glyph_buffer.data(); - int h = slot->bitmap.rows; - int bytes = info.width; - while (h--) { - memcpy (dst, src, bytes); - dst += pitch; - src += slot->bitmap.pitch; - } - } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) { - Q_ASSERT(format == Format_A32); - convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_RGB); - } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) { - Q_ASSERT(format == Format_A32); - convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_VRGB); - } else { - qWarning("QFontEngine: Glyph rendered in unknown pixel_mode=%d", slot->bitmap.pixel_mode); - return nullptr; - } - - if (!g) { - g = new Glyph; - g->data = nullptr; - } - - g->linearAdvance = info.linearAdvance; - g->width = info.width; - g->height = info.height; - g->x = info.x; - g->y = info.y; - g->advance = info.xOff; - g->format = format; - delete [] g->data; - g->data = glyph_buffer.take(); - - if (set) - set->setGlyph(glyph, subPixelPosition, g); - - return g; -} - -QFontEngine::FaceId QFontEngineFT::faceId() const -{ - return face_id; -} - -QFontEngine::Properties QFontEngineFT::properties() const -{ - Properties p = freetype->properties(); - if (p.postscriptName.isEmpty()) { - p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8()); - } - - return freetype->properties(); -} - -QFixed QFontEngineFT::emSquareSize() const -{ - if (FT_IS_SCALABLE(freetype->face)) - return freetype->face->units_per_EM; - else - return freetype->face->size->metrics.y_ppem; -} - -bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const -{ - return ft_getSfntTable(freetype->face, tag, buffer, length); -} - -int QFontEngineFT::synthesized() const -{ - int s = 0; - if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)) - s = SynthesizedItalic; - if ((fontDef.weight >= QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD)) - s |= SynthesizedBold; - if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face)) - s |= SynthesizedStretch; - return s; -} - -QFixed QFontEngineFT::ascent() const -{ - QFixed v = QFixed::fromFixed(metrics.ascender); - if (scalableBitmapScaleFactor != 1) - v *= scalableBitmapScaleFactor; - return v; -} - -QFixed QFontEngineFT::capHeight() const -{ - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2); - if (os2 && os2->version >= 2) { - lockFace(); - QFixed answer = QFixed::fromFixed(FT_MulFix(os2->sCapHeight, freetype->face->size->metrics.y_scale)); - unlockFace(); - return answer; - } - return calculatedCapHeight(); -} - -QFixed QFontEngineFT::descent() const -{ - QFixed v = QFixed::fromFixed(-metrics.descender); - if (scalableBitmapScaleFactor != 1) - v *= scalableBitmapScaleFactor; - return v; -} - -QFixed QFontEngineFT::leading() const -{ - QFixed v = QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender); - if (scalableBitmapScaleFactor != 1) - v *= scalableBitmapScaleFactor; - return v; -} - -QFixed QFontEngineFT::xHeight() const -{ - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2); - if (os2 && os2->sxHeight) { - lockFace(); - QFixed answer = QFixed(os2->sxHeight * freetype->face->size->metrics.y_ppem) / emSquareSize(); - unlockFace(); - return answer; - } - - return QFontEngine::xHeight(); -} - -QFixed QFontEngineFT::averageCharWidth() const -{ - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2); - if (os2 && os2->xAvgCharWidth) { - lockFace(); - QFixed answer = QFixed(os2->xAvgCharWidth * freetype->face->size->metrics.x_ppem) / emSquareSize(); - unlockFace(); - return answer; - } - - return QFontEngine::averageCharWidth(); -} - -qreal QFontEngineFT::maxCharWidth() const -{ - QFixed max_advance = QFixed::fromFixed(metrics.max_advance); - if (scalableBitmapScaleFactor != 1) - max_advance *= scalableBitmapScaleFactor; - return max_advance.toReal(); -} - -QFixed QFontEngineFT::lineThickness() const -{ - return line_thickness; -} - -QFixed QFontEngineFT::underlinePosition() const -{ - return underline_position; -} - -void QFontEngineFT::doKerning(QGlyphLayout *g, QFontEngine::ShaperFlags flags) const -{ - if (!kerning_pairs_loaded) { - kerning_pairs_loaded = true; - lockFace(); - if (freetype->face->size->metrics.x_ppem != 0) { - QFixed scalingFactor = emSquareSize() / QFixed(freetype->face->size->metrics.x_ppem); - unlockFace(); - const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor); - } else { - unlockFace(); - } - } - - if (shouldUseDesignMetrics(flags) && !(fontDef.styleStrategy & QFont::ForceIntegerMetrics)) - flags |= DesignMetrics; - else - flags &= ~DesignMetrics; - - QFontEngine::doKerning(g, flags); -} - -static inline FT_Matrix QTransformToFTMatrix(const QTransform &matrix) -{ - FT_Matrix m; - - m.xx = FT_Fixed(matrix.m11() * 65536); - m.xy = FT_Fixed(-matrix.m21() * 65536); - m.yx = FT_Fixed(-matrix.m12() * 65536); - m.yy = FT_Fixed(matrix.m22() * 65536); - - return m; -} - -QFontEngineFT::QGlyphSet *QFontEngineFT::TransformedGlyphSets::findSet(const QTransform &matrix, const QFontDef &fontDef) -{ - FT_Matrix m = QTransformToFTMatrix(matrix); - - int i = 0; - for (; i < nSets; ++i) { - QGlyphSet *g = sets[i]; - if (!g) - break; - if (g->transformationMatrix.xx == m.xx - && g->transformationMatrix.xy == m.xy - && g->transformationMatrix.yx == m.yx - && g->transformationMatrix.yy == m.yy) { - - // found a match, move it to the front - moveToFront(i); - return g; - } - } - - // don't cache more than nSets transformations - if (i == nSets) - // reuse the last set - --i; - moveToFront(nSets - 1); - if (!sets[0]) - sets[0] = new QGlyphSet; - QGlyphSet *gs = sets[0]; - gs->clear(); - gs->transformationMatrix = m; - gs->outline_drawing = fontDef.pixelSize * fontDef.pixelSize * qAbs(matrix.determinant()) > QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; - Q_ASSERT(gs != nullptr); - - return gs; -} - -void QFontEngineFT::TransformedGlyphSets::moveToFront(int i) -{ - QGlyphSet *g = sets[i]; - while (i > 0) { - sets[i] = sets[i - 1]; - --i; - } - sets[0] = g; -} - - -QFontEngineFT::QGlyphSet *QFontEngineFT::loadGlyphSet(const QTransform &matrix) -{ - if (matrix.type() > QTransform::TxShear || !cacheEnabled) - return 0; - - // FT_Set_Transform only supports scalable fonts - if (!FT_IS_SCALABLE(freetype->face)) - return matrix.type() <= QTransform::TxTranslate ? &defaultGlyphSet : nullptr; - - return transformedGlyphSets.findSet(matrix, fontDef); -} - -void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) -{ - FT_Face face = lockFace(Unscaled); - FT_Set_Transform(face, nullptr, nullptr); - FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP); - - int left = face->glyph->metrics.horiBearingX; - int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width; - int top = face->glyph->metrics.horiBearingY; - int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height; - - QFixedPoint p; - p.x = 0; - p.y = 0; - - metrics->width = QFixed::fromFixed(right-left); - metrics->height = QFixed::fromFixed(top-bottom); - metrics->x = QFixed::fromFixed(left); - metrics->y = QFixed::fromFixed(-top); - metrics->xoff = QFixed::fromFixed(face->glyph->advance.x); - - if (!FT_IS_SCALABLE(freetype->face)) - QFreetypeFace::addBitmapToPath(face->glyph, p, path); - else - QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6); - - FT_Set_Transform(face, &freetype->matrix, nullptr); - unlockFace(); -} - -bool QFontEngineFT::supportsTransformation(const QTransform &transform) const -{ - return transform.type() <= QTransform::TxRotate; -} - -void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) -{ - if (!glyphs.numGlyphs) - return; - - if (FT_IS_SCALABLE(freetype->face)) { - QFontEngine::addOutlineToPath(x, y, glyphs, path, flags); - } else { - QVarLengthArray<QFixedPoint> positions; - QVarLengthArray<glyph_t> positioned_glyphs; - QTransform matrix; - matrix.translate(x, y); - getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions); - - FT_Face face = lockFace(Unscaled); - for (int gl = 0; gl < glyphs.numGlyphs; gl++) { - FT_UInt glyph = positioned_glyphs[gl]; - FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO); - QFreetypeFace::addBitmapToPath(face->glyph, positions[gl], path); - } - unlockFace(); - } -} - -void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, - QPainterPath *path, QTextItem::RenderFlags) -{ - FT_Face face = lockFace(Unscaled); - - for (int gl = 0; gl < numGlyphs; gl++) { - FT_UInt glyph = glyphs[gl]; - - FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP); - - FT_GlyphSlot g = face->glyph; - if (g->format != FT_GLYPH_FORMAT_OUTLINE) - continue; - if (embolden) - FT_GlyphSlot_Embolden(g); - if (obliquen) - FT_GlyphSlot_Oblique(g); - QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize); - } - unlockFace(); -} - -glyph_t QFontEngineFT::glyphIndex(uint ucs4) const -{ - glyph_t glyph = ucs4 < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[ucs4] : 0; - if (glyph == 0) { - FT_Face face = freetype->face; - glyph = FT_Get_Char_Index(face, ucs4); - if (glyph == 0) { - // Certain fonts don't have no-break space and tab, - // while we usually want to render them as space - if (ucs4 == QChar::Nbsp || ucs4 == QChar::Tabulation) { - glyph = FT_Get_Char_Index(face, QChar::Space); - } else if (freetype->symbol_map) { - // Symbol fonts can have more than one CMAPs, FreeType should take the - // correct one for us by default, so we always try FT_Get_Char_Index - // first. If it didn't work (returns 0), we will explicitly set the - // CMAP to symbol font one and try again. symbol_map is not always the - // correct one because in certain fonts like Wingdings symbol_map only - // contains PUA codepoints instead of the common ones. - FT_Set_Charmap(face, freetype->symbol_map); - glyph = FT_Get_Char_Index(face, ucs4); - FT_Set_Charmap(face, freetype->unicode_map); - } - } - if (ucs4 < QFreetypeFace::cmapCacheSize) - freetype->cmapCache[ucs4] = glyph; - } - - return glyph; -} - -bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, - QFontEngine::ShaperFlags flags) const -{ - Q_ASSERT(glyphs->numGlyphs >= *nglyphs); - if (*nglyphs < len) { - *nglyphs = len; - return false; - } - - int glyph_pos = 0; - if (freetype->symbol_map) { - FT_Face face = freetype->face; - QStringIterator it(str, str + len); - while (it.hasNext()) { - uint uc = it.next(); - glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0; - if ( !glyphs->glyphs[glyph_pos] ) { - // Symbol fonts can have more than one CMAPs, FreeType should take the - // correct one for us by default, so we always try FT_Get_Char_Index - // first. If it didn't work (returns 0), we will explicitly set the - // CMAP to symbol font one and try again. symbol_map is not always the - // correct one because in certain fonts like Wingdings symbol_map only - // contains PUA codepoints instead of the common ones. - glyph_t glyph = FT_Get_Char_Index(face, uc); - // Certain symbol fonts don't have no-break space (0xa0) and tab (0x9), - // while we usually want to render them as space - if (!glyph && (uc == 0xa0 || uc == 0x9)) { - uc = 0x20; - glyph = FT_Get_Char_Index(face, uc); - } - if (!glyph) { - FT_Set_Charmap(face, freetype->symbol_map); - glyph = FT_Get_Char_Index(face, uc); - FT_Set_Charmap(face, freetype->unicode_map); - } - glyphs->glyphs[glyph_pos] = glyph; - if (uc < QFreetypeFace::cmapCacheSize) - freetype->cmapCache[uc] = glyph; - } - ++glyph_pos; - } - } else { - FT_Face face = freetype->face; - QStringIterator it(str, str + len); - while (it.hasNext()) { - uint uc = it.next(); - glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0; - if (!glyphs->glyphs[glyph_pos]) { - { - redo: - glyph_t glyph = FT_Get_Char_Index(face, uc); - if (!glyph && (uc == 0xa0 || uc == 0x9)) { - uc = 0x20; - goto redo; - } - glyphs->glyphs[glyph_pos] = glyph; - if (uc < QFreetypeFace::cmapCacheSize) - freetype->cmapCache[uc] = glyph; - } - } - ++glyph_pos; - } - } - - *nglyphs = glyph_pos; - glyphs->numGlyphs = glyph_pos; - - if (!(flags & GlyphIndicesOnly)) - recalcAdvances(glyphs, flags); - - return true; -} - -bool QFontEngineFT::shouldUseDesignMetrics(QFontEngine::ShaperFlags flags) const -{ - if (!FT_IS_SCALABLE(freetype->face)) - return false; - - return default_hint_style == HintNone || default_hint_style == HintLight || (flags & DesignMetrics); -} - -QFixed QFontEngineFT::scaledBitmapMetrics(QFixed m) const -{ - return m * scalableBitmapScaleFactor; -} - -glyph_metrics_t QFontEngineFT::scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &t) const -{ - QTransform trans; - trans.setMatrix(t.m11(), t.m12(), t.m13(), - t.m21(), t.m22(), t.m23(), - 0, 0, t.m33()); - const qreal scaleFactor = scalableBitmapScaleFactor.toReal(); - trans.scale(scaleFactor, scaleFactor); - - QRectF rect(m.x.toReal(), m.y.toReal(), m.width.toReal(), m.height.toReal()); - QPointF offset(m.xoff.toReal(), m.yoff.toReal()); - - rect = trans.mapRect(rect); - offset = trans.map(offset); - - glyph_metrics_t metrics; - metrics.x = QFixed::fromReal(rect.x()); - metrics.y = QFixed::fromReal(rect.y()); - metrics.width = QFixed::fromReal(rect.width()); - metrics.height = QFixed::fromReal(rect.height()); - metrics.xoff = QFixed::fromReal(offset.x()); - metrics.yoff = QFixed::fromReal(offset.y()); - return metrics; -} - -void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const -{ - FT_Face face = nullptr; - bool design = shouldUseDesignMetrics(flags); - for (int i = 0; i < glyphs->numGlyphs; i++) { - Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : nullptr; - // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph - GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono; - if (g && g->format == acceptableFormat) { - glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance); - } else { - if (!face) - face = lockFace(); - g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyphs->glyphs[i], 0, Format_None, true); - if (g) - glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance); - else - glyphs->advances[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10) - : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round(); - if (!cacheEnabled && g != &emptyGlyph) - delete g; - } - - if (scalableBitmapScaleFactor != 1) - glyphs->advances[i] *= scalableBitmapScaleFactor; - } - if (face) - unlockFace(); - - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - for (int i = 0; i < glyphs->numGlyphs; ++i) - glyphs->advances[i] = glyphs->advances[i].round(); - } -} - -glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs) -{ - FT_Face face = nullptr; - - glyph_metrics_t overall; - // initialize with line height, we get the same behaviour on all platforms - if (!isScalableBitmap()) { - overall.y = -ascent(); - overall.height = ascent() + descent(); - } else { - overall.y = QFixed::fromFixed(-metrics.ascender); - overall.height = QFixed::fromFixed(metrics.ascender - metrics.descender); - } - - QFixed ymax = 0; - QFixed xmax = 0; - for (int i = 0; i < glyphs.numGlyphs; i++) { - Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : nullptr; - if (!g) { - if (!face) - face = lockFace(); - g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyphs.glyphs[i], 0, Format_None, true); - } - if (g) { - QFixed x = overall.xoff + glyphs.offsets[i].x + g->x; - QFixed y = overall.yoff + glyphs.offsets[i].y - g->y; - overall.x = qMin(overall.x, x); - overall.y = qMin(overall.y, y); - xmax = qMax(xmax, x + g->width); - ymax = qMax(ymax, y + g->height); - overall.xoff += g->advance; - if (!cacheEnabled && g != &emptyGlyph) - delete g; - } else { - int left = FLOOR(face->glyph->metrics.horiBearingX); - int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width); - int top = CEIL(face->glyph->metrics.horiBearingY); - int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height); - - QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left)); - QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top); - overall.x = qMin(overall.x, x); - overall.y = qMin(overall.y, y); - xmax = qMax(xmax, x + TRUNC(right - left)); - ymax = qMax(ymax, y + TRUNC(top - bottom)); - overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x))); - } - } - overall.height = qMax(overall.height, ymax - overall.y); - overall.width = xmax - overall.x; - - if (face) - unlockFace(); - - if (isScalableBitmap()) - overall = scaledBitmapMetrics(overall, QTransform()); - return overall; -} - -glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph) -{ - FT_Face face = nullptr; - glyph_metrics_t overall; - Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : nullptr; - if (!g) { - face = lockFace(); - g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyph, 0, Format_None, true); - } - if (g) { - overall.x = g->x; - overall.y = -g->y; - overall.width = g->width; - overall.height = g->height; - overall.xoff = g->advance; - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - overall.xoff = overall.xoff.round(); - if (!cacheEnabled && g != &emptyGlyph) - delete g; - } else { - int left = FLOOR(face->glyph->metrics.horiBearingX); - int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width); - int top = CEIL(face->glyph->metrics.horiBearingY); - int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height); - - overall.width = TRUNC(right-left); - overall.height = TRUNC(top-bottom); - overall.x = TRUNC(left); - overall.y = -TRUNC(top); - overall.xoff = TRUNC(ROUND(face->glyph->advance.x)); - } - if (face) - unlockFace(); - - if (isScalableBitmap()) - overall = scaledBitmapMetrics(overall, QTransform()); - return overall; -} - -glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix) -{ - return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None); -} - -glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format) -{ - Glyph *g = loadGlyphFor(glyph, subPixelPosition, format, matrix, true); - - glyph_metrics_t overall; - if (g) { - overall.x = g->x; - overall.y = -g->y; - overall.width = g->width; - overall.height = g->height; - overall.xoff = g->advance; - if (!cacheEnabled && g != &emptyGlyph) - delete g; - } else { - FT_Face face = lockFace(); - int left = FLOOR(face->glyph->metrics.horiBearingX); - int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width); - int top = CEIL(face->glyph->metrics.horiBearingY); - int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height); - - overall.width = TRUNC(right-left); - overall.height = TRUNC(top-bottom); - overall.x = TRUNC(left); - overall.y = -TRUNC(top); - overall.xoff = TRUNC(ROUND(face->glyph->advance.x)); - unlockFace(); - } - - if (isScalableBitmap()) - overall = scaledBitmapMetrics(overall, matrix); - return overall; -} - -static inline QImage alphaMapFromGlyphData(QFontEngineFT::Glyph *glyph, QFontEngine::GlyphFormat glyphFormat) -{ - if (glyph == nullptr || glyph->height == 0 || glyph->width == 0) - return QImage(); - - QImage::Format format = QImage::Format_Invalid; - int bytesPerLine = -1; - switch (glyphFormat) { - case QFontEngine::Format_Mono: - format = QImage::Format_Mono; - bytesPerLine = ((glyph->width + 31) & ~31) >> 3; - break; - case QFontEngine::Format_A8: - format = QImage::Format_Alpha8; - bytesPerLine = (glyph->width + 3) & ~3; - break; - case QFontEngine::Format_A32: - format = QImage::Format_RGB32; - bytesPerLine = glyph->width * 4; - break; - default: - Q_UNREACHABLE(); - }; - - QImage img(static_cast<const uchar *>(glyph->data), glyph->width, glyph->height, bytesPerLine, format); - if (format == QImage::Format_Mono) - img.setColor(1, QColor(Qt::white).rgba()); // Expands color table to 2 items; item 0 set to transparent. - return img; -} - -QFontEngine::Glyph *QFontEngineFT::glyphData(glyph_t glyphIndex, QFixed subPixelPosition, - QFontEngine::GlyphFormat neededFormat, const QTransform &t) -{ - Q_ASSERT(cacheEnabled); - - if (isBitmapFont()) - neededFormat = Format_Mono; - else if (neededFormat == Format_None && defaultFormat != Format_None) - neededFormat = defaultFormat; - else if (neededFormat == Format_None) - neededFormat = Format_A8; - - Glyph *glyph = loadGlyphFor(glyphIndex, subPixelPosition, neededFormat, t); - if (!glyph || !glyph->width || !glyph->height) - return nullptr; - - return glyph; -} - -static inline bool is2dRotation(const QTransform &t) -{ - return qFuzzyCompare(t.m11(), t.m22()) && qFuzzyCompare(t.m12(), -t.m21()) - && qFuzzyCompare(t.m11()*t.m22() - t.m12()*t.m21(), qreal(1.0)); -} - -QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, - QFixed subPixelPosition, - GlyphFormat format, - const QTransform &t, - bool fetchBoundingBox, - bool disableOutlineDrawing) -{ - QGlyphSet *glyphSet = loadGlyphSet(t); - if (glyphSet != nullptr && glyphSet->outline_drawing && !disableOutlineDrawing && !fetchBoundingBox) - return nullptr; - - Glyph *glyph = glyphSet != nullptr ? glyphSet->getGlyph(g, subPixelPosition) : nullptr; - if (!glyph || glyph->format != format || (!fetchBoundingBox && !glyph->data)) { - QScopedValueRollback<HintStyle> saved_default_hint_style(default_hint_style); - if (t.type() >= QTransform::TxScale && !is2dRotation(t)) - default_hint_style = HintNone; // disable hinting if the glyphs are transformed - - lockFace(); - FT_Matrix m = this->matrix; - FT_Matrix ftMatrix = glyphSet != nullptr ? glyphSet->transformationMatrix : QTransformToFTMatrix(t); - FT_Matrix_Multiply(&ftMatrix, &m); - freetype->matrix = m; - glyph = loadGlyph(glyphSet, g, subPixelPosition, format, false, disableOutlineDrawing); - unlockFace(); - } - - return glyph; -} - -QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition) -{ - return alphaMapForGlyph(g, subPixelPosition, QTransform()); -} - -QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t) -{ - const GlyphFormat neededFormat = antialias ? Format_A8 : Format_Mono; - - Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, false, true); - - QImage img = alphaMapFromGlyphData(glyph, neededFormat); - img = img.copy(); - - if (!cacheEnabled && glyph != &emptyGlyph) - delete glyph; - - return img; -} - -QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t) -{ - if (t.type() > QTransform::TxRotate) - return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t); - - const GlyphFormat neededFormat = Format_A32; - - Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, false, true); - - QImage img = alphaMapFromGlyphData(glyph, neededFormat); - img = img.copy(); - - if (!cacheEnabled && glyph != &emptyGlyph) - delete glyph; - - if (!img.isNull()) - return img; - - return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t); -} - -QImage QFontEngineFT::bitmapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t, const QColor &color) -{ - Q_UNUSED(color); - - Glyph *glyph = loadGlyphFor(g, subPixelPosition, defaultFormat, t); - if (glyph == nullptr) - return QImage(); - - QImage img; - if (defaultFormat == GlyphFormat::Format_ARGB) - img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_ARGB32_Premultiplied).copy(); - else if (defaultFormat == GlyphFormat::Format_Mono) - img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_Mono).copy(); - - if (!img.isNull() && (!t.isIdentity() || scalableBitmapScaleFactor != 1)) { - QTransform trans(t); - const qreal scaleFactor = scalableBitmapScaleFactor.toReal(); - trans.scale(scaleFactor, scaleFactor); - img = img.transformed(trans, Qt::SmoothTransformation); - } - - if (!cacheEnabled && glyph != &emptyGlyph) - delete glyph; - - return img; -} - -void QFontEngineFT::removeGlyphFromCache(glyph_t glyph) -{ - defaultGlyphSet.removeGlyphFromCache(glyph, 0); -} - -int QFontEngineFT::glyphCount() const -{ - int count = 0; - FT_Face face = lockFace(); - if (face) { - count = face->num_glyphs; - unlockFace(); - } - return count; -} - -FT_Face QFontEngineFT::lockFace(Scaling scale) const -{ - freetype->lock(); - FT_Face face = freetype->face; - if (scale == Unscaled) { - if (FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0) == 0) { - freetype->xsize = face->units_per_EM << 6; - freetype->ysize = face->units_per_EM << 6; - } - } else if (freetype->xsize != xsize || freetype->ysize != ysize) { - FT_Set_Char_Size(face, xsize, ysize, 0, 0); - freetype->xsize = xsize; - freetype->ysize = ysize; - } - if (freetype->matrix.xx != matrix.xx || - freetype->matrix.yy != matrix.yy || - freetype->matrix.xy != matrix.xy || - freetype->matrix.yx != matrix.yx) { - freetype->matrix = matrix; - FT_Set_Transform(face, &freetype->matrix, nullptr); - } - - return face; -} - -void QFontEngineFT::unlockFace() const -{ - freetype->unlock(); -} - -FT_Face QFontEngineFT::non_locked_face() const -{ - return freetype->face; -} - - -QFontEngineFT::QGlyphSet::QGlyphSet() - : outline_drawing(false) -{ - transformationMatrix.xx = 0x10000; - transformationMatrix.yy = 0x10000; - transformationMatrix.xy = 0; - transformationMatrix.yx = 0; - memset(fast_glyph_data, 0, sizeof(fast_glyph_data)); - fast_glyph_count = 0; -} - -QFontEngineFT::QGlyphSet::~QGlyphSet() -{ - clear(); -} - -void QFontEngineFT::QGlyphSet::clear() -{ - if (fast_glyph_count > 0) { - for (int i = 0; i < 256; ++i) { - if (fast_glyph_data[i]) { - delete fast_glyph_data[i]; - fast_glyph_data[i] = nullptr; - } - } - fast_glyph_count = 0; - } - qDeleteAll(glyph_data); - glyph_data.clear(); -} - -void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition) -{ - if (useFastGlyphData(index, subPixelPosition)) { - if (fast_glyph_data[index]) { - delete fast_glyph_data[index]; - fast_glyph_data[index] = nullptr; - if (fast_glyph_count > 0) - --fast_glyph_count; - } - } else { - delete glyph_data.take(GlyphAndSubPixelPosition(index, subPixelPosition)); - } -} - -void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph) -{ - if (useFastGlyphData(index, subPixelPosition)) { - if (!fast_glyph_data[index]) - ++fast_glyph_count; - fast_glyph_data[index] = glyph; - } else { - glyph_data.insert(GlyphAndSubPixelPosition(index, subPixelPosition), glyph); - } -} - -int QFontEngineFT::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) -{ - lockFace(); - bool hsubpixel = true; - int vfactor = 1; - int load_flags = loadFlags(nullptr, Format_A8, flags, hsubpixel, vfactor); - int result = freetype->getPointInOutline(glyph, load_flags, point, xpos, ypos, nPoints); - unlockFace(); - return result; -} - -bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe) -{ - if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype)) - return false; - - // Increase the reference of this QFreetypeFace since one more QFontEngineFT - // will be using it - freetype->ref.ref(); - - default_load_flags = fe->default_load_flags; - default_hint_style = fe->default_hint_style; - antialias = fe->antialias; - transform = fe->transform; - embolden = fe->embolden; - obliquen = fe->obliquen; - subpixelType = fe->subpixelType; - lcdFilterType = fe->lcdFilterType; - embeddedbitmap = fe->embeddedbitmap; - - return true; -} - -QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const -{ - QFontDef fontDef(this->fontDef); - fontDef.pixelSize = pixelSize; - QFontEngineFT *fe = new QFontEngineFT(fontDef); - if (!fe->initFromFontEngine(this)) { - delete fe; - return nullptr; - } else { - return fe; - } -} - -Qt::HANDLE QFontEngineFT::handle() const -{ - return non_locked_face(); -} - -QT_END_NAMESPACE - -#endif // QT_NO_FREETYPE diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h deleted file mode 100644 index 8019588bf5..0000000000 --- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h +++ /dev/null @@ -1,364 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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$ -** -****************************************************************************/ -#ifndef QFONTENGINE_FT_P_H -#define QFONTENGINE_FT_P_H -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "private/qfontengine_p.h" - -#ifndef QT_NO_FREETYPE - -#include <ft2build.h> -#include FT_FREETYPE_H - - -#ifndef Q_OS_WIN -#include <unistd.h> -#endif - -#include <qmutex.h> - -#include <string.h> - -QT_BEGIN_NAMESPACE - -class QFontEngineFTRawFont; -class QFontconfigDatabase; - -/* - * This class represents one font file on disk (like Arial.ttf) and is shared between all the font engines - * that show this font file (at different pixel sizes). - */ -class QFreetypeFace -{ -public: - void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing, QFixed *scalableBitmapScaleFactor); - QFontEngine::Properties properties() const; - bool getSfntTable(uint tag, uchar *buffer, uint *length) const; - - static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id, - const QByteArray &fontData = QByteArray()); - void release(const QFontEngine::FaceId &face_id); - - // locks the struct for usage. Any read/write operations require locking. - void lock() - { - _lock.lock(); - } - void unlock() - { - _lock.unlock(); - } - - FT_Face face; - int xsize; // 26.6 - int ysize; // 26.6 - FT_Matrix matrix; - FT_CharMap unicode_map; - FT_CharMap symbol_map; - - enum { cmapCacheSize = 0x200 }; - glyph_t cmapCache[cmapCacheSize]; - - int fsType() const; - - int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints); - - bool isScalableBitmap() const; - - static void addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale); - static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path); - -private: - friend class QFontEngineFT; - friend class QtFreetypeData; - friend struct QScopedPointerDeleter<QFreetypeFace>; - QFreetypeFace() = default; - ~QFreetypeFace() {} - void cleanup(); - QAtomicInt ref; - QRecursiveMutex _lock; - QByteArray fontData; - - QFontEngine::Holder hbFace; -}; - -class QFontEngineFT : public QFontEngine -{ -public: - struct GlyphInfo { - int linearAdvance; - unsigned short width; - unsigned short height; - short x; - short y; - short xOff; - short yOff; - }; - - struct GlyphAndSubPixelPosition - { - GlyphAndSubPixelPosition(glyph_t g, QFixed spp) : glyph(g), subPixelPosition(spp) {} - - bool operator==(const GlyphAndSubPixelPosition &other) const - { - return glyph == other.glyph && subPixelPosition == other.subPixelPosition; - } - - glyph_t glyph; - QFixed subPixelPosition; - }; - - struct QGlyphSet - { - QGlyphSet(); - ~QGlyphSet(); - FT_Matrix transformationMatrix; - bool outline_drawing; - - void removeGlyphFromCache(glyph_t index, QFixed subPixelPosition); - void clear(); - inline bool useFastGlyphData(glyph_t index, QFixed subPixelPosition) const { - return (index < 256 && subPixelPosition == 0); - } - inline Glyph *getGlyph(glyph_t index, QFixed subPixelPosition = 0) const; - void setGlyph(glyph_t index, QFixed spp, Glyph *glyph); - - inline bool isGlyphMissing(glyph_t index) const { return missing_glyphs.contains(index); } - inline void setGlyphMissing(glyph_t index) const { missing_glyphs.insert(index); } -private: - Q_DISABLE_COPY(QGlyphSet); - mutable QHash<GlyphAndSubPixelPosition, Glyph *> glyph_data; // maps from glyph index to glyph data - mutable QSet<glyph_t> missing_glyphs; - mutable Glyph *fast_glyph_data[256]; // for fast lookup of glyphs < 256 - mutable int fast_glyph_count; - }; - - QFontEngine::FaceId faceId() const override; - QFontEngine::Properties properties() const override; - QFixed emSquareSize() const override; - bool supportsSubPixelPositions() const override - { - return default_hint_style == HintLight || - default_hint_style == HintNone; - } - - bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override; - int synthesized() const override; - - QFixed ascent() const override; - QFixed capHeight() const override; - QFixed descent() const override; - QFixed leading() const override; - QFixed xHeight() const override; - QFixed averageCharWidth() const override; - - qreal maxCharWidth() const override; - QFixed lineThickness() const override; - QFixed underlinePosition() const override; - - glyph_t glyphIndex(uint ucs4) const override; - void doKerning(QGlyphLayout *, ShaperFlags) const override; - - void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override; - - bool supportsTransformation(const QTransform &transform) const override; - - void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags flags) override; - void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, - QPainterPath *path, QTextItem::RenderFlags flags) override; - - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; - - glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; - glyph_metrics_t boundingBox(glyph_t glyph) override; - glyph_metrics_t boundingBox(glyph_t glyph, const QTransform &matrix) override; - - void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags flags) const override; - QImage alphaMapForGlyph(glyph_t g) override { return alphaMapForGlyph(g, 0); } - QImage alphaMapForGlyph(glyph_t, QFixed) override; - QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override; - QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override; - QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override; - glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, - QFixed subPixelPosition, - const QTransform &matrix, - QFontEngine::GlyphFormat format) override; - Glyph *glyphData(glyph_t glyph, QFixed subPixelPosition, - GlyphFormat neededFormat, const QTransform &t) override; - bool hasInternalCaching() const override { return cacheEnabled; } - bool expectsGammaCorrectedBlending() const override; - - void removeGlyphFromCache(glyph_t glyph) override; - int glyphMargin(QFontEngine::GlyphFormat /* format */) override { return 0; } - - int glyphCount() const override; - - enum Scaling { - Scaled, - Unscaled - }; - FT_Face lockFace(Scaling scale = Scaled) const; - void unlockFace() const; - - FT_Face non_locked_face() const; - - inline bool drawAntialiased() const { return antialias; } - inline bool invalid() const { return xsize == 0 && ysize == 0; } - inline bool isBitmapFont() const { return defaultFormat == Format_Mono; } - inline bool isScalableBitmap() const { return freetype->isScalableBitmap(); } - - inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const - { return loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyph, subPixelPosition, format, fetchMetricsOnly, disableOutlineDrawing); } - Glyph *loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const; - Glyph *loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format, const QTransform &t, bool fetchBoundingBox = false, bool disableOutlineDrawing = false); - - QGlyphSet *loadGlyphSet(const QTransform &matrix); - - QFontEngineFT(const QFontDef &fd); - virtual ~QFontEngineFT(); - - bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None, - const QByteArray &fontData = QByteArray()); - bool init(FaceId faceId, bool antialias, GlyphFormat format, - QFreetypeFace *freetypeFace); - - int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) override; - - void setQtDefaultHintStyle(QFont::HintingPreference hintingPreference); - void setDefaultHintStyle(HintStyle style) override; - - QFontEngine *cloneWithSize(qreal pixelSize) const override; - Qt::HANDLE handle() const override; - bool initFromFontEngine(const QFontEngineFT *fontEngine); - - HintStyle defaultHintStyle() const { return default_hint_style; } - - static QFontEngineFT *create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData = QByteArray()); - static QFontEngineFT *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); - -protected: - - QFreetypeFace *freetype; - mutable int default_load_flags; - HintStyle default_hint_style; - bool antialias; - bool transform; - bool embolden; - bool obliquen; - SubpixelAntialiasingType subpixelType; - int lcdFilterType; - bool embeddedbitmap; - bool cacheEnabled; - bool forceAutoHint; - bool stemDarkeningDriver; - -private: - friend class QFontEngineFTRawFont; - friend class QFontconfigDatabase; - friend class QFreeTypeFontDatabase; - friend class QFontEngineMultiFontConfig; - - int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const; - bool shouldUseDesignMetrics(ShaperFlags flags) const; - QFixed scaledBitmapMetrics(QFixed m) const; - glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &matrix) const; - - GlyphFormat defaultFormat; - FT_Matrix matrix; - - struct TransformedGlyphSets { - enum { nSets = 10 }; - QGlyphSet *sets[nSets]; - - QGlyphSet *findSet(const QTransform &matrix, const QFontDef &fontDef); - TransformedGlyphSets() { std::fill(&sets[0], &sets[nSets], nullptr); } - ~TransformedGlyphSets() { qDeleteAll(&sets[0], &sets[nSets]); } - private: - void moveToFront(int i); - Q_DISABLE_COPY(TransformedGlyphSets); - }; - TransformedGlyphSets transformedGlyphSets; - mutable QGlyphSet defaultGlyphSet; - - QFontEngine::FaceId face_id; - - int xsize; - int ysize; - - QFixed line_thickness; - QFixed underline_position; - - FT_Size_Metrics metrics; - mutable bool kerning_pairs_loaded; - QFixed scalableBitmapScaleFactor; -}; - -Q_DECLARE_TYPEINFO(QFontEngineFT::QGlyphSet, Q_MOVABLE_TYPE); - - -inline uint qHash(const QFontEngineFT::GlyphAndSubPixelPosition &g) -{ - return (g.glyph << 8) | (g.subPixelPosition * 10).round().toInt(); -} - -inline QFontEngineFT::Glyph *QFontEngineFT::QGlyphSet::getGlyph(glyph_t index, QFixed subPixelPosition) const -{ - if (useFastGlyphData(index, subPixelPosition)) - return fast_glyph_data[index]; - return glyph_data.value(GlyphAndSubPixelPosition(index, subPixelPosition)); -} - -extern FT_Library qt_getFreetype(); - -QT_END_NAMESPACE - -#endif // QT_NO_FREETYPE - -#endif // QFONTENGINE_FT_P_H diff --git a/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase.cpp b/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase.cpp deleted file mode 100644 index 25c10fbd3c..0000000000 --- a/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/**************************************************************************** -** -** 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 "qfreetypefontdatabase_p.h" - -#include <QtGui/private/qguiapplication_p.h> -#include <qpa/qplatformscreen.h> - -#include <QtCore/QFile> -#include <QtCore/QLibraryInfo> -#include <QtCore/QDir> -#include <QtCore/QtEndian> - -#undef QT_NO_FREETYPE -#include <QtFontDatabaseSupport/private/qfontengine_ft_p.h> - -#include <ft2build.h> -#include FT_TRUETYPE_TABLES_H -#include FT_ERRORS_H - -QT_BEGIN_NAMESPACE - -void QFreeTypeFontDatabase::populateFontDatabase() -{ - QString fontpath = fontDir(); - QDir dir(fontpath); - - if (!dir.exists()) { - qWarning("QFontDatabase: Cannot find font directory %s.\n" - "Note that Qt no longer ships fonts. Deploy some (from https://dejavu-fonts.github.io/ for example) or switch to fontconfig.", - qPrintable(fontpath)); - return; - } - - QStringList nameFilters; - nameFilters << QLatin1String("*.ttf") - << QLatin1String("*.ttc") - << QLatin1String("*.pfa") - << QLatin1String("*.pfb") - << QLatin1String("*.otf"); - - const auto fis = dir.entryInfoList(nameFilters, QDir::Files); - for (const QFileInfo &fi : fis) { - const QByteArray file = QFile::encodeName(fi.absoluteFilePath()); - QFreeTypeFontDatabase::addTTFile(QByteArray(), file); - } -} - -QFontEngine *QFreeTypeFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPtr) -{ - FontFile *fontfile = static_cast<FontFile *>(usrPtr); - QFontEngine::FaceId faceId; - faceId.filename = QFile::encodeName(fontfile->fileName); - faceId.index = fontfile->indexValue; - - return QFontEngineFT::create(fontDef, faceId); -} - -QFontEngine *QFreeTypeFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, - QFont::HintingPreference hintingPreference) -{ - return QFontEngineFT::create(fontData, pixelSize, hintingPreference); -} - -QStringList QFreeTypeFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) -{ - return QFreeTypeFontDatabase::addTTFile(fontData, fileName.toLocal8Bit()); -} - -void QFreeTypeFontDatabase::releaseHandle(void *handle) -{ - FontFile *file = static_cast<FontFile *>(handle); - delete file; -} - -extern FT_Library qt_getFreetype(); - -QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) -{ - 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 << ':' << Qt::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; - - bool fixedPitch = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH); - 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_MS_SYMBOL) { - writingSystems.setSupported(QFontDatabase::Symbol); - break; - } - } - - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); - if (os2) { - quint32 unicodeRange[4] = { - quint32(os2->ulUnicodeRange1), - quint32(os2->ulUnicodeRange2), - quint32(os2->ulUnicodeRange3), - quint32(os2->ulUnicodeRange4) - }; - quint32 codePageRange[2] = { - quint32(os2->ulCodePageRange1), - quint32(os2->ulCodePageRange2) - }; - - writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - - if (os2->usWeightClass) { - weight = QPlatformFontDatabase::weightFromInteger(os2->usWeightClass); - } else if (os2->panose[2]) { - int w = os2->panose[2]; - if (w <= 1) - weight = QFont::Thin; - else if (w <= 2) - weight = QFont::ExtraLight; - else if (w <= 3) - weight = QFont::Light; - else if (w <= 5) - weight = QFont::Normal; - else if (w <= 6) - weight = QFont::Medium; - else if (w <= 7) - weight = QFont::DemiBold; - else if (w <= 8) - weight = QFont::Bold; - else if (w <= 9) - weight = QFont::ExtraBold; - else if (w <= 10) - weight = QFont::Black; - } - } - - QString family = QString::fromLatin1(face->family_name); - FontFile *fontFile = new FontFile; - fontFile->fileName = QFile::decodeName(file); - fontFile->indexValue = index; - - QFont::Stretch stretch = QFont::Unstretched; - - registerFont(family,QString::fromLatin1(face->style_name),QString(),weight,style,stretch,true,true,0,fixedPitch,writingSystems,fontFile); - - families.append(family); - - FT_Done_Face(face); - ++index; - } while (index < numFaces); - return families; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase_p.h b/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase_p.h deleted file mode 100644 index 0b2956b16e..0000000000 --- a/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase_p.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QFREETYPEFONTDATABASE_H -#define QFREETYPEFONTDATABASE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <qpa/qplatformfontdatabase.h> -#include <QtCore/QByteArray> -#include <QtCore/QString> - -QT_BEGIN_NAMESPACE - -struct FontFile -{ - QString fileName; - int indexValue; -}; - -class QFreeTypeFontDatabase : public QPlatformFontDatabase -{ -public: - void populateFontDatabase() override; - QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; - QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; - QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) override; - void releaseHandle(void *handle) override; - - static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file); -}; - -QT_END_NAMESPACE - -#endif // QFREETYPEFONTDATABASE_H diff --git a/src/platformsupport/fontdatabases/genericunix/genericunix.pri b/src/platformsupport/fontdatabases/genericunix/genericunix.pri deleted file mode 100644 index e9db6c07e2..0000000000 --- a/src/platformsupport/fontdatabases/genericunix/genericunix.pri +++ /dev/null @@ -1 +0,0 @@ -HEADERS += $$PWD/qgenericunixfontdatabase_p.h diff --git a/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h b/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h deleted file mode 100644 index ccf5ad6d13..0000000000 --- a/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QGENERICUNIXFONTDATABASE_H -#define QGENERICUNIXFONTDATABASE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> - -#if QT_CONFIG(fontconfig) -#include <QtFontDatabaseSupport/private/qfontconfigdatabase_p.h> -typedef QFontconfigDatabase QGenericUnixFontDatabase; -#else -#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h> -typedef QFreeTypeFontDatabase QGenericUnixFontDatabase; -#endif //Q_FONTCONFIGDATABASE - -#endif // QGENERICUNIXFONTDATABASE_H diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri deleted file mode 100644 index 95b9926e65..0000000000 --- a/src/platformsupport/fontdatabases/mac/coretext.pri +++ /dev/null @@ -1,15 +0,0 @@ -HEADERS += $$PWD/qcoretextfontdatabase_p.h $$PWD/qfontengine_coretext_p.h -OBJECTIVE_SOURCES += $$PWD/qfontengine_coretext.mm $$PWD/qcoretextfontdatabase.mm - -LIBS_PRIVATE += \ - -framework CoreFoundation \ - -framework CoreGraphics \ - -framework CoreText \ - -framework Foundation - -macos: \ - LIBS_PRIVATE += -framework AppKit -else: \ - LIBS_PRIVATE += -framework UIKit - -CONFIG += watchos_coretext diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm deleted file mode 100644 index 894919a1c8..0000000000 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ /dev/null @@ -1,797 +0,0 @@ -/**************************************************************************** -** -** 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 "qglobal.h" - -#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 <QtCore/qelapsedtimer.h> - -#include "qcoretextfontdatabase_p.h" -#include "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 *) }; - -QCoreTextFontDatabase::QCoreTextFontDatabase() - : m_hasPopulatedAliases(false) -{ -} - -QCoreTextFontDatabase::~QCoreTextFontDatabase() -{ - for (CTFontDescriptorRef ref : qAsConst(m_systemFontDescriptors)) - CFRelease(ref); -} - -void QCoreTextFontDatabase::populateFontDatabase() -{ - qCDebug(lcQpaFonts) << "Populating font database..."; - QElapsedTimer elapsed; - if (lcQpaFonts().isDebugEnabled()) - elapsed.start(); - - QCFType<CFArrayRef> familyNames = CTFontManagerCopyAvailableFontFamilyNames(); - for (NSString *familyName in familyNames.as<const NSArray *>()) - QPlatformFontDatabase::registerFontFamily(QString::fromNSString(familyName)); - - qCDebug(lcQpaFonts) << "Populating available families took" << elapsed.restart() << "ms"; - - // Force creating the theme fonts to get the descriptors in m_systemFontDescriptors - if (m_themeFonts.isEmpty()) - (void)themeFonts(); - - qCDebug(lcQpaFonts) << "Resolving theme fonts took" << elapsed.restart() << "ms"; - - Q_FOREACH (CTFontDescriptorRef fontDesc, m_systemFontDescriptors) - populateFromDescriptor(fontDesc); - - qCDebug(lcQpaFonts) << "Populating system descriptors took" << elapsed.restart() << "ms"; - - Q_ASSERT(!m_hasPopulatedAliases); -} - -bool QCoreTextFontDatabase::populateFamilyAliases(const QString &missingFamily) -{ -#if defined(Q_OS_MACOS) - if (m_hasPopulatedAliases) - return false; - - // There's no API to go from a localized family name to its non-localized - // name, so we have to resort to enumerating all the available fonts and - // doing a reverse lookup. - - qCDebug(lcQpaFonts) << "Populating family aliases..."; - QElapsedTimer elapsed; - elapsed.start(); - - QString nonLocalizedMatch; - QCFType<CFArrayRef> familyNames = CTFontManagerCopyAvailableFontFamilyNames(); - NSFontManager *fontManager = NSFontManager.sharedFontManager; - for (NSString *familyName in familyNames.as<const NSArray *>()) { - NSString *localizedFamilyName = [fontManager localizedNameForFamily:familyName face:nil]; - if (![localizedFamilyName isEqual:familyName]) { - QString nonLocalizedFamily = QString::fromNSString(familyName); - QString localizedFamily = QString::fromNSString(localizedFamilyName); - QPlatformFontDatabase::registerAliasToFontFamily(nonLocalizedFamily, localizedFamily); - if (localizedFamily == missingFamily) - nonLocalizedMatch = nonLocalizedFamily; - } - } - m_hasPopulatedAliases = true; - - if (lcQpaFonts().isWarningEnabled()) { - QString warningMessage; - QDebug msg(&warningMessage); - - msg << "Populating font family aliases took" << elapsed.restart() << "ms."; - if (!nonLocalizedMatch.isNull()) - msg << "Replace uses of" << missingFamily << "with its non-localized name" << nonLocalizedMatch; - else - msg << "Replace uses of missing font family" << missingFamily << "with one that exists"; - msg << "to avoid this cost."; - - qCWarning(lcQpaFonts) << qPrintable(warningMessage); - } - - return true; -#else - Q_UNUSED(missingFamily); - 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) { - qCWarning(lcQpaFonts) << "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)); - - // 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 - -CTFontDescriptorRef descriptorForFamily(const QString &familyName) -{ - return CTFontDescriptorCreateWithAttributes(CFDictionaryRef(@{ - (id)kCTFontFamilyNameAttribute: familyName.toNSString() - })); -} - -CTFontDescriptorRef descriptorForFamily(const char *familyName) -{ - return descriptorForFamily(QString::fromLatin1(familyName)); -} - -CFArrayRef fallbacksForDescriptor(CTFontDescriptorRef descriptor) -{ - QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr); - if (!font) { - qCWarning(lcQpaFonts) << "Failed to create fallback font for" << descriptor; - return nullptr; - } - - CFArrayRef cascadeList = CFArrayRef(CTFontCopyDefaultCascadeListForLanguages(font, - (CFArrayRef)[NSUserDefaults.standardUserDefaults stringArrayForKey:@"AppleLanguages"])); - - if (!cascadeList) { - qCWarning(lcQpaFonts) << "Failed to create fallback cascade list for" << descriptor; - return nullptr; - } - - return cascadeList; -} - -CFArrayRef QCoreTextFontDatabase::fallbacksForFamily(const QString &family) -{ - if (family.isEmpty()) - return nullptr; - - QCFType<CTFontDescriptorRef> fontDescriptor = descriptorForFamily(family); - if (!fontDescriptor) { - qCWarning(lcQpaFonts) << "Failed to create fallback font descriptor for" << family; - return nullptr; - } - - // If the font is not available we want to fall back to the style hint. - // By creating a matching font descriptor we can verify whether the font - // is available or not, and avoid CTFontCreateWithFontDescriptor picking - // a default font for us based on incomplete information. - fontDescriptor = CTFontDescriptorCreateMatchingFontDescriptor(fontDescriptor, 0); - if (!fontDescriptor) - return nullptr; - - return fallbacksForDescriptor(fontDescriptor); -} - -CTFontDescriptorRef descriptorForFontType(CTFontUIFontType uiType) -{ - static const CGFloat kDefaultSizeForRequestedUIType = 0.0; - QCFType<CTFontRef> ctFont = CTFontCreateUIFontForLanguage( - uiType, kDefaultSizeForRequestedUIType, nullptr); - return CTFontCopyFontDescriptor(ctFont); -} - -CTFontDescriptorRef descriptorForStyle(QFont::StyleHint styleHint) -{ - switch (styleHint) { - case QFont::SansSerif: return descriptorForFamily("Helvetica"); - case QFont::Serif: return descriptorForFamily("Times New Roman"); - case QFont::Monospace: return descriptorForFamily("Menlo"); -#ifdef Q_OS_MACOS - case QFont::Cursive: return descriptorForFamily("Apple Chancery"); -#endif - case QFont::Fantasy: return descriptorForFamily("Zapfino"); - case QFont::TypeWriter: return descriptorForFamily("American Typewriter"); - case QFont::AnyStyle: Q_FALLTHROUGH(); - case QFont::System: return descriptorForFontType(kCTFontUIFontSystem); - default: return nullptr; // No matching font on this platform - } -} - -QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const -{ - Q_UNUSED(style); - - qCDebug(lcQpaFonts).nospace() << "Resolving fallbacks families for" - << (!family.isEmpty() ? qPrintable(QLatin1String(" family '%1' with").arg(family)) : "") - << " style hint " << styleHint; - - QMacAutoReleasePool pool; - - QStringList fallbackList; - - QCFType<CFArrayRef> fallbackFonts = fallbacksForFamily(family); - if (!fallbackFonts || !CFArrayGetCount(fallbackFonts)) { - // We were not able to find a fallback for the specific family, - // or the family was empty, so we fall back to the style hint. - if (!family.isEmpty()) - qCDebug(lcQpaFonts) << "No fallbacks found. Using style hint instead"; - - if (QCFType<CTFontDescriptorRef> styleDescriptor = descriptorForStyle(styleHint)) { - CFMutableArrayRef tmp = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(tmp, styleDescriptor); - QCFType<CFArrayRef> styleFallbacks = fallbacksForDescriptor(styleDescriptor); - CFArrayAppendArray(tmp, styleFallbacks, CFRangeMake(0, CFArrayGetCount(styleFallbacks))); - fallbackFonts = tmp; - } - } - - if (!fallbackFonts) - return fallbackList; - - const int numberOfFallbacks = CFArrayGetCount(fallbackFonts); - for (int i = 0; i < numberOfFallbacks; ++i) { - auto fallbackDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fallbackFonts, i)); - auto fallbackFamilyName = QCFString(CTFontDescriptorCopyAttribute(fallbackDescriptor, kCTFontFamilyNameAttribute)); - - if (!isFamilyPopulated(fallbackFamilyName)) { - // We need to populate, or at least register the fallback fonts, - // otherwise the Qt font database may not know they exist. - if (isPrivateFontFamily(fallbackFamilyName)) - const_cast<QCoreTextFontDatabase *>(this)->populateFromDescriptor(fallbackDescriptor); - else - registerFontFamily(fallbackFamilyName); - } - - fallbackList.append(fallbackFamilyName); - } - - // Some fallback fonts will have have an order in the list returned - // by Core Text that would indicate they should be preferred for e.g. - // Arabic, or Emoji, while in reality only supporting a tiny subset - // of the required glyphs, or representing them by question marks. - // Move these to the end, so that the proper fonts are preferred. - for (const char *family : { ".Apple Symbols Fallback", ".Noto Sans Universal" }) { - int index = fallbackList.indexOf(QLatin1String(family)); - if (index >= 0) - fallbackList.move(index, fallbackList.size() - 1); - } - -#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")); -#endif - - extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &); - fallbackList = qt_sort_families_by_writing_system(script, fallbackList); - - qCDebug(lcQpaFonts).nospace() << "Fallback families ordered by script " << script << ": " << fallbackList; - - return fallbackList; -} - -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 - - // macOS default case and iOS fallback case - return descriptorForFontType(fontTypeFromTheme(f)); -} - -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<CTFontDescriptorRef> systemFont = descriptorForFontType(kCTFontUIFontSystem); - defaultFontName = QCFString(CTFontDescriptorCopyAttribute(systemFont, kCTFontFamilyNameAttribute)); - } - - 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 - diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h deleted file mode 100644 index eebb3eb964..0000000000 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QCORETEXTFONTDATABASE_H -#define QCORETEXTFONTDATABASE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <qglobal.h> - -#include <qpa/qplatformfontdatabase.h> -#include <qpa/qplatformtheme.h> -#include <private/qcore_mac_p.h> - -Q_FORWARD_DECLARE_CF_TYPE(CTFontDescriptor); -Q_FORWARD_DECLARE_CF_TYPE(CTFont); - -Q_DECLARE_METATYPE(QCFType<CGFontRef>); -Q_DECLARE_METATYPE(QCFType<CFURLRef>); - -QT_BEGIN_NAMESPACE - -class QCoreTextFontDatabase : public QPlatformFontDatabase -{ -public: - QCoreTextFontDatabase(); - ~QCoreTextFontDatabase(); - void populateFontDatabase() override; - bool populateFamilyAliases(const QString &missingFamily) override; - void populateFamily(const QString &familyName) override; - void invalidate() override; - - QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override; - QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) override; - void releaseHandle(void *handle) override; - bool isPrivateFontFamily(const QString &family) const override; - QFont defaultFont() const override; - bool fontsAlwaysScalable() const override; - QList<int> standardSizes() const override; - - // For iOS and OS X platform themes - QFont *themeFont(QPlatformTheme::Font) const; - const QHash<QPlatformTheme::Font, QFont *> &themeFonts() const; - -protected: - mutable QSet<CTFontDescriptorRef> m_systemFontDescriptors; - -private: - void populateFromDescriptor(CTFontDescriptorRef font, const QString &familyName = QString()); - static CFArrayRef fallbacksForFamily(const QString &family); - - mutable QString defaultFontName; - - mutable QHash<QPlatformTheme::Font, QFont *> m_themeFonts; - bool m_hasPopulatedAliases; -}; - -// Split out into separate template class so that the compiler doesn't have -// to generate code for each override in QCoreTextFontDatabase for each T. - -template <class T> -class QCoreTextFontDatabaseEngineFactory : public QCoreTextFontDatabase -{ -public: - QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; - QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; -}; - -QT_END_NAMESPACE - -#endif // QCORETEXTFONTDATABASE_H diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm deleted file mode 100644 index 30c80ebd86..0000000000 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ /dev/null @@ -1,1055 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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 "qfontengine_coretext_p.h" - -#include <qpa/qplatformfontdatabase.h> -#include <QtCore/qendian.h> -#if QT_CONFIG(settings) -#include <QtCore/qsettings.h> -#endif -#include <QtCore/qoperatingsystemversion.h> -#include <private/qcoregraphics_p.h> -#include <private/qimage_p.h> - -#include <cmath> - -#if defined(Q_OS_MACOS) -#import <AppKit/AppKit.h> -#endif - -#if defined(QT_PLATFORM_UIKIT) -#import <UIKit/UIKit.h> -#endif - -// These are available cross platform, exported as kCTFontWeightXXX from CoreText.framework, -// but they are not documented and are not in public headers so are private API and exposed -// only through the NSFontWeightXXX and UIFontWeightXXX aliases in AppKit and UIKit (rdar://26109857) -#if defined(Q_OS_MACOS) -#define kCTFontWeightUltraLight NSFontWeightUltraLight -#define kCTFontWeightThin NSFontWeightThin -#define kCTFontWeightLight NSFontWeightLight -#define kCTFontWeightRegular NSFontWeightRegular -#define kCTFontWeightMedium NSFontWeightMedium -#define kCTFontWeightSemibold NSFontWeightSemibold -#define kCTFontWeightBold NSFontWeightBold -#define kCTFontWeightHeavy NSFontWeightHeavy -#define kCTFontWeightBlack NSFontWeightBlack -#elif defined(QT_PLATFORM_UIKIT) -#define kCTFontWeightUltraLight UIFontWeightUltraLight -#define kCTFontWeightThin UIFontWeightThin -#define kCTFontWeightLight UIFontWeightLight -#define kCTFontWeightRegular UIFontWeightRegular -#define kCTFontWeightMedium UIFontWeightMedium -#define kCTFontWeightSemibold UIFontWeightSemibold -#define kCTFontWeightBold UIFontWeightBold -#define kCTFontWeightHeavy UIFontWeightHeavy -#define kCTFontWeightBlack UIFontWeightBlack -#endif - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") - -static float SYNTHETIC_ITALIC_SKEW = std::tan(14.f * std::acos(0.f) / 90.f); - -bool QCoreTextFontEngine::ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length) -{ - CTFontRef ctfont = *(CTFontRef *)user_data; - - QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0); - if (!table) - return false; - - CFIndex tableLength = CFDataGetLength(table); - if (buffer && int(*length) >= tableLength) - CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); - *length = tableLength; - Q_ASSERT(int(*length) > 0); - return true; -} - -QFont::Weight QCoreTextFontEngine::qtWeightFromCFWeight(float value) -{ -#define COMPARE_WEIGHT_DISTANCE(ct_weight, qt_weight) \ - { \ - float d; \ - if ((d = qAbs(value - ct_weight)) < distance) { \ - distance = d; \ - ret = qt_weight; \ - } \ - } - - float distance = qAbs(value - kCTFontWeightBlack); - QFont::Weight ret = QFont::Black; - - // Compare distance to system weight to find the closest match. - // (Note: Must go from high to low, so that midpoints are rounded up) - COMPARE_WEIGHT_DISTANCE(kCTFontWeightHeavy, QFont::ExtraBold); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightBold, QFont::Bold); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightSemibold, QFont::DemiBold); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightMedium, QFont::Medium); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightRegular, QFont::Normal); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightLight, QFont::Light); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightThin, QFont::ExtraLight); - COMPARE_WEIGHT_DISTANCE(kCTFontWeightUltraLight, QFont::Thin); - -#undef COMPARE_WEIGHT_DISTANCE - - return ret; -} - -CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef) -{ - CGAffineTransform transform = CGAffineTransformIdentity; - if (fontDef.stretch && fontDef.stretch != 100) - transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); - return transform; -} - -// Keeps font data alive until engine is disposed -class QCoreTextRawFontEngine : public QCoreTextFontEngine -{ -public: - QCoreTextRawFontEngine(CGFontRef font, const QFontDef &def, const QByteArray &fontData) - : QCoreTextFontEngine(font, def) - , m_fontData(fontData) - {} - QFontEngine *cloneWithSize(qreal pixelSize) const - { - QFontDef newFontDef = fontDef; - newFontDef.pixelSize = pixelSize; - newFontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); - - return new QCoreTextRawFontEngine(cgFont, newFontDef, m_fontData); - } - QByteArray m_fontData; -}; - -QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - Q_UNUSED(hintingPreference); - - QCFType<CFDataRef> fontDataReference = fontData.toRawCFData(); - QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithCFData(fontDataReference); - - // Note: CTFontCreateWithGraphicsFont (which we call from the QCoreTextFontEngine - // constructor) has a bug causing it to retain the CGFontRef but never release it. - // The result is that we are leaking the CGFont, CGDataProvider, and CGData, but - // as the CGData is created from the raw QByteArray data, which we deref in the - // subclass above during destruction, we're at least not leaking the font data, - // (unless CoreText copies it internally). http://stackoverflow.com/questions/40805382/ - QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider); - - if (!cgFont) { - qWarning("QCoreTextFontEngine::create: CGFontCreateWithDataProvider failed"); - return nullptr; - } - - QFontDef def; - def.pixelSize = pixelSize; - def.pointSize = pixelSize * 72.0 / qt_defaultDpi(); - return new QCoreTextRawFontEngine(cgFont, def, fontData); -} - -QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) - : QCoreTextFontEngine(def) -{ - ctfont = QCFType<CTFontRef>::constructFromGet(font); - cgFont = CTFontCopyGraphicsFont(font, nullptr); - init(); -} - -QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def) - : QCoreTextFontEngine(def) -{ - cgFont = QCFType<CGFontRef>::constructFromGet(font); - ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, nullptr); - init(); -} - -QCoreTextFontEngine::QCoreTextFontEngine(const QFontDef &def) - : QFontEngine(Mac) -{ - fontDef = def; - transform = qt_transform_from_fontdef(fontDef); -} - -QCoreTextFontEngine::~QCoreTextFontEngine() -{ -} - -void QCoreTextFontEngine::init() -{ - Q_ASSERT(ctfont); - Q_ASSERT(cgFont); - - face_id.index = 0; - QCFString name = CTFontCopyName(ctfont, kCTFontUniqueNameKey); - face_id.filename = QString::fromCFString(name).toUtf8(); - - QCFString family = CTFontCopyFamilyName(ctfont); - fontDef.family = family; - - QCFString styleName = (CFStringRef) CTFontCopyAttribute(ctfont, kCTFontStyleNameAttribute); - fontDef.styleName = styleName; - - synthesisFlags = 0; - CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont); - - if (traits & kCTFontColorGlyphsTrait) - glyphFormat = QFontEngine::Format_ARGB; - else if (shouldSmoothFont() && fontSmoothing() == FontSmoothing::Subpixel) - glyphFormat = QFontEngine::Format_A32; - else - glyphFormat = QFontEngine::Format_A8; - - if (traits & kCTFontItalicTrait) - fontDef.style = QFont::StyleItalic; - - static const auto getTraitValue = [](CFDictionaryRef allTraits, CFStringRef trait) -> float { - if (CFDictionaryContainsKey(allTraits, trait)) { - CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait); - float v = 0; - CFNumberGetValue(traitNum, kCFNumberFloatType, &v); - return v; - } - return 0; - }; - - QCFType<CFDictionaryRef> allTraits = CTFontCopyTraits(ctfont); - fontDef.weight = QCoreTextFontEngine::qtWeightFromCFWeight(getTraitValue(allTraits, kCTFontWeightTrait)); - int slant = static_cast<int>(getTraitValue(allTraits, kCTFontSlantTrait) * 500 + 500); - if (slant > 500 && !(traits & kCTFontItalicTrait)) - fontDef.style = QFont::StyleOblique; - - if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) - synthesisFlags |= SynthesizedBold; - // XXX: we probably don't need to synthesis italic for oblique font - if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) - synthesisFlags |= SynthesizedItalic; - - avgCharWidth = 0; - QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); - unsigned emSize = CTFontGetUnitsPerEm(ctfont); - if (os2Table.size() >= 10) { - fsType = qFromBigEndian<quint16>(os2Table.constData() + 8); - // qAbs is a workaround for weird fonts like Lucida Grande - qint16 width = qAbs(qFromBigEndian<qint16>(os2Table.constData() + 2)); - avgCharWidth = QFixed::fromReal(width * fontDef.pixelSize / emSize); - } else - avgCharWidth = QFontEngine::averageCharWidth(); - - underlineThickness = QFixed::fromReal(CTFontGetUnderlineThickness(ctfont)); - underlinePos = -QFixed::fromReal(CTFontGetUnderlinePosition(ctfont)); - - cache_cost = (CTFontGetAscent(ctfont) + CTFontGetDescent(ctfont)) * avgCharWidth.toInt() * 2000; - - // HACK hb_coretext requires both CTFont and CGFont but user_data is only void* - Q_ASSERT((void *)(&ctfont + 1) == (void *)&cgFont); - faceData.user_data = &ctfont; - faceData.get_font_table = ct_getSfntTable; - - kerningPairsLoaded = false; -} - -glyph_t QCoreTextFontEngine::glyphIndex(uint ucs4) const -{ - int len = 0; - - QChar str[2]; - if (Q_UNLIKELY(QChar::requiresSurrogates(ucs4))) { - str[len++] = QChar(QChar::highSurrogate(ucs4)); - str[len++] = QChar(QChar::lowSurrogate(ucs4)); - } else { - str[len++] = QChar(ucs4); - } - - CGGlyph glyphIndices[2]; - - CTFontGetGlyphsForCharacters(ctfont, (const UniChar *)str, glyphIndices, len); - - return glyphIndices[0]; -} - -bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, - int *nglyphs, QFontEngine::ShaperFlags flags) const -{ - Q_ASSERT(glyphs->numGlyphs >= *nglyphs); - if (*nglyphs < len) { - *nglyphs = len; - return false; - } - - QVarLengthArray<CGGlyph> cgGlyphs(len); - CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len); - - int glyph_pos = 0; - for (int i = 0; i < len; ++i) { - glyphs->glyphs[glyph_pos] = cgGlyphs[i]; - if (glyph_pos < i) - cgGlyphs[glyph_pos] = cgGlyphs[i]; - glyph_pos++; - - // If it's a non-BMP char, skip the lower part of surrogate pair and go - // directly to the next char without increasing glyph_pos - if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) - ++i; - } - - *nglyphs = glyph_pos; - glyphs->numGlyphs = glyph_pos; - - if (!(flags & GlyphIndicesOnly)) - loadAdvancesForGlyphs(cgGlyphs, glyphs); - - return true; -} - -glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs) -{ - QFixed w; - bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics; - - for (int i = 0; i < glyphs.numGlyphs; ++i) { - w += round ? glyphs.effectiveAdvance(i).round() - : glyphs.effectiveAdvance(i); - } - return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0); -} - -glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) -{ - glyph_metrics_t ret; - CGGlyph g = glyph; - CGRect rect = CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontOrientationHorizontal, &g, 0, 1); - if (synthesisFlags & QFontEngine::SynthesizedItalic) { - rect.size.width += rect.size.height * SYNTHETIC_ITALIC_SKEW; - } - ret.width = QFixed::fromReal(rect.size.width); - ret.height = QFixed::fromReal(rect.size.height); - ret.x = QFixed::fromReal(rect.origin.x); - ret.y = -QFixed::fromReal(rect.origin.y) - ret.height; - CGSize advances[1]; - CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, &g, advances, 1); - ret.xoff = QFixed::fromReal(advances[0].width); - ret.yoff = QFixed::fromReal(advances[0].height); - - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - ret.xoff = ret.xoff.round(); - ret.yoff = ret.yoff.round(); - } - - return ret; -} - -QFixed QCoreTextFontEngine::ascent() const -{ - return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - ? QFixed::fromReal(CTFontGetAscent(ctfont)).round() - : QFixed::fromReal(CTFontGetAscent(ctfont)); -} - -QFixed QCoreTextFontEngine::capHeight() const -{ - QFixed c = QFixed::fromReal(CTFontGetCapHeight(ctfont)); - if (c <= 0) - return calculatedCapHeight(); - - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - c = c.round(); - - return c; -} - -QFixed QCoreTextFontEngine::descent() const -{ - QFixed d = QFixed::fromReal(CTFontGetDescent(ctfont)); - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - d = d.round(); - - return d; -} -QFixed QCoreTextFontEngine::leading() const -{ - return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - ? QFixed::fromReal(CTFontGetLeading(ctfont)).round() - : QFixed::fromReal(CTFontGetLeading(ctfont)); -} -QFixed QCoreTextFontEngine::xHeight() const -{ - return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - ? QFixed::fromReal(CTFontGetXHeight(ctfont)).round() - : QFixed::fromReal(CTFontGetXHeight(ctfont)); -} - -QFixed QCoreTextFontEngine::averageCharWidth() const -{ - return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - ? avgCharWidth.round() : avgCharWidth; -} - -qreal QCoreTextFontEngine::maxCharWidth() const -{ - // ### FIXME: 'W' might not be the widest character, but this is better than nothing - const glyph_t glyph = glyphIndex('W'); - glyph_metrics_t bb = const_cast<QCoreTextFontEngine *>(this)->boundingBox(glyph); - return bb.xoff.toReal(); -} - -bool QCoreTextFontEngine::hasColorGlyphs() const -{ - return glyphFormat == QFontEngine::Format_ARGB; -} - -void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight) -{ - QVarLengthArray<QFixedPoint> positions; - QVarLengthArray<glyph_t> glyphs; - QTransform matrix; - matrix.translate(x, y); - getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - if (glyphs.size() == 0) - return; - - CGContextSetFontSize(ctx, fontDef.pixelSize); - - CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx); - - CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, -1, 0, -paintDeviceHeight); - - CGAffineTransformConcat(cgMatrix, oldTextMatrix); - - if (synthesisFlags & QFontEngine::SynthesizedItalic) - cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0)); - - cgMatrix = CGAffineTransformConcat(cgMatrix, transform); - - CGContextSetTextMatrix(ctx, cgMatrix); - - CGContextSetTextDrawingMode(ctx, kCGTextFill); - - QVarLengthArray<CGPoint> cgPositions(glyphs.size()); - QVarLengthArray<CGGlyph> cgGlyphs(glyphs.size()); - const qreal firstX = positions[0].x.toReal(); - const qreal firstY = positions[0].y.toReal(); - for (int i = 0; i < glyphs.size(); ++i) { - cgPositions[i].x = positions[i].x.toReal() - firstX; - cgPositions[i].y = firstY - positions[i].y.toReal(); - cgGlyphs[i] = glyphs[i]; - } - - //NSLog(@"Font inDraw %@ ctfont %@", CGFontCopyFullName(cgFont), CTFontCopyFamilyName(ctfont)); - - CGContextSetTextPosition(ctx, positions[0].x.toReal(), positions[0].y.toReal()); - CTFontDrawGlyphs(ctfont, cgGlyphs.data(), cgPositions.data(), glyphs.size(), ctx); - - if (synthesisFlags & QFontEngine::SynthesizedBold) { - CGContextSetTextPosition(ctx, positions[0].x.toReal() + 0.5 * lineThickness().toReal(), - positions[0].y.toReal()); - CTFontDrawGlyphs(ctfont, cgGlyphs.data(), cgPositions.data(), glyphs.size(), ctx); - } - - CGContextSetTextMatrix(ctx, oldTextMatrix); -} - -struct ConvertPathInfo -{ - ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos, qreal newStretch = 1.0) : - path(newPath), pos(newPos), stretch(newStretch) {} - QPainterPath *path; - QPointF pos; - qreal stretch; -}; - -static void convertCGPathToQPainterPath(void *info, const CGPathElement *element) -{ - ConvertPathInfo *myInfo = static_cast<ConvertPathInfo *>(info); - switch(element->type) { - case kCGPathElementMoveToPoint: - myInfo->path->moveTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), - element->points[0].y + myInfo->pos.y()); - break; - case kCGPathElementAddLineToPoint: - myInfo->path->lineTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), - element->points[0].y + myInfo->pos.y()); - break; - case kCGPathElementAddQuadCurveToPoint: - myInfo->path->quadTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), - element->points[0].y + myInfo->pos.y(), - (element->points[1].x * myInfo->stretch) + myInfo->pos.x(), - element->points[1].y + myInfo->pos.y()); - break; - case kCGPathElementAddCurveToPoint: - myInfo->path->cubicTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(), - element->points[0].y + myInfo->pos.y(), - (element->points[1].x * myInfo->stretch) + myInfo->pos.x(), - element->points[1].y + myInfo->pos.y(), - (element->points[2].x * myInfo->stretch) + myInfo->pos.x(), - element->points[2].y + myInfo->pos.y()); - break; - case kCGPathElementCloseSubpath: - myInfo->path->closeSubpath(); - break; - default: - qCWarning(lcQpaFonts) << "Unhandled path transform type: " << element->type; - } - -} - -void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs, - QPainterPath *path, QTextItem::RenderFlags) -{ - if (hasColorGlyphs()) - return; // We can't convert color-glyphs to path - - CGAffineTransform cgMatrix = CGAffineTransformIdentity; - cgMatrix = CGAffineTransformScale(cgMatrix, 1, -1); - - if (synthesisFlags & QFontEngine::SynthesizedItalic) - cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0)); - - qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0; - for (int i = 0; i < nGlyphs; ++i) { - QCFType<CGPathRef> cgpath = CTFontCreatePathForGlyph(ctfont, glyphs[i], &cgMatrix); - ConvertPathInfo info(path, positions[i].toPointF(), stretch); - CGPathApply(cgpath, &info, convertCGPathToQPainterPath); - } -} - -static void qcoretextfontengine_scaleMetrics(glyph_metrics_t &br, const QTransform &matrix) -{ - if (matrix.isScaling()) { - qreal hscale = matrix.m11(); - qreal vscale = matrix.m22(); - br.width = QFixed::fromReal(br.width.toReal() * hscale); - br.height = QFixed::fromReal(br.height.toReal() * vscale); - br.x = QFixed::fromReal(br.x.toReal() * hscale); - br.y = QFixed::fromReal(br.y.toReal() * vscale); - } -} - -glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, GlyphFormat format) -{ - if (matrix.type() > QTransform::TxScale) - return QFontEngine::alphaMapBoundingBox(glyph, subPixelPosition, matrix, format); - - glyph_metrics_t br = boundingBox(glyph); - qcoretextfontengine_scaleMetrics(br, matrix); - - // Normalize width and height - if (br.width < 0) - br.width = -br.width; - if (br.height < 0) - br.height = -br.height; - - if (format == QFontEngine::Format_A8 || format == QFontEngine::Format_A32) { - // Drawing a glyph at x-position 0 with anti-aliasing enabled - // will potentially fill the pixel to the left of 0, as the - // coordinates are not aligned to the center of pixels. To - // prevent clipping of this pixel we need to shift the glyph - // in the bitmap one pixel to the right. The shift needs to - // be reflected in the glyph metrics as well, so that the final - // position of the glyph is correct, which is why doing the - // shift in imageForGlyph() is not enough. - br.x -= 1; - - // As we've shifted the glyph one pixel to the right, we need - // to expand the width of the alpha map bounding box as well. - br.width += 1; - - // But we have the same anti-aliasing problem on the right - // hand side of the glyph, eg. if the width of the glyph - // results in the bounding rect landing between two pixels. - // We pad the bounding rect again to account for the possible - // anti-aliased drawing. - br.width += 1; - - // We also shift the glyph to right right based on the subpixel - // position, so we pad the bounding box to take account for the - // subpixel positions that may result in the glyph being drawn - // one pixel to the right of the 0-subpixel position. - br.width += 1; - - // The same same logic as for the x-position needs to be applied - // to the y-position, except we don't need to compensate for - // the subpixel positioning. - br.y -= 1; - br.height += 2; - } - - return br; -} - -/* - Apple has gone through many iterations of its font smoothing algorithms, - and there are many ways to enable or disable certain aspects of it. As - keeping up with all the different toggles and behavior differences between - macOS versions is tricky, we resort to rendering a single glyph in a few - configurations, picking up the font smoothing algorithm from the observed - result. - - The possible values are: - - - Disabled: No font smoothing is applied. - - Possibly triggered by the user unchecking the "Use font smoothing when - available" checkbox in the system preferences or setting AppleFontSmoothing - to 0. Also controlled by the CGContextSetAllowsFontSmoothing() API, - which gets its default from the settings above. This API overrides - the more granular CGContextSetShouldSmoothFonts(), which we use to - enable (request) or disable font smoothing. - - Note that this does not exclude normal antialiasing, controlled by - the CGContextSetShouldAntialias() API. - - - Subpixel: Font smoothing is applied, and affects subpixels. - - This was the default mode on macOS versions prior to 10.14 (Mojave). - The font dilation (stem darkening) parameters were controlled by the - AppleFontSmoothing setting, ranging from 1 to 3 (light to strong). - - On Mojave it is no longer supported, but can be triggered by a legacy - override (CGFontRenderingFontSmoothingDisabled=NO), so we need to - still account for it, otherwise users will have a bad time. - - - Grayscale: Font smoothing is applied, but does not affect subpixels. - - This is the default mode on macOS 10.14 (Mojave). The font dilation - (stem darkening) parameters are not affected by the AppleFontSmoothing - setting, but are instead computed based on the fill color used when - drawing the glyphs (white fill gives a lighter dilation than black - fill). This affects how we build our glyph cache, since we produce - alpha maps by drawing white on black. -*/ -QCoreTextFontEngine::FontSmoothing QCoreTextFontEngine::fontSmoothing() -{ - static const FontSmoothing cachedFontSmoothing = [] { - static const int kSize = 10; - QCFType<CTFontRef> font = CTFontCreateWithName(CFSTR("Helvetica"), kSize, nullptr); - - UniChar character('X'); CGGlyph glyph; - CTFontGetGlyphsForCharacters(font, &character, &glyph, 1); - - auto drawGlyph = [&](bool smooth) -> QImage { - QImage image(kSize, kSize, QImage::Format_RGB32); - image.fill(0); - - QMacCGContext ctx(&image); - CGContextSetTextDrawingMode(ctx, kCGTextFill); - CGContextSetGrayFillColor(ctx, 1, 1); - - // Will be ignored if CGContextSetAllowsFontSmoothing() has been - // set to false by CoreGraphics based on user defaults. - CGContextSetShouldSmoothFonts(ctx, smooth); - - CTFontDrawGlyphs(font, &glyph, &CGPointZero, 1, ctx); - return image; - }; - - QImage nonSmoothed = drawGlyph(false); - QImage smoothed = drawGlyph(true); - - FontSmoothing fontSmoothing = FontSmoothing::Disabled; - [&] { - for (int x = 0; x < kSize; ++x) { - for (int y = 0; y < kSize; ++y) { - QRgb sp = smoothed.pixel(x, y); - if (qRed(sp) != qGreen(sp) || qRed(sp) != qBlue(sp)) { - fontSmoothing = FontSmoothing::Subpixel; - return; - } - - if (sp != nonSmoothed.pixel(x, y)) - fontSmoothing = FontSmoothing::Grayscale; - } - } - }(); - - auto defaults = [NSUserDefaults standardUserDefaults]; - qCDebug(lcQpaFonts) << "Resolved font smoothing algorithm. Defaults =" - << [[defaults dictionaryRepresentation] dictionaryWithValuesForKeys:@[ - @"AppleFontSmoothing", - @"CGFontRenderingFontSmoothingDisabled" - ]] << "Result =" << fontSmoothing; - - return fontSmoothing; - }(); - - return cachedFontSmoothing; -} - -bool QCoreTextFontEngine::shouldAntialias() const -{ - return !(fontDef.styleStrategy & QFont::NoAntialias); -} - -bool QCoreTextFontEngine::shouldSmoothFont() const -{ - if (hasColorGlyphs()) - return false; - - if (!shouldAntialias()) - return false; - - switch (fontSmoothing()) { - case Disabled: return false; - case Subpixel: return !(fontDef.styleStrategy & QFont::NoSubpixelAntialias); - case Grayscale: return true; - } - - Q_UNREACHABLE(); -} - -bool QCoreTextFontEngine::expectsGammaCorrectedBlending() const -{ - return shouldSmoothFont() && fontSmoothing() == Subpixel; -} - -qreal QCoreTextFontEngine::fontSmoothingGamma() -{ - return 2.0; -} - -QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, const QColor &color) -{ - glyph_metrics_t br = alphaMapBoundingBox(glyph, subPixelPosition, matrix, glyphFormat); - - QImage::Format imageFormat = hasColorGlyphs() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; - QImage im(br.width.ceil().toInt(), br.height.ceil().toInt(), imageFormat); - if (!im.width() || !im.height()) - return im; - - QCFType<CGColorSpaceRef> colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - QCFType<CGContextRef> ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(), - 8, im.bytesPerLine(), colorspace, - qt_mac_bitmapInfoForImage(im)); - Q_ASSERT(ctx); - - CGContextSetShouldAntialias(ctx, shouldAntialias()); - - const bool shouldSmooth = shouldSmoothFont(); - CGContextSetShouldSmoothFonts(ctx, shouldSmooth); - -#if defined(Q_OS_MACOS) - auto glyphColor = [&] { - if (shouldSmooth && fontSmoothing() == Grayscale) { - // The grayscale font smoothing algorithm introduced in macOS Mojave (10.14) adjusts - // its dilation (stem darkening) parameters based on the fill color. This means our - // default approach of drawing white on black to produce the alpha map will result - // in non-native looking text when then drawn as black on white during the final blit. - // As a workaround we use the application's current appearance to decide whether to - // draw with white or black fill, and then invert the glyph image in the latter case, - // producing an alpha map. This covers the most common use-cases, but longer term we - // should propagate the fill color all the way from the paint engine, and include it - //in the key for the glyph cache. - - if (!qt_mac_applicationIsInDarkMode()) - return kCGColorBlack; - } - return kCGColorWhite; - }(); - - const bool blackOnWhiteGlyphs = glyphColor == kCGColorBlack; - if (blackOnWhiteGlyphs) - im.fill(Qt::white); - else -#endif - im.fill(0); - - CGContextSetFontSize(ctx, fontDef.pixelSize); - - CGAffineTransform cgMatrix = CGAffineTransformIdentity; - - if (synthesisFlags & QFontEngine::SynthesizedItalic) - cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0)); - - if (!hasColorGlyphs()) // CTFontDrawGlyphs incorporates the font's matrix already - cgMatrix = CGAffineTransformConcat(cgMatrix, transform); - - if (matrix.isScaling()) - cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMakeScale(matrix.m11(), matrix.m22())); - - CGGlyph cgGlyph = glyph; - qreal pos_x = -br.x.truncate() + subPixelPosition.toReal(); - qreal pos_y = im.height() + br.y.toReal(); - - if (!hasColorGlyphs()) { - CGContextSetTextMatrix(ctx, cgMatrix); -#if defined(Q_OS_MACOS) - CGContextSetFillColorWithColor(ctx, CGColorGetConstantColor(glyphColor)); -#else - CGContextSetRGBFillColor(ctx, 1, 1, 1, 1); -#endif - CGContextSetTextDrawingMode(ctx, kCGTextFill); - CGContextSetTextPosition(ctx, pos_x, pos_y); - - CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx); - - if (synthesisFlags & QFontEngine::SynthesizedBold) { - CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y); - CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx); - } - } else { - CGContextSetRGBFillColor(ctx, color.redF(), color.greenF(), color.blueF(), color.alphaF()); - - // CGContextSetTextMatrix does not work with color glyphs, so we use - // the CTM instead. This means we must translate the CTM as well, to - // set the glyph position, instead of using CGContextSetTextPosition. - CGContextTranslateCTM(ctx, pos_x, pos_y); - CGContextConcatCTM(ctx, cgMatrix); - - // CGContextShowGlyphsWithAdvances does not support the 'sbix' color-bitmap - // glyphs in the Apple Color Emoji font, so we use CTFontDrawGlyphs instead. - CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx); - } - - if (expectsGammaCorrectedBlending()) - qGamma_correct_back_to_linear_cs(&im); - -#if defined(Q_OS_MACOS) - if (blackOnWhiteGlyphs) - im.invertPixels(); -#endif - - return im; -} - -QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) -{ - return alphaMapForGlyph(glyph, subPixelPosition, QTransform()); -} - -QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &x) -{ - if (x.type() > QTransform::TxScale) - return QFontEngine::alphaMapForGlyph(glyph, subPixelPosition, x); - - QImage im = imageForGlyph(glyph, subPixelPosition, x); - - QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8); - - for (int y=0; y<im.height(); ++y) { - uint *src = (uint*) im.scanLine(y); - uchar *dst = alphaMap.scanLine(y); - for (int x=0; x<im.width(); ++x) { - *dst = qGray(*src); - ++dst; - ++src; - } - } - - return alphaMap; -} - -QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &x) -{ - if (x.type() > QTransform::TxScale) - return QFontEngine::alphaRGBMapForGlyph(glyph, subPixelPosition, x); - - return imageForGlyph(glyph, subPixelPosition, x); -} - -QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color) -{ - if (t.type() > QTransform::TxScale) - return QFontEngine::bitmapForGlyph(glyph, subPixelPosition, t, color); - - return imageForGlyph(glyph, subPixelPosition, t, color); -} - -void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const -{ - Q_UNUSED(flags); - - const int numGlyphs = glyphs->numGlyphs; - QVarLengthArray<CGGlyph> cgGlyphs(numGlyphs); - - for (int i = 0; i < numGlyphs; ++i) { - Q_ASSERT(!QFontEngineMulti::highByte(glyphs->glyphs[i])); - cgGlyphs[i] = glyphs->glyphs[i]; - } - - loadAdvancesForGlyphs(cgGlyphs, glyphs); -} - -void QCoreTextFontEngine::loadAdvancesForGlyphs(QVarLengthArray<CGGlyph> &cgGlyphs, QGlyphLayout *glyphs) const -{ - const int numGlyphs = glyphs->numGlyphs; - QVarLengthArray<CGSize> advances(numGlyphs); - CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), numGlyphs); - - for (int i = 0; i < numGlyphs; ++i) { - QFixed advance = QFixed::fromReal(advances[i].width); - glyphs->advances[i] = fontDef.styleStrategy & QFont::ForceIntegerMetrics - ? advance.round() : advance; - } -} - -QFontEngine::FaceId QCoreTextFontEngine::faceId() const -{ - return face_id; -} - -bool QCoreTextFontEngine::canRender(const QChar *string, int len) const -{ - QVarLengthArray<CGGlyph> cgGlyphs(len); - return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len); -} - -bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const -{ - return ct_getSfntTable((void *)&ctfont, tag, buffer, length); -} - -void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metric) -{ - CGAffineTransform cgMatrix = CGAffineTransformIdentity; - - qreal emSquare = CTFontGetUnitsPerEm(ctfont); - qreal scale = emSquare / CTFontGetSize(ctfont); - cgMatrix = CGAffineTransformScale(cgMatrix, scale, -scale); - - QCFType<CGPathRef> cgpath = CTFontCreatePathForGlyph(ctfont, (CGGlyph) glyph, &cgMatrix); - ConvertPathInfo info(path, QPointF(0,0)); - CGPathApply(cgpath, &info, convertCGPathToQPainterPath); - - *metric = boundingBox(glyph); - // scale the metrics too - metric->width = QFixed::fromReal(metric->width.toReal() * scale); - metric->height = QFixed::fromReal(metric->height.toReal() * scale); - metric->x = QFixed::fromReal(metric->x.toReal() * scale); - metric->y = QFixed::fromReal(metric->y.toReal() * scale); - metric->xoff = QFixed::fromReal(metric->xoff.toReal() * scale); - metric->yoff = QFixed::fromReal(metric->yoff.toReal() * scale); -} - -QFixed QCoreTextFontEngine::emSquareSize() const -{ - return QFixed(int(CTFontGetUnitsPerEm(ctfont))); -} - -QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const -{ - QFontDef newFontDef = fontDef; - newFontDef.pixelSize = pixelSize; - newFontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); - - return new QCoreTextFontEngine(cgFont, newFontDef); -} - -Qt::HANDLE QCoreTextFontEngine::handle() const -{ - return (Qt::HANDLE)(static_cast<CTFontRef>(ctfont)); -} - -bool QCoreTextFontEngine::supportsTransformation(const QTransform &transform) const -{ - if (transform.type() < QTransform::TxScale) - return true; - else if (transform.type() == QTransform::TxScale && - transform.m11() >= 0 && transform.m22() >= 0) - return true; - else - return false; -} - -QFixed QCoreTextFontEngine::lineThickness() const -{ - return underlineThickness; -} - -QFixed QCoreTextFontEngine::underlinePosition() const -{ - return underlinePos; -} - -QFontEngine::Properties QCoreTextFontEngine::properties() const -{ - Properties result; - - QCFString psName, copyright; - psName = CTFontCopyPostScriptName(ctfont); - copyright = CTFontCopyName(ctfont, kCTFontCopyrightNameKey); - result.postscriptName = QString::fromCFString(psName).toUtf8(); - result.copyright = QString::fromCFString(copyright).toUtf8(); - - qreal emSquare = CTFontGetUnitsPerEm(ctfont); - qreal scale = emSquare / CTFontGetSize(ctfont); - - CGRect cgRect = CTFontGetBoundingBox(ctfont); - result.boundingBox = QRectF(cgRect.origin.x * scale, - -CTFontGetAscent(ctfont) * scale, - cgRect.size.width * scale, - cgRect.size.height * scale); - - result.emSquare = emSquareSize(); - result.ascent = QFixed::fromReal(CTFontGetAscent(ctfont) * scale); - result.descent = QFixed::fromReal(CTFontGetDescent(ctfont) * scale); - result.leading = QFixed::fromReal(CTFontGetLeading(ctfont) * scale); - result.italicAngle = QFixed::fromReal(CTFontGetSlantAngle(ctfont)); - result.capHeight = QFixed::fromReal(CTFontGetCapHeight(ctfont) * scale); - result.lineWidth = QFixed::fromReal(CTFontGetUnderlineThickness(ctfont) * scale); - - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - result.ascent = result.ascent.round(); - result.descent = result.descent.round(); - result.leading = result.leading.round(); - result.italicAngle = result.italicAngle.round(); - result.capHeight = result.capHeight.round(); - result.lineWidth = result.lineWidth.round(); - } - - return result; -} - -void QCoreTextFontEngine::doKerning(QGlyphLayout *g, ShaperFlags flags) const -{ - if (!kerningPairsLoaded) { - kerningPairsLoaded = true; - qreal emSquare = CTFontGetUnitsPerEm(ctfont); - qreal scale = emSquare / CTFontGetSize(ctfont); - - const_cast<QCoreTextFontEngine *>(this)->loadKerningPairs(QFixed::fromReal(scale)); - } - - QFontEngine::doKerning(g, flags); -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h deleted file mode 100644 index 51d839688d..0000000000 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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$ -** -****************************************************************************/ - -#ifndef QFONTENGINE_CORETEXT_P_H -#define QFONTENGINE_CORETEXT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qfontengine_p.h> -#include <private/qcore_mac_p.h> -#include <QtCore/qloggingcategory.h> - -#ifdef Q_OS_OSX -#include <ApplicationServices/ApplicationServices.h> -#else -#include <CoreText/CoreText.h> -#include <CoreGraphics/CoreGraphics.h> -#endif - -QT_BEGIN_NAMESPACE - -Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) - -class QCoreTextFontEngine : public QFontEngine -{ - Q_GADGET - -public: - QCoreTextFontEngine(CTFontRef font, const QFontDef &def); - QCoreTextFontEngine(CGFontRef font, const QFontDef &def); - ~QCoreTextFontEngine(); - - glyph_t glyphIndex(uint ucs4) const override; - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; - void recalcAdvances(QGlyphLayout *, ShaperFlags) const override; - - glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; - glyph_metrics_t boundingBox(glyph_t glyph) override; - - QFixed ascent() const override; - QFixed capHeight() const override; - QFixed descent() const override; - QFixed leading() const override; - QFixed xHeight() const override; - qreal maxCharWidth() const override; - QFixed averageCharWidth() const override; - - void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, - QPainterPath *path, QTextItem::RenderFlags) override; - - bool canRender(const QChar *string, int len) const override; - - int synthesized() const override { return synthesisFlags; } - bool supportsSubPixelPositions() const override { return true; } - - QFixed lineThickness() const override; - QFixed underlinePosition() const override; - - void draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight); - - FaceId faceId() const override; - bool getSfntTableData(uint /*tag*/, uchar * /*buffer*/, uint * /*length*/) const override; - void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override; - QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition) override; - QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override; - QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override; - glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) override; - QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override; - QFixed emSquareSize() const override; - void doKerning(QGlyphLayout *g, ShaperFlags flags) const override; - - bool supportsTransformation(const QTransform &transform) const override; - bool expectsGammaCorrectedBlending() const override; - - QFontEngine *cloneWithSize(qreal pixelSize) const override; - Qt::HANDLE handle() const override; - int glyphMargin(QFontEngine::GlyphFormat format) override { Q_UNUSED(format); return 0; } - - QFontEngine::Properties properties() const override; - - enum FontSmoothing { Disabled, Subpixel, Grayscale }; - Q_ENUM(FontSmoothing); - - static FontSmoothing fontSmoothing(); - static qreal fontSmoothingGamma(); - - static bool ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length); - static QFont::Weight qtWeightFromCFWeight(float value); - - static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); - -protected: - QCoreTextFontEngine(const QFontDef &def); - void init(); - QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &m, const QColor &color = QColor()); - void loadAdvancesForGlyphs(QVarLengthArray<CGGlyph> &cgGlyphs, QGlyphLayout *glyphs) const; - bool hasColorGlyphs() const; - bool shouldAntialias() const; - bool shouldSmoothFont() const; - - QCFType<CTFontRef> ctfont; - QCFType<CGFontRef> cgFont; - int synthesisFlags; - CGAffineTransform transform; - QFixed avgCharWidth; - QFixed underlineThickness; - QFixed underlinePos; - QFontEngine::FaceId face_id; - mutable bool kerningPairsLoaded; -}; - -CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef); - -QT_END_NAMESPACE - -#endif // QFONTENGINE_CORETEXT_P_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp deleted file mode 100644 index 36a94724c1..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ /dev/null @@ -1,2087 +0,0 @@ -/**************************************************************************** -** -** 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 "qwindowsfontdatabase_p.h" -#include "qwindowsfontdatabase_ft_p.h" // for default font -#include "qwindowsfontengine_p.h" -#include "qwindowsfontenginedirectwrite_p.h" -#include <QtCore/qt_windows.h> - -#include <QtGui/QFont> -#include <QtGui/QGuiApplication> -#include <QtGui/private/qhighdpiscaling_p.h> - -#include <QtCore/qmath.h> -#include <QtCore/QDebug> -#include <QtCore/QFile> -#include <QtCore/QtEndian> -#include <QtCore/QThreadStorage> -#include <QtCore/private/qsystemlibrary_p.h> -#include <QtCore/private/qwinregistry_p.h> - -#include <wchar.h> - -#if !defined(QT_NO_DIRECTWRITE) -# if defined(QT_USE_DIRECTWRITE2) -# include <dwrite_2.h> -# else -# include <dwrite.h> -# endif -# include <d2d1.h> -#endif - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") - -#ifndef QT_NO_DIRECTWRITE -// ### fixme: Consider direct linking of dwrite.dll once Windows Vista pre SP2 is dropped (QTBUG-49711) - -typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **); - -static inline DWriteCreateFactoryType resolveDWriteCreateFactory() -{ - QSystemLibrary library(QStringLiteral("dwrite")); - QFunctionPointer result = library.resolve("DWriteCreateFactory"); - if (Q_UNLIKELY(!result)) { - qWarning("Unable to load dwrite.dll"); - return nullptr; - } - return reinterpret_cast<DWriteCreateFactoryType>(result); -} - -static void createDirectWriteFactory(IDWriteFactory **factory) -{ - *factory = nullptr; - - static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory(); - if (!dWriteCreateFactory) - return; - - IUnknown *result = NULL; -#if defined(QT_USE_DIRECTWRITE2) - dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result); -#endif - - if (result == NULL) { - if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) { - qErrnoWarning("DWriteCreateFactory failed"); - return; - } - } - - *factory = static_cast<IDWriteFactory *>(result); -} - -static inline bool useDirectWrite(QFont::HintingPreference hintingPreference, - const QString &familyName = QString(), - bool isColorFont = false) -{ - const unsigned options = QWindowsFontDatabase::fontOptions(); - if (Q_UNLIKELY(options & QWindowsFontDatabase::DontUseDirectWriteFonts)) - return false; - - // At some scales, GDI will misrender the MingLiU font, so we force use of - // DirectWrite to work around the issue. - if (Q_UNLIKELY(familyName.startsWith(QLatin1String("MingLiU")))) - return true; - - if (isColorFont) - return (options & QWindowsFontDatabase::DontUseColorFonts) == 0; - - return hintingPreference == QFont::PreferNoHinting - || hintingPreference == QFont::PreferVerticalHinting - || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting); -} -#endif // !QT_NO_DIRECTWRITE - -// Helper classes for creating font engines directly from font data -namespace { - -# pragma pack(1) - - // Common structure for all formats of the "name" table - struct NameTable - { - quint16 format; - quint16 count; - quint16 stringOffset; - }; - - struct NameRecord - { - quint16 platformID; - quint16 encodingID; - quint16 languageID; - quint16 nameID; - quint16 length; - quint16 offset; - }; - - struct OffsetSubTable - { - quint32 scalerType; - quint16 numTables; - quint16 searchRange; - quint16 entrySelector; - quint16 rangeShift; - }; - - struct TableDirectory - { - quint32 identifier; - quint32 checkSum; - quint32 offset; - quint32 length; - }; - - struct OS2Table - { - quint16 version; - qint16 avgCharWidth; - quint16 weightClass; - quint16 widthClass; - quint16 type; - qint16 subscriptXSize; - qint16 subscriptYSize; - qint16 subscriptXOffset; - qint16 subscriptYOffset; - qint16 superscriptXSize; - qint16 superscriptYSize; - qint16 superscriptXOffset; - qint16 superscriptYOffset; - qint16 strikeOutSize; - qint16 strikeOutPosition; - qint16 familyClass; - quint8 panose[10]; - quint32 unicodeRanges[4]; - quint8 vendorID[4]; - quint16 selection; - quint16 firstCharIndex; - quint16 lastCharIndex; - qint16 typoAscender; - qint16 typoDescender; - qint16 typoLineGap; - quint16 winAscent; - quint16 winDescent; - quint32 codepageRanges[2]; - qint16 height; - qint16 capHeight; - quint16 defaultChar; - quint16 breakChar; - quint16 maxContext; - }; - -# pragma pack() - - class EmbeddedFont - { - public: - EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) {} - - QString changeFamilyName(const QString &newFamilyName); - QByteArray data() const { return m_fontData; } - TableDirectory *tableDirectoryEntry(const QByteArray &tagName); - QString familyName(TableDirectory *nameTableDirectory = 0); - - private: - QByteArray m_fontData; - }; - - TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName) - { - Q_ASSERT(tagName.size() == 4); - quint32 tagId = *(reinterpret_cast<const quint32 *>(tagName.constData())); - const size_t fontDataSize = m_fontData.size(); - if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable))) - return 0; - - OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data()); - TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1); - - const size_t tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables); - if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount)) - return 0; - - TableDirectory *tableDirectoryEnd = tableDirectory + tableCount; - for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) { - if (entry->identifier == tagId) - return entry; - } - - return 0; - } - - QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry) - { - QString name; - - if (nameTableDirectoryEntry == 0) - nameTableDirectoryEntry = tableDirectoryEntry("name"); - - if (nameTableDirectoryEntry != 0) { - quint32 offset = qFromBigEndian<quint32>(nameTableDirectoryEntry->offset); - if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable))) - return QString(); - - NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data() + offset); - NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1); - - quint16 nameTableCount = qFromBigEndian<quint16>(nameTable->count); - if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameRecord) * nameTableCount)) - return QString(); - - for (int i = 0; i < nameTableCount; ++i, ++nameRecord) { - if (qFromBigEndian<quint16>(nameRecord->nameID) == 1 - && qFromBigEndian<quint16>(nameRecord->platformID) == 3 // Windows - && qFromBigEndian<quint16>(nameRecord->languageID) == 0x0409) { // US English - quint16 stringOffset = qFromBigEndian<quint16>(nameTable->stringOffset); - quint16 nameOffset = qFromBigEndian<quint16>(nameRecord->offset); - quint16 nameLength = qFromBigEndian<quint16>(nameRecord->length); - - if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength)) - return QString(); - - const void *ptr = reinterpret_cast<const quint8 *>(nameTable) - + stringOffset - + nameOffset; - - const quint16 *s = reinterpret_cast<const quint16 *>(ptr); - const quint16 *e = s + nameLength / sizeof(quint16); - while (s != e) - name += QChar( qFromBigEndian<quint16>(*s++)); - break; - } - } - } - - return name; - } - - QString EmbeddedFont::changeFamilyName(const QString &newFamilyName) - { - TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name"); - if (nameTableDirectoryEntry == 0) - return QString(); - - QString oldFamilyName = familyName(nameTableDirectoryEntry); - - // Reserve size for name table header, five required name records and string - const int requiredRecordCount = 5; - quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 }; - - int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount; - int newFamilyNameSize = newFamilyName.size() * int(sizeof(quint16)); - - const QString regularString = QString::fromLatin1("Regular"); - int regularStringSize = regularString.size() * int(sizeof(quint16)); - - // Align table size of table to 32 bits (pad with 0) - int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4; - - QByteArray newNameTable(fullSize, char(0)); - - { - NameTable *nameTable = reinterpret_cast<NameTable *>(newNameTable.data()); - nameTable->count = qbswap<quint16>(requiredRecordCount); - nameTable->stringOffset = qbswap<quint16>(sizeOfHeader); - - NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1); - for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) { - nameRecord->nameID = qbswap<quint16>(nameIds[i]); - nameRecord->encodingID = qbswap<quint16>(1); - nameRecord->languageID = qbswap<quint16>(0x0409); - nameRecord->platformID = qbswap<quint16>(3); - nameRecord->length = qbswap<quint16>(newFamilyNameSize); - - // Special case for sub-family - if (nameIds[i] == 4) { - nameRecord->offset = qbswap<quint16>(newFamilyNameSize); - nameRecord->length = qbswap<quint16>(regularStringSize); - } - } - - // nameRecord now points to string data - quint16 *stringStorage = reinterpret_cast<quint16 *>(nameRecord); - const quint16 *sourceString = newFamilyName.utf16(); - for (int i = 0; i < newFamilyName.size(); ++i) - stringStorage[i] = qbswap<quint16>(sourceString[i]); - stringStorage += newFamilyName.size(); - - sourceString = regularString.utf16(); - for (int i = 0; i < regularString.size(); ++i) - stringStorage[i] = qbswap<quint16>(sourceString[i]); - } - - quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data()); - quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize); - - quint32 checkSum = 0; - while (p < tableEnd) - checkSum += qFromBigEndian<quint32>(*(p++)); - - nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum); - nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size()); - nameTableDirectoryEntry->length = qbswap<quint32>(fullSize); - - m_fontData.append(newNameTable); - - return oldFamilyName; - } - -#if !defined(QT_NO_DIRECTWRITE) - - class DirectWriteFontFileStream: public IDWriteFontFileStream - { - Q_DISABLE_COPY(DirectWriteFontFileStream) - public: - DirectWriteFontFileStream(const QByteArray &fontData) - : m_fontData(fontData) - , m_referenceCount(0) - { - } - virtual ~DirectWriteFontFileStream() - { - } - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - - HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset, - UINT64 fragmentSize, OUT void **fragmentContext); - void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext); - HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize); - HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime); - - private: - QByteArray m_fontData; - ULONG m_referenceCount; - }; - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object) - { - if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { - *object = this; - AddRef(); - return S_OK; - } else { - *object = NULL; - return E_NOINTERFACE; - } - } - - ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef() - { - return InterlockedIncrement(&m_referenceCount); - } - - ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release() - { - ULONG newCount = InterlockedDecrement(&m_referenceCount); - if (newCount == 0) - delete this; - return newCount; - } - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment( - const void **fragmentStart, - UINT64 fileOffset, - UINT64 fragmentSize, - OUT void **fragmentContext) - { - *fragmentContext = NULL; - if (fileOffset + fragmentSize <= quint64(m_fontData.size())) { - *fragmentStart = m_fontData.data() + fileOffset; - return S_OK; - } else { - *fragmentStart = NULL; - return E_FAIL; - } - } - - void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *) - { - } - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize) - { - *fileSize = m_fontData.size(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) - { - *lastWriteTime = 0; - return E_NOTIMPL; - } - - class DirectWriteFontFileLoader: public IDWriteFontFileLoader - { - public: - DirectWriteFontFileLoader() : m_referenceCount(0) {} - virtual ~DirectWriteFontFileLoader() - { - } - - inline void addKey(const void *key, const QByteArray &fontData) - { - Q_ASSERT(!m_fontDatas.contains(key)); - m_fontDatas.insert(key, fontData); - } - - inline void removeKey(const void *key) - { - m_fontDatas.remove(key); - } - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - - HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey, - UINT32 fontFileReferenceKeySize, - OUT IDWriteFontFileStream **fontFileStream); - - private: - ULONG m_referenceCount; - QHash<const void *, QByteArray> m_fontDatas; - }; - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid, - void **object) - { - if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { - *object = this; - AddRef(); - return S_OK; - } else { - *object = NULL; - return E_NOINTERFACE; - } - } - - ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef() - { - return InterlockedIncrement(&m_referenceCount); - } - - ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release() - { - ULONG newCount = InterlockedDecrement(&m_referenceCount); - if (newCount == 0) - delete this; - return newCount; - } - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey( - void const *fontFileReferenceKey, - UINT32 fontFileReferenceKeySize, - IDWriteFontFileStream **fontFileStream) - { - Q_UNUSED(fontFileReferenceKeySize); - - if (fontFileReferenceKeySize != sizeof(const void *)) { - qWarning("%s: Wrong key size", __FUNCTION__); - return E_FAIL; - } - - const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey); - *fontFileStream = NULL; - auto it = m_fontDatas.constFind(key); - if (it == m_fontDatas.constEnd()) - return E_FAIL; - - QByteArray fontData = it.value(); - DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData); - stream->AddRef(); - *fontFileStream = stream; - - return S_OK; - } - - class CustomFontFileLoader - { - public: - CustomFontFileLoader() : m_directWriteFontFileLoader(nullptr) - { - createDirectWriteFactory(&m_directWriteFactory); - - if (m_directWriteFactory) { - m_directWriteFontFileLoader = new DirectWriteFontFileLoader(); - m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader); - } - } - - ~CustomFontFileLoader() - { - if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0) - m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader); - - if (m_directWriteFactory != 0) - m_directWriteFactory->Release(); - } - - void addKey(const void *key, const QByteArray &fontData) - { - if (m_directWriteFontFileLoader != 0) - m_directWriteFontFileLoader->addKey(key, fontData); - } - - void removeKey(const void *key) - { - if (m_directWriteFontFileLoader != 0) - m_directWriteFontFileLoader->removeKey(key); - } - - IDWriteFontFileLoader *loader() const - { - return m_directWriteFontFileLoader; - } - - private: - IDWriteFactory *m_directWriteFactory; - DirectWriteFontFileLoader *m_directWriteFontFileLoader; - }; - -#endif - -} // Anonymous namespace - -/*! - \struct QWindowsFontEngineData - \brief Static constant data shared by the font engines. - \ingroup qt-lighthouse-win -*/ - -QWindowsFontEngineData::QWindowsFontEngineData() - : fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma()) -{ - // from qapplication_win.cpp - UINT result = 0; - if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0)) - clearTypeEnabled = (result == FE_FONTSMOOTHINGCLEARTYPE); - - const qreal gray_gamma = 2.31; - for (int i=0; i<256; ++i) - pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047)); - - HDC displayDC = GetDC(0); - hdc = CreateCompatibleDC(displayDC); - ReleaseDC(0, displayDC); -} - -unsigned QWindowsFontDatabase::m_fontOptions = 0; - -void QWindowsFontDatabase::setFontOptions(unsigned options) -{ - m_fontOptions = options & (QWindowsFontDatabase::DontUseDirectWriteFonts | - QWindowsFontDatabase::DontUseColorFonts); -} - -unsigned QWindowsFontDatabase::fontOptions() -{ - return m_fontOptions; -} - -QWindowsFontEngineData::~QWindowsFontEngineData() -{ - if (hdc) - DeleteDC(hdc); -#if !defined(QT_NO_DIRECTWRITE) - if (directWriteGdiInterop) - directWriteGdiInterop->Release(); - if (directWriteFactory) - directWriteFactory->Release(); -#endif -} - -qreal QWindowsFontDatabase::fontSmoothingGamma() -{ - int winSmooth; - qreal result = 1; - if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) - result = qreal(winSmooth) / qreal(1000.0); - - // Safeguard ourselves against corrupt registry values... - if (result > 5 || result < 1) - result = qreal(1.4); - return result; -} - -#if !defined(QT_NO_DIRECTWRITE) -static inline bool initDirectWrite(QWindowsFontEngineData *d) -{ - if (!d->directWriteFactory) { - createDirectWriteFactory(&d->directWriteFactory); - if (!d->directWriteFactory) - return false; - } - if (!d->directWriteGdiInterop) { - const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop); - if (FAILED(hr)) { - qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__); - return false; - } - } - return true; -} - -#endif // !defined(QT_NO_DIRECTWRITE) - -/*! - \class QWindowsFontDatabase - \brief Font database for Windows - - \note The Qt 4.8 WIndows font database employed a mechanism of - delayed population of the database again passing a font name - to EnumFontFamiliesEx(), working around the fact that - EnumFontFamiliesEx() does not list all fonts by default. - This should be introduced to Lighthouse as well? - - \internal - \ingroup qt-lighthouse-win -*/ - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const QFontDef &def) -{ - QDebugStateSaver saver(d); - d.nospace(); - d.noquote(); - d << "QFontDef(Family=\"" << def.family << '"'; - if (!def.styleName.isEmpty()) - d << ", stylename=" << def.styleName; - d << ", pointsize=" << def.pointSize << ", pixelsize=" << def.pixelSize - << ", styleHint=" << def.styleHint << ", weight=" << def.weight - << ", stretch=" << def.stretch << ", hintingPreference=" - << def.hintingPreference << ')'; - return d; -} - -QDebug operator<<(QDebug d, const LOGFONT &lf) -{ - QDebugStateSaver saver(d); - d.nospace(); - d.noquote(); - d << "LOGFONT(\"" << QString::fromWCharArray(lf.lfFaceName) - << "\", lfWidth=" << lf.lfWidth << ", lfHeight=" << lf.lfHeight << ')'; - return d; -} -#endif // !QT_NO_DEBUG_STREAM - -static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet) -{ - switch (charSet) { - case ANSI_CHARSET: - case EASTEUROPE_CHARSET: - case BALTIC_CHARSET: - case TURKISH_CHARSET: - return QFontDatabase::Latin; - case GREEK_CHARSET: - return QFontDatabase::Greek; - case RUSSIAN_CHARSET: - return QFontDatabase::Cyrillic; - case HEBREW_CHARSET: - return QFontDatabase::Hebrew; - case ARABIC_CHARSET: - return QFontDatabase::Arabic; - case THAI_CHARSET: - return QFontDatabase::Thai; - case GB2312_CHARSET: - return QFontDatabase::SimplifiedChinese; - case CHINESEBIG5_CHARSET: - return QFontDatabase::TraditionalChinese; - case SHIFTJIS_CHARSET: - return QFontDatabase::Japanese; - case HANGUL_CHARSET: - case JOHAB_CHARSET: - return QFontDatabase::Korean; - case VIETNAMESE_CHARSET: - return QFontDatabase::Vietnamese; - case SYMBOL_CHARSET: - return QFontDatabase::Symbol; - default: - break; - } - return QFontDatabase::Any; -} - -#ifdef MAKE_TAG -#undef MAKE_TAG -#endif -// GetFontData expects the tags in little endian ;( -#define MAKE_TAG(ch1, ch2, ch3, ch4) (\ - (((quint32)(ch4)) << 24) | \ - (((quint32)(ch3)) << 16) | \ - (((quint32)(ch2)) << 8) | \ - ((quint32)(ch1)) \ - ) - -bool qt_localizedName(const QString &name) -{ - const QChar *c = name.unicode(); - for (int i = 0; i < name.length(); ++i) { - if (c[i].unicode() >= 0x100) - return true; - } - return false; -} - -namespace { - -static QString readName(bool unicode, const uchar *string, int length) -{ - QString out; - if (unicode) { - // utf16 - - length /= 2; - out.resize(length); - QChar *uc = out.data(); - for (int i = 0; i < length; ++i) - uc[i] = qt_getUShort(string + 2*i); - } else { - // Apple Roman - - out.resize(length); - QChar *uc = out.data(); - for (int i = 0; i < length; ++i) - uc[i] = QLatin1Char(char(string[i])); - } - return out; -} - -enum FieldTypeValue { - FamilyId = 1, - StyleId = 2, - PreferredFamilyId = 16, - PreferredStyleId = 17, -}; - -enum PlatformFieldValue { - PlatformId_Unicode = 0, - PlatformId_Apple = 1, - PlatformId_Microsoft = 3 -}; - -QFontNames qt_getCanonicalFontNames(const uchar *table, quint32 bytes) -{ - QFontNames out; - const int NameRecordSize = 12; - const int MS_LangIdEnglish = 0x009; - - // get the name table - quint16 count; - quint16 string_offset; - const unsigned char *names; - - if (bytes < 8) - return out; - - if (qt_getUShort(table) != 0) - return out; - - count = qt_getUShort(table + 2); - string_offset = qt_getUShort(table + 4); - names = table + 6; - - if (string_offset >= bytes || 6 + count*NameRecordSize > string_offset) - return out; - - enum PlatformIdType { - NotFound = 0, - Unicode = 1, - Apple = 2, - Microsoft = 3 - }; - - PlatformIdType idStatus[4] = { NotFound, NotFound, NotFound, NotFound }; - int ids[4] = { -1, -1, -1, -1 }; - - for (int i = 0; i < count; ++i) { - // search for the correct name entries - - quint16 platform_id = qt_getUShort(names + i*NameRecordSize); - quint16 encoding_id = qt_getUShort(names + 2 + i*NameRecordSize); - quint16 language_id = qt_getUShort(names + 4 + i*NameRecordSize); - quint16 name_id = qt_getUShort(names + 6 + i*NameRecordSize); - - PlatformIdType *idType = nullptr; - int *id = nullptr; - - switch (name_id) { - case FamilyId: - idType = &idStatus[0]; - id = &ids[0]; - break; - case StyleId: - idType = &idStatus[1]; - id = &ids[1]; - break; - case PreferredFamilyId: - idType = &idStatus[2]; - id = &ids[2]; - break; - case PreferredStyleId: - idType = &idStatus[3]; - id = &ids[3]; - break; - default: - continue; - } - - quint16 length = qt_getUShort(names + 8 + i*NameRecordSize); - quint16 offset = qt_getUShort(names + 10 + i*NameRecordSize); - if (DWORD(string_offset + offset + length) > bytes) - continue; - - if ((platform_id == PlatformId_Microsoft - && (encoding_id == 0 || encoding_id == 1)) - && ((language_id & 0x3ff) == MS_LangIdEnglish - || *idType < Microsoft)) { - *id = i; - *idType = Microsoft; - } - // not sure if encoding id 4 for Unicode is utf16 or ucs4... - else if (platform_id == PlatformId_Unicode && encoding_id < 4 && *idType < Unicode) { - *id = i; - *idType = Unicode; - } - else if (platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0 && *idType < Apple) { - *id = i; - *idType = Apple; - } - } - - QString strings[4]; - for (int i = 0; i < 4; ++i) { - if (idStatus[i] == NotFound) - continue; - int id = ids[i]; - quint16 length = qt_getUShort(names + 8 + id * NameRecordSize); - quint16 offset = qt_getUShort(names + 10 + id * NameRecordSize); - const unsigned char *string = table + string_offset + offset; - strings[i] = readName(idStatus[i] != Apple, string, length); - } - - out.name = strings[0]; - out.style = strings[1]; - out.preferredName = strings[2]; - out.preferredStyle = strings[3]; - return out; -} - -} // namespace - -QString qt_getEnglishName(const QString &familyName, bool includeStyle) -{ - QString i18n_name; - QString faceName = familyName; - faceName.truncate(LF_FACESIZE - 1); - - HDC hdc = GetDC( 0 ); - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - faceName.toWCharArray(lf.lfFaceName); - lf.lfFaceName[faceName.size()] = 0; - lf.lfCharSet = DEFAULT_CHARSET; - HFONT hfont = CreateFontIndirect(&lf); - - if (!hfont) { - ReleaseDC(0, hdc); - return QString(); - } - - HGDIOBJ oldobj = SelectObject( hdc, hfont ); - - const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' ); - - // get the name table - unsigned char *table = 0; - - DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 ); - if ( bytes == GDI_ERROR ) { - // ### Unused variable - // int err = GetLastError(); - goto error; - } - - table = new unsigned char[bytes]; - GetFontData(hdc, name_tag, 0, table, bytes); - if ( bytes == GDI_ERROR ) - goto error; - - { - const QFontNames names = qt_getCanonicalFontNames(table, bytes); - i18n_name = names.name; - if (includeStyle) - i18n_name += QLatin1Char(' ') + names.style; - } -error: - delete [] table; - SelectObject( hdc, oldobj ); - DeleteObject( hfont ); - ReleaseDC( 0, hdc ); - - //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data()); - return i18n_name; -} - -// Note this duplicates parts of qt_getEnglishName, we should try to unify the two functions. -QFontNames qt_getCanonicalFontNames(const LOGFONT &lf) -{ - QFontNames fontNames; - HDC hdc = GetDC(0); - HFONT hfont = CreateFontIndirect(&lf); - - if (!hfont) { - ReleaseDC(0, hdc); - return fontNames; - } - - HGDIOBJ oldobj = SelectObject(hdc, hfont); - - // get the name table - QByteArray table; - const DWORD name_tag = MAKE_TAG('n', 'a', 'm', 'e'); - DWORD bytes = GetFontData(hdc, name_tag, 0, 0, 0); - if (bytes != GDI_ERROR) { - table.resize(bytes); - - if (GetFontData(hdc, name_tag, 0, table.data(), bytes) != GDI_ERROR) - fontNames = qt_getCanonicalFontNames(reinterpret_cast<const uchar*>(table.constData()), bytes); - } - - SelectObject(hdc, oldobj); - DeleteObject(hfont); - ReleaseDC(0, hdc); - - return fontNames; -} - -static QChar *createFontFile(const QString &faceName) -{ - QChar *faceNamePtr = nullptr; - if (!faceName.isEmpty()) { - const int nameLength = qMin(faceName.length(), LF_FACESIZE - 1); - faceNamePtr = new QChar[nameLength + 1]; - memcpy(static_cast<void *>(faceNamePtr), faceName.utf16(), sizeof(wchar_t) * nameLength); - faceNamePtr[nameLength] = 0; - } - return faceNamePtr; -} - -namespace { - struct StoreFontPayload { - StoreFontPayload(const QString &family, - QWindowsFontDatabase *fontDatabase) - : populatedFontFamily(family) - , windowsFontDatabase(fontDatabase) - {} - - QString populatedFontFamily; - QSet<QPair<QString,QString> > foundFontAndStyles; - QWindowsFontDatabase *windowsFontDatabase; - }; -} - -static bool addFontToDatabase(QString familyName, - QString styleName, - const LOGFONT &logFont, - const TEXTMETRIC *textmetric, - const FONTSIGNATURE *signature, - int type, - StoreFontPayload *sfp) -{ - // the "@family" fonts are just the same as "family". Ignore them. - if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_"))) - return false; - - uchar charSet = logFont.lfCharSet; - - static const int SMOOTH_SCALABLE = 0xffff; - const QString foundryName; // No such concept. - const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH); - const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); - const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE); - const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight; - const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal; - const bool antialias = false; - const QFont::Weight weight = QPlatformFontDatabase::weightFromInteger(textmetric->tmWeight); - const QFont::Stretch stretch = QFont::Unstretched; - -#ifndef QT_NO_DEBUG_OUTPUT - if (lcQpaFonts().isDebugEnabled()) { - QString message; - QTextStream str(&message); - str << __FUNCTION__ << ' ' << familyName << ' ' << charSet << " TTF=" << ttf; - if (type & DEVICE_FONTTYPE) - str << " DEVICE"; - if (type & RASTER_FONTTYPE) - str << " RASTER"; - if (type & TRUETYPE_FONTTYPE) - str << " TRUETYPE"; - str << " scalable=" << scalable << " Size=" << size - << " Style=" << style << " Weight=" << weight - << " stretch=" << stretch; - qCDebug(lcQpaFonts) << message; - } -#endif - QString englishName; - QString faceName; - - QString subFamilyName; - QString subFamilyStyle; - // Look-up names registered in the font - QFontNames canonicalNames = qt_getCanonicalFontNames(logFont); - if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty()) - englishName = canonicalNames.name; - if (!canonicalNames.preferredName.isEmpty()) { - subFamilyName = familyName; - subFamilyStyle = styleName; - faceName = familyName; // Remember the original name for later lookups - familyName = canonicalNames.preferredName; - styleName = canonicalNames.preferredStyle; - } - - QSupportedWritingSystems writingSystems; - if (type & TRUETYPE_FONTTYPE) { - Q_ASSERT(signature); - quint32 unicodeRange[4] = { - signature->fsUsb[0], signature->fsUsb[1], - signature->fsUsb[2], signature->fsUsb[3] - }; - quint32 codePageRange[2] = { - signature->fsCsb[0], signature->fsCsb[1] - }; - writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains - // the symbol for Baht, and Windows thus reports that it supports the Thai script. - // Since it's the default UI font on this platform, most widgets will be unable to - // display Thai text by default. As a temporary work around, we special case Segoe UI - // and remove the Thai script from its list of supported writing systems. - if (writingSystems.supported(QFontDatabase::Thai) && - familyName == QLatin1String("Segoe UI")) - writingSystems.setSupported(QFontDatabase::Thai, false); - } else { - const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet); - if (ws != QFontDatabase::Any) - writingSystems.setSupported(ws); - } - - // We came here from populating a different font family, so we have - // to ensure the entire typographic family is populated before we - // mark it as such inside registerFont() - if (!subFamilyName.isEmpty() - && familyName != subFamilyName - && sfp->populatedFontFamily != familyName - && !QPlatformFontDatabase::isFamilyPopulated(familyName)) { - sfp->windowsFontDatabase->populateFamily(familyName); - } - - QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); - - // add fonts windows can generate for us: - if (weight <= QFont::DemiBold && styleName.isEmpty()) - QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); - if (style != QFont::StyleItalic && styleName.isEmpty()) - QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, - QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); - if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty()) - QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold, - QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); - - if (!subFamilyName.isEmpty() && familyName != subFamilyName) { - QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); - } - - if (!englishName.isEmpty() && englishName != familyName) - QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName); - - return true; -} - -static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric, - DWORD type, LPARAM lparam) -{ - const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont); - const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName); - const QString styleName = QString::fromWCharArray(f->elfStyle); - - // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according - // to the documentation is identical to a TEXTMETRIC except for the last four - // members, which we don't use anyway - const FONTSIGNATURE *signature = nullptr; - StoreFontPayload *sfp = reinterpret_cast<StoreFontPayload *>(lparam); - Q_ASSERT(sfp != nullptr); - if (type & TRUETYPE_FONTTYPE) { - signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig; - // We get a callback for each script-type supported, but we register them all - // at once using the signature, so we only need one call to addFontToDatabase(). - QPair<QString,QString> fontAndStyle(familyName, styleName); - if (sfp->foundFontAndStyles.contains(fontAndStyle)) - return 1; - sfp->foundFontAndStyles.insert(fontAndStyle); - } - addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp); - - // keep on enumerating - return 1; -} - -void QWindowsFontDatabase::populateFamily(const QString &familyName) -{ - qCDebug(lcQpaFonts) << familyName; - if (familyName.size() >= LF_FACESIZE) { - qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\''; - return; - } - HDC dummy = GetDC(0); - LOGFONT lf; - lf.lfCharSet = DEFAULT_CHARSET; - familyName.toWCharArray(lf.lfFaceName); - lf.lfFaceName[familyName.size()] = 0; - lf.lfPitchAndFamily = 0; - StoreFontPayload sfp(familyName, this); - EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&sfp), 0); - ReleaseDC(0, dummy); -} - -static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric, - DWORD, LPARAM) -{ - // the "@family" fonts are just the same as "family". Ignore them. - const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont); - const wchar_t *faceNameW = f->elfLogFont.lfFaceName; - if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) { - const QString faceName = QString::fromWCharArray(faceNameW); - QPlatformFontDatabase::registerFontFamily(faceName); - // Register current font's english name as alias - const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); - if (ttf && qt_localizedName(faceName)) { - const QString englishName = qt_getEnglishName(faceName); - if (!englishName.isEmpty()) - QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName); - } - } - return 1; // continue -} - -void QWindowsFontDatabase::addDefaultEUDCFont() -{ - const QString path = QWinRegistryKey(HKEY_CURRENT_USER, LR"(EUDC\1252)") - .stringValue(L"SystemDefaultEUDCFont"); - if (!path.isEmpty()) { - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) { - qCWarning(lcQpaFonts) << "Unable to open default EUDC font:" << path; - return; - } - - m_eudcFonts = addApplicationFont(file.readAll(), path); - } -} - -void QWindowsFontDatabase::populateFontDatabase() -{ - removeApplicationFonts(); - HDC dummy = GetDC(0); - LOGFONT lf; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfFaceName[0] = 0; - lf.lfPitchAndFamily = 0; - EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0); - ReleaseDC(0, dummy); - // Work around EnumFontFamiliesEx() not listing the system font. - QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().family(); - if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily) - QPlatformFontDatabase::registerFontFamily(systemDefaultFamily); - addDefaultEUDCFont(); -} - -typedef QSharedPointer<QWindowsFontEngineData> QWindowsFontEngineDataPtr; - -typedef QThreadStorage<QWindowsFontEngineDataPtr> FontEngineThreadLocalData; - -Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData) - -QSharedPointer<QWindowsFontEngineData> sharedFontData() -{ - FontEngineThreadLocalData *data = fontEngineThreadLocalData(); - if (!data->hasLocalData()) - data->setLocalData(QSharedPointer<QWindowsFontEngineData>::create()); - return data->localData(); -} - -QWindowsFontDatabase::QWindowsFontDatabase() -{ - // Properties accessed by QWin32PrintEngine (Qt Print Support) - static const int hfontMetaTypeId = qRegisterMetaType<HFONT>(); - static const int logFontMetaTypeId = qRegisterMetaType<LOGFONT>(); - Q_UNUSED(hfontMetaTypeId) - Q_UNUSED(logFontMetaTypeId) - - if (lcQpaFonts().isDebugEnabled()) { - const QWindowsFontEngineDataPtr data = sharedFontData(); - qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: " - << data->clearTypeEnabled << "gamma: " << data->fontSmoothingGamma; - } -} - -QWindowsFontDatabase::~QWindowsFontDatabase() -{ - removeApplicationFonts(); -} - -QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) -{ - const QString faceName(static_cast<const QChar*>(handle)); - QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName, - defaultVerticalDPI(), - sharedFontData()); - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle; - return fe; -} - -QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - EmbeddedFont font(fontData); - QFontEngine *fontEngine = 0; - -#if !defined(QT_NO_DIRECTWRITE) - if (!useDirectWrite(hintingPreference)) -#endif - { - GUID guid; - CoCreateGuid(&guid); - -QT_WARNING_PUSH -QT_WARNING_DISABLE_GCC("-Wstrict-aliasing") - QString uniqueFamilyName = QLatin1Char('f') - + QString::number(guid.Data1, 36) + QLatin1Char('-') - + QString::number(guid.Data2, 36) + QLatin1Char('-') - + QString::number(guid.Data3, 36) + QLatin1Char('-') - + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36); -QT_WARNING_POP - - QString actualFontName = font.changeFamilyName(uniqueFamilyName); - if (actualFontName.isEmpty()) { - qWarning("%s: Can't change family name of font", __FUNCTION__); - return 0; - } - - DWORD count = 0; - QByteArray newFontData = font.data(); - HANDLE fontHandle = - AddFontMemResourceEx(const_cast<char *>(newFontData.constData()), - DWORD(newFontData.size()), 0, &count); - if (count == 0 && fontHandle != 0) { - RemoveFontMemResourceEx(fontHandle); - fontHandle = 0; - } - - if (fontHandle == 0) { - qWarning("%s: AddFontMemResourceEx failed", __FUNCTION__); - } else { - QFontDef request; - request.family = uniqueFamilyName; - request.pixelSize = pixelSize; - request.styleStrategy = QFont::PreferMatch; - request.hintingPreference = hintingPreference; - request.stretch = QFont::Unstretched; - - fontEngine = QWindowsFontDatabase::createEngine(request, QString(), - defaultVerticalDPI(), - sharedFontData()); - - if (fontEngine) { - if (request.family != fontEngine->fontDef.family) { - qWarning("%s: Failed to load font. Got fallback instead: %s", - __FUNCTION__, qPrintable(fontEngine->fontDef.family)); - if (fontEngine->ref.loadRelaxed() == 0) - delete fontEngine; - fontEngine = 0; - } else { - Q_ASSERT(fontEngine->ref.loadRelaxed() == 0); - - // Override the generated font name - switch (fontEngine->type()) { - case QFontEngine::Win: - static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName); - fontEngine->fontDef.family = actualFontName; - break; - -#if !defined(QT_NO_DIRECTWRITE) - case QFontEngine::DirectWrite: - static_cast<QWindowsFontEngineDirectWrite *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName); - fontEngine->fontDef.family = actualFontName; - break; -#endif // !QT_NO_DIRECTWRITE - - default: - Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled font engine."); - } - - UniqueFontData uniqueData; - uniqueData.handle = fontHandle; - uniqueData.refCount.ref(); - m_uniqueFontData[uniqueFamilyName] = uniqueData; - } - } else { - RemoveFontMemResourceEx(fontHandle); - } - } - } -#if !defined(QT_NO_DIRECTWRITE) - else { - CustomFontFileLoader fontFileLoader; - fontFileLoader.addKey(this, fontData); - - QSharedPointer<QWindowsFontEngineData> fontEngineData = sharedFontData(); - if (!initDirectWrite(fontEngineData.data())) - return 0; - - IDWriteFontFile *fontFile = 0; - void *key = this; - - HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key, - sizeof(void *), - fontFileLoader.loader(), - &fontFile); - if (FAILED(hres)) { - qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__); - return 0; - } - - BOOL isSupportedFontType; - DWRITE_FONT_FILE_TYPE fontFileType; - DWRITE_FONT_FACE_TYPE fontFaceType; - UINT32 numberOfFaces; - fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces); - if (!isSupportedFontType) { - fontFile->Release(); - return 0; - } - - IDWriteFontFace *directWriteFontFace = 0; - hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType, - 1, - &fontFile, - 0, - DWRITE_FONT_SIMULATIONS_NONE, - &directWriteFontFace); - if (FAILED(hres)) { - qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__); - fontFile->Release(); - return 0; - } - - fontFile->Release(); - - fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace, - pixelSize, - fontEngineData); - - // Get font family from font data - fontEngine->fontDef.family = font.familyName(); - fontEngine->fontDef.hintingPreference = hintingPreference; - - directWriteFontFace->Release(); - } -#endif - - // Get style and weight info - if (fontEngine != 0) { - TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2"); - if (os2TableEntry != 0) { - const OS2Table *os2Table = - reinterpret_cast<const OS2Table *>(fontData.constData() - + qFromBigEndian<quint32>(os2TableEntry->offset)); - - bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0); - bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9); - - if (italic) - fontEngine->fontDef.style = QFont::StyleItalic; - else if (oblique) - fontEngine->fontDef.style = QFont::StyleOblique; - else - fontEngine->fontDef.style = QFont::StyleNormal; - - fontEngine->fontDef.weight = QPlatformFontDatabase::weightFromInteger(qFromBigEndian<quint16>(os2Table->weightClass)); - } - } - - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine; - return fontEngine; -} - -static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData) -{ - QList<quint32> offsets; - const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData); - if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) { - if (headerTag != MAKE_TAG(0, 1, 0, 0) - && headerTag != MAKE_TAG('O', 'T', 'T', 'O') - && headerTag != MAKE_TAG('t', 'r', 'u', 'e') - && headerTag != MAKE_TAG('t', 'y', 'p', '1')) - return offsets; - offsets << 0; - return offsets; - } - const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8); - for (uint i = 0; i < numFonts; ++i) { - offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4); - } - return offsets; -} - -static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length) -{ - const quint16 numTables = qFromBigEndian<quint16>(data + 4); - for (uint i = 0; i < numTables; ++i) { - const quint32 offset = 12 + 16 * i; - if (*reinterpret_cast<const quint32 *>(data + offset) == tag) { - *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8); - *length = qFromBigEndian<quint32>(data + offset + 12); - return; - } - } - *table = 0; - *length = 0; - return; -} - -static void getFamiliesAndSignatures(const QByteArray &fontData, - QList<QFontNames> *families, - QVector<FONTSIGNATURE> *signatures, - QVector<QFontValues> *values) -{ - const uchar *data = reinterpret_cast<const uchar *>(fontData.constData()); - - QList<quint32> offsets = getTrueTypeFontOffsets(data); - if (offsets.isEmpty()) - return; - - for (int i = 0; i < offsets.count(); ++i) { - const uchar *font = data + offsets.at(i); - const uchar *table; - quint32 length; - getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length); - if (!table) - continue; - QFontNames names = qt_getCanonicalFontNames(table, length); - if (names.name.isEmpty()) - continue; - - families->append(std::move(names)); - - if (values || signatures) - getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length); - - if (values) { - QFontValues fontValues; - if (table && length >= 64) { - // Read in some details about the font, offset calculated based on the specification - fontValues.weight = qFromBigEndian<quint16>(table + 4); - - quint16 fsSelection = qFromBigEndian<quint16>(table + 62); - fontValues.isItalic = (fsSelection & 1) != 0; - fontValues.isUnderlined = (fsSelection & (1 << 1)) != 0; - fontValues.isOverstruck = (fsSelection & (1 << 4)) != 0; - } - values->append(std::move(fontValues)); - } - - if (signatures) { - FONTSIGNATURE signature; - if (table && length >= 86) { - // Offsets taken from OS/2 table in the TrueType spec - signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42); - signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46); - signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50); - signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54); - - signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78); - signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82); - } else { - memset(&signature, 0, sizeof(signature)); - } - signatures->append(signature); - } - } -} - -QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) -{ - WinApplicationFont font; - font.fileName = fileName; - QVector<FONTSIGNATURE> signatures; - QVector<QFontValues> fontValues; - QList<QFontNames> families; - QStringList familyNames; - - if (!fontData.isEmpty()) { - getFamiliesAndSignatures(fontData, &families, &signatures, &fontValues); - if (families.isEmpty()) - return familyNames; - - DWORD dummy = 0; - font.handle = - AddFontMemResourceEx(const_cast<char *>(fontData.constData()), - DWORD(fontData.size()), 0, &dummy); - if (font.handle == 0) - return QStringList(); - - // Memory fonts won't show up in enumeration, so do add them the hard way. - for (int j = 0; j < families.count(); ++j) { - const auto &family = families.at(j); - const QString &familyName = family.name; - const QString &styleName = family.style; - familyNames << familyName; - HDC hdc = GetDC(0); - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size())); - lf.lfCharSet = DEFAULT_CHARSET; - const QFontValues &values = fontValues.at(j); - lf.lfWeight = values.weight; - if (values.isItalic) - lf.lfItalic = TRUE; - if (values.isOverstruck) - lf.lfStrikeOut = TRUE; - if (values.isUnderlined) - lf.lfUnderline = TRUE; - HFONT hfont = CreateFontIndirect(&lf); - HGDIOBJ oldobj = SelectObject(hdc, hfont); - - TEXTMETRIC textMetrics; - GetTextMetrics(hdc, &textMetrics); - - StoreFontPayload sfp(familyName, this); - addFontToDatabase(familyName, styleName, lf, &textMetrics, &signatures.at(j), - TRUETYPE_FONTTYPE, &sfp); - - SelectObject(hdc, oldobj); - DeleteObject(hfont); - ReleaseDC(0, hdc); - } - } else { - QFile f(fileName); - if (!f.open(QIODevice::ReadOnly)) - return QStringList(); - QByteArray data = f.readAll(); - f.close(); - - getFamiliesAndSignatures(data, &families, nullptr, nullptr); - if (families.isEmpty()) - return QStringList(); - - if (AddFontResourceExW((wchar_t*)fileName.utf16(), FR_PRIVATE, 0) == 0) - return QStringList(); - - font.handle = 0; - - // Fonts based on files are added via populate, as they will show up in font enumeration. - for (int j = 0; j < families.count(); ++j) { - const QString familyName = families.at(j).name; - familyNames << familyName; - populateFamily(familyName); - } - } - - m_applicationFonts << font; - - return familyNames; -} - -void QWindowsFontDatabase::removeApplicationFonts() -{ - for (const WinApplicationFont &font : qAsConst(m_applicationFonts)) { - if (font.handle) { - RemoveFontMemResourceEx(font.handle); - } else { - RemoveFontResourceExW(reinterpret_cast<LPCWSTR>(font.fileName.utf16()), - FR_PRIVATE, nullptr); - } - } - m_applicationFonts.clear(); - m_eudcFonts.clear(); -} - -void QWindowsFontDatabase::releaseHandle(void *handle) -{ - const QChar *faceName = reinterpret_cast<const QChar *>(handle); - delete[] faceName; -} - -QString QWindowsFontDatabase::fontDir() const -{ - const QString result = QPlatformFontDatabase::fontDir(); - qCDebug(lcQpaFonts) << __FUNCTION__ << result; - return result; -} - -bool QWindowsFontDatabase::fontsAlwaysScalable() const -{ - return false; -} - -void QWindowsFontDatabase::derefUniqueFont(const QString &uniqueFont) -{ - if (m_uniqueFontData.contains(uniqueFont)) { - if (!m_uniqueFontData[uniqueFont].refCount.deref()) { - RemoveFontMemResourceEx(m_uniqueFontData[uniqueFont].handle); - m_uniqueFontData.remove(uniqueFont); - } - } -} - -void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont) -{ - if (m_uniqueFontData.contains(uniqueFont)) - m_uniqueFontData[uniqueFont].refCount.ref(); -} - -// ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont() -HFONT QWindowsFontDatabase::systemFont() -{ - static const auto stock_sysfont = - reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT)); - return stock_sysfont; -} - -// Creation functions - -static const char *other_tryFonts[] = { - "Arial", - "MS UI Gothic", - "Gulim", - "SimSun", - "PMingLiU", - "Arial Unicode MS", - 0 -}; - -static const char *jp_tryFonts [] = { - "MS UI Gothic", - "Arial", - "Gulim", - "SimSun", - "PMingLiU", - "Arial Unicode MS", - 0 -}; - -static const char *ch_CN_tryFonts [] = { - "SimSun", - "Arial", - "PMingLiU", - "Gulim", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char *ch_TW_tryFonts [] = { - "PMingLiU", - "Arial", - "SimSun", - "Gulim", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char *kr_tryFonts[] = { - "Gulim", - "Arial", - "PMingLiU", - "SimSun", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char **tryFonts = 0; - -LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request, const QString &faceName) -{ - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - - lf.lfHeight = -qRound(request.pixelSize); - lf.lfWidth = 0; - lf.lfEscapement = 0; - lf.lfOrientation = 0; - if (request.weight == 50) - lf.lfWeight = FW_DONTCARE; - else - lf.lfWeight = (request.weight*900)/99; - lf.lfItalic = request.style != QFont::StyleNormal; - lf.lfCharSet = DEFAULT_CHARSET; - - int strat = OUT_DEFAULT_PRECIS; - if (request.styleStrategy & QFont::PreferBitmap) { - strat = OUT_RASTER_PRECIS; - } else if (request.styleStrategy & QFont::PreferDevice) { - strat = OUT_DEVICE_PRECIS; - } else if (request.styleStrategy & QFont::PreferOutline) { - strat = OUT_OUTLINE_PRECIS; - } else if (request.styleStrategy & QFont::ForceOutline) { - strat = OUT_TT_ONLY_PRECIS; - } - - lf.lfOutPrecision = strat; - - int qual = DEFAULT_QUALITY; - - if (request.styleStrategy & QFont::PreferMatch) - qual = DRAFT_QUALITY; - else if (request.styleStrategy & QFont::PreferQuality) - qual = PROOF_QUALITY; - - if (request.styleStrategy & QFont::PreferAntialias) { - qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0 - ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY; - } else if (request.styleStrategy & QFont::NoAntialias) { - qual = NONANTIALIASED_QUALITY; - } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && sharedFontData()->clearTypeEnabled) { - qual = ANTIALIASED_QUALITY; - } - - lf.lfQuality = qual; - - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - - int hint = FF_DONTCARE; - switch (request.styleHint) { - case QFont::Helvetica: - hint = FF_SWISS; - break; - case QFont::Times: - hint = FF_ROMAN; - break; - case QFont::Courier: - hint = FF_MODERN; - break; - case QFont::OldEnglish: - hint = FF_DECORATIVE; - break; - case QFont::System: - hint = FF_MODERN; - break; - default: - break; - } - - lf.lfPitchAndFamily = DEFAULT_PITCH | hint; - - QString fam = faceName; - if (fam.isEmpty()) - fam = request.families.size() > 0 ? request.families.at(0) : request.family; - if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) { - qCritical("%s: Family name '%s' is too long.", __FUNCTION__, qPrintable(fam)); - fam.truncate(LF_FACESIZE - 1); - } - - if (fam.isEmpty()) - fam = QStringLiteral("MS Sans Serif"); - - if (fam == QLatin1String("MS Sans Serif") - && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) { - fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale - } - if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap)) - fam = QStringLiteral("Courier New"); - - memcpy(lf.lfFaceName, fam.utf16(), fam.size() * sizeof(wchar_t)); - - return lf; -} - -QStringList QWindowsFontDatabase::extraTryFontsForFamily(const QString &family) -{ - QStringList result; - QFontDatabase db; - if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) { - if (!tryFonts) { - LANGID lid = GetUserDefaultLangID(); - switch (lid&0xff) { - case LANG_CHINESE: // Chinese - if ( lid == 0x0804 || lid == 0x1004) // China mainland and Singapore - tryFonts = ch_CN_tryFonts; - else - tryFonts = ch_TW_tryFonts; // Taiwan, Hong Kong and Macau - break; - case LANG_JAPANESE: - tryFonts = jp_tryFonts; - break; - case LANG_KOREAN: - tryFonts = kr_tryFonts; - break; - default: - tryFonts = other_tryFonts; - break; - } - } - QFontDatabase db; - const QStringList families = db.families(); - const char **tf = tryFonts; - while (tf && *tf) { - // QTBUG-31689, family might be an English alias for a localized font name. - const QString family = QString::fromLatin1(*tf); - if (families.contains(family) || db.hasFamily(family)) - result << family; - ++tf; - } - } - result.append(QStringLiteral("Segoe UI Emoji")); - result.append(QStringLiteral("Segoe UI Symbol")); - return result; -} - -QString QWindowsFontDatabase::familyForStyleHint(QFont::StyleHint styleHint) -{ - switch (styleHint) { - case QFont::Times: - return QStringLiteral("Times New Roman"); - case QFont::Courier: - return QStringLiteral("Courier New"); - case QFont::Monospace: - return QStringLiteral("Courier New"); - case QFont::Cursive: - return QStringLiteral("Comic Sans MS"); - case QFont::Fantasy: - return QStringLiteral("Impact"); - case QFont::Decorative: - return QStringLiteral("Old English"); - case QFont::Helvetica: - return QStringLiteral("Arial"); - case QFont::System: - default: - break; - } - return QStringLiteral("MS Shell Dlg 2"); -} - -QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const -{ - QStringList result; - result.append(QWindowsFontDatabase::familyForStyleHint(styleHint)); - result.append(m_eudcFonts); - result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); - result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script)); - - qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint - << script << result; - return result; -} - - -QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const QString &faceName, - int dpi, - const QSharedPointer<QWindowsFontEngineData> &data) -{ - QFontEngine *fe = 0; - - LOGFONT lf = fontDefToLOGFONT(request, faceName); - const bool preferClearTypeAA = lf.lfQuality == CLEARTYPE_QUALITY; - - if (request.stretch != 100) { - HFONT hfont = CreateFontIndirect(&lf); - if (!hfont) { - qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__); - hfont = QWindowsFontDatabase::systemFont(); - } - - HGDIOBJ oldObj = SelectObject(data->hdc, hfont); - TEXTMETRIC tm; - if (!GetTextMetrics(data->hdc, &tm)) - qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__); - else - lf.lfWidth = tm.tmAveCharWidth * request.stretch / 100; - SelectObject(data->hdc, oldObj); - - DeleteObject(hfont); - } - -#if !defined(QT_NO_DIRECTWRITE) - if (initDirectWrite(data.data())) { - const QString fam = QString::fromWCharArray(lf.lfFaceName); - const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam); - if (nameSubstitute != fam) { - const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1); - memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t)); - lf.lfFaceName[nameSubstituteLength] = 0; - } - - HFONT hfont = CreateFontIndirect(&lf); - if (!hfont) { - qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__); - } else { - HGDIOBJ oldFont = SelectObject(data->hdc, hfont); - - const QFont::HintingPreference hintingPreference = - static_cast<QFont::HintingPreference>(request.hintingPreference); - bool useDw = useDirectWrite(hintingPreference, fam); - - IDWriteFontFace *directWriteFontFace = NULL; - HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace); - if (SUCCEEDED(hr)) { - bool isColorFont = false; -#if defined(QT_USE_DIRECTWRITE2) - IDWriteFontFace2 *directWriteFontFace2 = nullptr; - if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2), - reinterpret_cast<void **>(&directWriteFontFace2)))) { - if (directWriteFontFace2->IsColorFont()) - isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0; - } -#endif - useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont); - qCDebug(lcQpaFonts) << __FUNCTION__ << request.family << request.pointSize - << "pt" << "hintingPreference=" << hintingPreference << "color=" << isColorFont - << dpi << "dpi" << "useDirectWrite=" << useDw; - if (useDw) { - QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, - request.pixelSize, - data); - - wchar_t n[64]; - GetTextFace(data->hdc, 64, n); - - QFontDef fontDef = request; - fontDef.family = QString::fromWCharArray(n); - - if (isColorFont) - fedw->glyphFormat = QFontEngine::Format_ARGB; - fedw->initFontInfo(fontDef, dpi); - fe = fedw; - } else { - directWriteFontFace->Release(); - } - } else if (useDw) { - const QString errorString = qt_error_string(int(hr)); - qWarning().noquote().nospace() << "DirectWrite: CreateFontFaceFromHDC() failed (" - << errorString << ") for " << request << ' ' << lf << " dpi=" << dpi; - } - - SelectObject(data->hdc, oldFont); - DeleteObject(hfont); - } - } -#endif // QT_NO_DIRECTWRITE - - if (!fe) { - QWindowsFontEngine *few = new QWindowsFontEngine(request.family, lf, data); - if (preferClearTypeAA) - few->glyphFormat = QFontEngine::Format_A32; - few->initFontInfo(request, dpi); - fe = few; - } - - return fe; -} - -QFont QWindowsFontDatabase::systemDefaultFont() -{ -#if QT_VERSION >= 0x060000 - // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610) - NONCLIENTMETRICS ncm; - ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0); - const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); -#else - LOGFONT lf; - GetObject(QWindowsFontDatabase::systemFont(), sizeof(lf), &lf); - QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(lf); - // "MS Shell Dlg 2" is the correct system font >= Win2k - if (systemFont.family() == QLatin1String("MS Shell Dlg")) - systemFont.setFamily(QStringLiteral("MS Shell Dlg 2")); - // Qt 5 by (Qt 4) legacy uses GetStockObject(DEFAULT_GUI_FONT) to - // obtain the default GUI font (typically "MS Shell Dlg 2, 8pt"). This has been - // long deprecated; the message font of the NONCLIENTMETRICS structure obtained by - // SystemParametersInfo(SPI_GETNONCLIENTMETRICS) should be used instead (see - // QWindowsTheme::refreshFonts(), typically "Segoe UI, 9pt"), which is larger. -#endif // Qt 5 - qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; - return systemFont; -} - -QFont QWindowsFontDatabase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In) -{ - if (verticalDPI_In <= 0) - verticalDPI_In = defaultVerticalDPI(); - QFont qFont(QString::fromWCharArray(logFont.lfFaceName)); - qFont.setItalic(logFont.lfItalic); - if (logFont.lfWeight != FW_DONTCARE) - qFont.setWeight(QPlatformFontDatabase::weightFromInteger(logFont.lfWeight)); - const qreal logFontHeight = qAbs(logFont.lfHeight); - qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In)); - qFont.setUnderline(logFont.lfUnderline); - qFont.setOverline(false); - qFont.setStrikeOut(logFont.lfStrikeOut); - return qFont; -} - -int QWindowsFontDatabase::defaultVerticalDPI() -{ - static int vDPI = -1; - if (vDPI == -1) { - if (HDC defaultDC = GetDC(0)) { - vDPI = GetDeviceCaps(defaultDC, LOGPIXELSY); - ReleaseDC(0, defaultDC); - } else { - // FIXME: Resolve now or return 96 and keep unresolved? - vDPI = 96; - } - } - return vDPI; -} - -bool QWindowsFontDatabase::isPrivateFontFamily(const QString &family) const -{ - return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family); -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp deleted file mode 100644 index 5c2742d295..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/**************************************************************************** -** -** 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 "qwindowsfontdatabase_ft_p.h" -#include "qwindowsfontdatabase_p.h" - -#include <QtFontDatabaseSupport/private/qfontengine_ft_p.h> - -#include <ft2build.h> -#include FT_TRUETYPE_TABLES_H - -#include <QtCore/QDir> -#include <QtCore/QDirIterator> -#include <QtCore/QSettings> -#if QT_CONFIG(regularexpression) -#include <QtCore/QRegularExpression> -#else -#include <QtCore/QRegExp> -#endif -#include <QtGui/QGuiApplication> -#include <QtGui/QFontDatabase> - -#include <wchar.h> - -QT_BEGIN_NAMESPACE - -static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet) -{ - switch (charSet) { - case ANSI_CHARSET: - case EASTEUROPE_CHARSET: - case BALTIC_CHARSET: - case TURKISH_CHARSET: - return QFontDatabase::Latin; - case GREEK_CHARSET: - return QFontDatabase::Greek; - case RUSSIAN_CHARSET: - return QFontDatabase::Cyrillic; - case HEBREW_CHARSET: - return QFontDatabase::Hebrew; - case ARABIC_CHARSET: - return QFontDatabase::Arabic; - case THAI_CHARSET: - return QFontDatabase::Thai; - case GB2312_CHARSET: - return QFontDatabase::SimplifiedChinese; - case CHINESEBIG5_CHARSET: - return QFontDatabase::TraditionalChinese; - case SHIFTJIS_CHARSET: - return QFontDatabase::Japanese; - case HANGUL_CHARSET: - case JOHAB_CHARSET: - return QFontDatabase::Korean; - case VIETNAMESE_CHARSET: - return QFontDatabase::Vietnamese; - case SYMBOL_CHARSET: - return QFontDatabase::Symbol; - default: - break; - } - return QFontDatabase::Any; -} - -static FontFile * createFontFile(const QString &fileName, int index) -{ - FontFile *fontFile = new FontFile; - fontFile->fileName = fileName; - fontFile->indexValue = index; - return fontFile; -} - -namespace { -struct FontKey -{ - QString fileName; - QStringList fontNames; -}; -} // namespace - -typedef QVector<FontKey> FontKeys; - -static FontKeys &fontKeys() -{ - static FontKeys result; - if (result.isEmpty()) { - const QStringList keys = { QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), - QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") }; - for (const auto key : keys) { - const QSettings fontRegistry(key, QSettings::NativeFormat); - const QStringList allKeys = fontRegistry.allKeys(); - const QString trueType = QStringLiteral("(TrueType)"); -#if QT_CONFIG(regularexpression) - const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+")); -#else - const QRegExp sizeListMatch(QLatin1String("\\s(\\d+,)+\\d+")); -#endif - Q_ASSERT(sizeListMatch.isValid()); - const int size = allKeys.size(); - result.reserve(result.size() + size); - for (int i = 0; i < size; ++i) { - FontKey fontKey; - const QString ®istryFontKey = allKeys.at(i); - fontKey.fileName = fontRegistry.value(registryFontKey).toString(); - QString realKey = registryFontKey; - realKey.remove(trueType); - realKey.remove(sizeListMatch); - const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&')); - fontKey.fontNames.reserve(fontNames.size()); - for (const QStringRef &fontName : fontNames) - fontKey.fontNames.append(fontName.trimmed().toString()); - result.append(fontKey); - } - } - } - return result; -} - -static const FontKey *findFontKey(const QString &name, int *indexIn = nullptr) -{ - const FontKeys &keys = fontKeys(); - for (auto it = keys.constBegin(), cend = keys.constEnd(); it != cend; ++it) { - const int index = it->fontNames.indexOf(name); - if (index >= 0) { - if (indexIn) - *indexIn = index; - return &(*it); - } - } - if (indexIn) - *indexIn = -1; - return nullptr; -} - -static bool addFontToDatabase(QString familyName, - QString styleName, - const QString &fullName, - const LOGFONT &logFont, - const TEXTMETRIC *textmetric, - const FONTSIGNATURE *signature, - int type) -{ - // the "@family" fonts are just the same as "family". Ignore them. - if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_"))) - return false; - - uchar charSet = logFont.lfCharSet; - - static const int SMOOTH_SCALABLE = 0xffff; - const QString foundryName; // No such concept. - const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH); - const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); - const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE); - const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight; - const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal; - const bool antialias = false; - const QFont::Weight weight = QPlatformFontDatabase::weightFromInteger(textmetric->tmWeight); - const QFont::Stretch stretch = QFont::Unstretched; - -#ifndef QT_NO_DEBUG_STREAM - if (lcQpaFonts().isDebugEnabled()) { - QString message; - QTextStream str(&message); - str << __FUNCTION__ << ' ' << familyName << "::" << fullName << ' ' << charSet << " TTF=" << ttf; - if (type & DEVICE_FONTTYPE) - str << " DEVICE"; - if (type & RASTER_FONTTYPE) - str << " RASTER"; - if (type & TRUETYPE_FONTTYPE) - str << " TRUETYPE"; - str << " scalable=" << scalable << " Size=" << size - << " Style=" << style << " Weight=" << weight - << " stretch=" << stretch; - qCDebug(lcQpaFonts) << message; - } -#endif - - QString englishName; - QString faceName = familyName; - - QString subFamilyName; - QString subFamilyStyle; - // Look-up names registered in the font - QFontNames canonicalNames = qt_getCanonicalFontNames(logFont); - if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty()) - englishName = canonicalNames.name; - if (!canonicalNames.preferredName.isEmpty()) { - subFamilyName = familyName; - subFamilyStyle = styleName; - familyName = canonicalNames.preferredName; - styleName = canonicalNames.preferredStyle; - } - - QSupportedWritingSystems writingSystems; - if (type & TRUETYPE_FONTTYPE) { - Q_ASSERT(signature); - quint32 unicodeRange[4] = { - signature->fsUsb[0], signature->fsUsb[1], - signature->fsUsb[2], signature->fsUsb[3] - }; - quint32 codePageRange[2] = { - signature->fsCsb[0], signature->fsCsb[1] - }; - writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains - // the symbol for Baht, and Windows thus reports that it supports the Thai script. - // Since it's the default UI font on this platform, most widgets will be unable to - // display Thai text by default. As a temporary work around, we special case Segoe UI - // and remove the Thai script from its list of supported writing systems. - if (writingSystems.supported(QFontDatabase::Thai) && - faceName == QLatin1String("Segoe UI")) - writingSystems.setSupported(QFontDatabase::Thai, false); - } else { - const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet); - if (ws != QFontDatabase::Any) - writingSystems.setSupported(ws); - } - - int index = 0; - const FontKey *key = findFontKey(fullName, &index); - if (!key) { - // On non-English locales, the styles of the font may be localized in enumeration, but - // not in the registry. - QLocale systemLocale = QLocale::system(); - if (systemLocale.language() != QLocale::C - && systemLocale.language() != QLocale::English - && styleName != QLatin1String("Italic") - && styleName != QLatin1String("Bold")) { - key = findFontKey(qt_getEnglishName(fullName, true), &index); - } - if (!key) - key = findFontKey(faceName, &index); - if (!key && !englishName.isEmpty()) - key = findFontKey(englishName, &index); - if (!key) - return false; - } - QString value = key->fileName; - if (value.isEmpty()) - return false; - - if (!QDir::isAbsolutePath(value)) - value.prepend(QFile::decodeName(qgetenv("windir") + "\\Fonts\\")); - - QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch, - antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); - - // add fonts windows can generate for us: - if (weight <= QFont::DemiBold && styleName.isEmpty()) - QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold, style, stretch, - antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); - - if (style != QFont::StyleItalic && styleName.isEmpty()) - QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, QFont::StyleItalic, stretch, - antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); - - if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty()) - QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold, QFont::StyleItalic, stretch, - antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); - - if (!subFamilyName.isEmpty() && familyName != subFamilyName) { - QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); - } - - if (!englishName.isEmpty() && englishName != familyName) - QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName); - - return true; -} - -static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric, - DWORD type, LPARAM lparam) -{ - const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont); - const QString faceName = QString::fromWCharArray(f->elfLogFont.lfFaceName); - const QString styleName = QString::fromWCharArray(f->elfStyle); - const QString fullName = QString::fromWCharArray(f->elfFullName); - - // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according - // to the documentation is identical to a TEXTMETRIC except for the last four - // members, which we don't use anyway - const FONTSIGNATURE *signature = nullptr; - if (type & TRUETYPE_FONTTYPE) { - signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig; - // We get a callback for each script-type supported, but we register them all - // at once using the signature, so we only need one call to addFontToDatabase(). - QSet<QPair<QString,QString>> *foundFontAndStyles = reinterpret_cast<QSet<QPair<QString,QString>> *>(lparam); - QPair<QString,QString> fontAndStyle(faceName, styleName); - if (foundFontAndStyles->contains(fontAndStyle)) - return 1; - foundFontAndStyles->insert(fontAndStyle); - } - addFontToDatabase(faceName, styleName, fullName, *logFont, textmetric, signature, type); - - // keep on enumerating - return 1; -} - -/*! - \brief Populate font database using EnumFontFamiliesEx(). - - Normally, leaving the name empty should enumerate - all fonts, however, system fonts like "MS Shell Dlg 2" - are only found when specifying the name explicitly. -*/ - -void QWindowsFontDatabaseFT::populateFamily(const QString &familyName) -{ - qCDebug(lcQpaFonts) << familyName; - if (familyName.size() >= LF_FACESIZE) { - qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\''; - return; - } - HDC dummy = GetDC(0); - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - familyName.toWCharArray(lf.lfFaceName); - lf.lfFaceName[familyName.size()] = 0; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfPitchAndFamily = 0; - QSet<QPair<QString,QString>> foundFontAndStyles; - EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&foundFontAndStyles), 0); - ReleaseDC(0, dummy); -} - -// Delayed population of font families - -static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric, - DWORD, LPARAM) -{ - const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont); - // the "@family" fonts are just the same as "family". Ignore them. - const wchar_t *faceNameW = f->elfLogFont.lfFaceName; - if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) { - // Register only font families for which a font file exists for delayed population - const bool ttf = textmetric->tmPitchAndFamily & TMPF_TRUETYPE; - const QString faceName = QString::fromWCharArray(faceNameW); - const FontKey *key = findFontKey(faceName); - if (!key) { - key = findFontKey(QString::fromWCharArray(f->elfFullName)); - if (!key && ttf && qt_localizedName(faceName)) - key = findFontKey(qt_getEnglishName(faceName)); - } - if (key) { - QPlatformFontDatabase::registerFontFamily(faceName); - // Register current font's english name as alias - if (ttf && qt_localizedName(faceName)) { - const QString englishName = qt_getEnglishName(faceName); - if (!englishName.isEmpty()) - QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName); - } - } - } - return 1; // continue -} - -void QWindowsFontDatabaseFT::populateFontDatabase() -{ - HDC dummy = GetDC(0); - LOGFONT lf; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfFaceName[0] = 0; - lf.lfPitchAndFamily = 0; - EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0); - ReleaseDC(0, dummy); - // Work around EnumFontFamiliesEx() not listing the system font - QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().family(); - if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily) - QPlatformFontDatabase::registerFontFamily(systemDefaultFamily); -} - -QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, void *handle) -{ - QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontDef, handle); - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.family << fe << handle; - return fe; -} - -QFontEngine *QWindowsFontDatabaseFT::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontData, pixelSize, hintingPreference); - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe; - return fe; -} - -QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const -{ - QStringList result; - result.append(QWindowsFontDatabase::familyForStyleHint(styleHint)); - result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); - result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script)); - - qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint - << script << result; - - return result; -} -QString QWindowsFontDatabaseFT::fontDir() const -{ - const QString result = QLatin1String(qgetenv("windir")) + QLatin1String("/Fonts");//QPlatformFontDatabase::fontDir(); - qCDebug(lcQpaFonts) << __FUNCTION__ << result; - return result; -} - -QFont QWindowsFontDatabaseFT::defaultFont() const -{ - return QWindowsFontDatabase::systemDefaultFont(); -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h deleted file mode 100644 index c3d201b3a0..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSFONTDATABASEFT_H -#define QWINDOWSFONTDATABASEFT_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h> -#include <QtCore/QSharedPointer> -#include <QtCore/qt_windows.h> - -QT_BEGIN_NAMESPACE - -class QWindowsFontDatabaseFT : public QFreeTypeFontDatabase -{ -public: - void populateFontDatabase() override; - void populateFamily(const QString &familyName) override; - QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; - QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, - QFont::HintingPreference hintingPreference) override; - - QStringList fallbacksForFamily(const QString &family, QFont::Style style, - QFont::StyleHint styleHint, - QChar::Script script) const override; - - QString fontDir() const override; - QFont defaultFont() const override; -}; - -QT_END_NAMESPACE - -#endif // QWINDOWSFONTDATABASEFT_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h deleted file mode 100644 index f132e69d4d..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h +++ /dev/null @@ -1,193 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSFONTDATABASE_H -#define QWINDOWSFONTDATABASE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <qpa/qplatformfontdatabase.h> -#include <QtCore/QSharedPointer> -#include <QtCore/QLoggingCategory> -#include <QtCore/qt_windows.h> - -#if !defined(QT_NO_DIRECTWRITE) - struct IDWriteFactory; - struct IDWriteGdiInterop; -#endif - -QT_BEGIN_NAMESPACE - -Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) - -class QWindowsFontEngineData -{ - Q_DISABLE_COPY_MOVE(QWindowsFontEngineData) -public: - QWindowsFontEngineData(); - ~QWindowsFontEngineData(); - - uint pow_gamma[256]; - - bool clearTypeEnabled = false; - qreal fontSmoothingGamma; - HDC hdc = 0; -#if !defined(QT_NO_DIRECTWRITE) - IDWriteFactory *directWriteFactory = nullptr; - IDWriteGdiInterop *directWriteGdiInterop = nullptr; -#endif -}; - -class QWindowsFontDatabase : public QPlatformFontDatabase -{ - Q_DISABLE_COPY_MOVE(QWindowsFontDatabase) -public: - enum FontOptions { - // Relevant bits from QWindowsIntegration::Options - DontUseDirectWriteFonts = 0x40, - DontUseColorFonts = 0x80 - }; - - QWindowsFontDatabase(); - ~QWindowsFontDatabase() override; - - void ensureFamilyPopulated(const QString &familyName); - - void populateFontDatabase() override; - void populateFamily(const QString &familyName) override; - QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; - QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; - QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override; - QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) override; - void releaseHandle(void *handle) override; - QString fontDir() const override; - - QFont defaultFont() const override { return systemDefaultFont(); } - bool fontsAlwaysScalable() const override; - void derefUniqueFont(const QString &uniqueFont); - void refUniqueFont(const QString &uniqueFont); - bool isPrivateFontFamily(const QString &family) const override; - - static QFont systemDefaultFont(); - - static QFontEngine *createEngine(const QFontDef &request, const QString &faceName, - int dpi, - const QSharedPointer<QWindowsFontEngineData> &data); - - static HFONT systemFont(); - static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0); - - static qreal fontSmoothingGamma(); - static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef, const QString &faceName); - - static QStringList extraTryFontsForFamily(const QString &family); - static QString familyForStyleHint(QFont::StyleHint styleHint); - - static int defaultVerticalDPI(); - - static void setFontOptions(unsigned options); - static unsigned fontOptions(); - -private: - void removeApplicationFonts(); - void addDefaultEUDCFont(); - - struct WinApplicationFont { - HANDLE handle; - QString fileName; - }; - - QList<WinApplicationFont> m_applicationFonts; - - struct UniqueFontData { - HANDLE handle; - QAtomicInt refCount; - }; - - QMap<QString, UniqueFontData> m_uniqueFontData; - - static unsigned m_fontOptions; - QStringList m_eudcFonts; -}; - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug, const QFontDef &def); -#endif - -inline quint16 qt_getUShort(const unsigned char *p) -{ - quint16 val; - val = *p++ << 8; - val |= *p; - - return val; -} - -struct QFontNames -{ - QString name; // e.g. "DejaVu Sans Condensed" - QString style; // e.g. "Italic" - QString preferredName; // e.g. "DejaVu Sans" - QString preferredStyle; // e.g. "Condensed Italic" -}; - -struct QFontValues -{ - quint16 weight = 0; - bool isItalic = false; - bool isOverstruck = false; - bool isUnderlined = false; -}; - -bool qt_localizedName(const QString &name); -QString qt_getEnglishName(const QString &familyName, bool includeStyle = false); -QFontNames qt_getCanonicalFontNames(const LOGFONT &lf); - -QT_END_NAMESPACE - -#endif // QWINDOWSFONTDATABASE_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp deleted file mode 100644 index 2ae378c558..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp +++ /dev/null @@ -1,1211 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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 "qwindowsfontengine_p.h" -#include "qwindowsnativeimage_p.h" -#include "qwindowsfontdatabase_p.h" -#include <QtCore/qt_windows.h> -#include "qwindowsfontenginedirectwrite_p.h" - -#include <QtGui/qpa/qplatformintegration.h> -#include <QtGui/private/qtextengine_p.h> // glyph_metrics_t -#include <QtGui/private/qguiapplication_p.h> -#include <QtGui/QPaintDevice> -#include <QtGui/QBitmap> -#include <QtGui/QPainter> -#include <QtGui/private/qpainter_p.h> -#include <QtGui/QPaintEngine> -#include <QtGui/private/qpaintengine_raster_p.h> - -#include <QtCore/QtEndian> -#include <QtCore/QFile> -#include <QtCore/qmath.h> -#include <QtCore/QTextStream> -#include <QtCore/QThreadStorage> -#include <QtCore/private/qsystemlibrary_p.h> -#include <QtCore/private/qstringiterator_p.h> - -#include <QtCore/QDebug> - -#include <limits.h> - -#if !defined(QT_NO_DIRECTWRITE) -# include <dwrite.h> -# include <comdef.h> -#endif - -QT_BEGIN_NAMESPACE - -//### mingw needed define -#ifndef TT_PRIM_CSPLINE -#define TT_PRIM_CSPLINE 3 -#endif - -// GetFontData expects the tags in little endian ;( -#define MAKE_LITTLE_ENDIAN_TAG(ch1, ch2, ch3, ch4) (\ - (((quint32)(ch4)) << 24) | \ - (((quint32)(ch3)) << 16) | \ - (((quint32)(ch2)) << 8) | \ - ((quint32)(ch1)) \ - ) - -// common DC for all fonts - -typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT); -static PtrGetCharWidthI ptrGetCharWidthI = 0; -static bool resolvedGetCharWidthI = false; - -static void resolveGetCharWidthI() -{ - if (resolvedGetCharWidthI) - return; - resolvedGetCharWidthI = true; - ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI"); -} - -// general font engine - -QFixed QWindowsFontEngine::lineThickness() const -{ - if(lineWidth > 0) - return lineWidth; - - return QFontEngine::lineThickness(); -} - -static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc) -{ - const auto size = GetOutlineTextMetrics(hdc, 0, nullptr); - auto otm = reinterpret_cast<OUTLINETEXTMETRIC *>(malloc(size)); - GetOutlineTextMetrics(hdc, size, otm); - return otm; -} - -bool QWindowsFontEngine::hasCFFTable() const -{ - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('C', 'F', 'F', ' '), 0, 0, 0) != GDI_ERROR; -} - -bool QWindowsFontEngine::hasCMapTable() const -{ - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('c', 'm', 'a', 'p'), 0, 0, 0) != GDI_ERROR; -} - -static inline QString stringFromOutLineTextMetric(const OUTLINETEXTMETRIC *otm, PSTR offset) -{ - const uchar *p = reinterpret_cast<const uchar *>(otm) + quintptr(offset); - return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(p)); -} - -void QWindowsFontEngine::getCMap() -{ - ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE) || hasCMapTable(); - - cffTable = hasCFFTable(); - - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - bool symb = false; - if (ttf) { - cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p')); - cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()), - cmapTable.size(), &symb, &cmapSize); - } - if (!cmap) { - ttf = false; - symb = false; - } - symbol = symb; - designToDevice = 1; - _faceId.index = 0; - if(cmap) { - OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc); - unitsPerEm = int(otm->otmEMSquare); - const QFixed unitsPerEmF(unitsPerEm); - designToDevice = unitsPerEmF / QFixed::fromReal(fontDef.pixelSize); - x_height = int(otm->otmsXHeight); - loadKerningPairs(designToDevice); - _faceId.filename = QFile::encodeName(stringFromOutLineTextMetric(otm, otm->otmpFullName)); - lineWidth = otm->otmsUnderscoreSize; - fsType = otm->otmfsType; - free(otm); - - } else { - unitsPerEm = tm.tmHeight; - } -} - -int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const -{ - int glyph_pos = 0; - { - if (symbol) { - QStringIterator it(str, str + numChars); - while (it.hasNext()) { - const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); - if(!glyphs->glyphs[glyph_pos] && uc < 0x100) - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000); - ++glyph_pos; - } - } else if (ttf) { - QStringIterator it(str, str + numChars); - while (it.hasNext()) { - const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); - ++glyph_pos; - } - } else { - QStringIterator it(str, str + numChars); - while (it.hasNext()) { - const uint uc = it.next(); - if (uc >= tm.tmFirstChar && uc <= tm.tmLastChar) - glyphs->glyphs[glyph_pos] = uc; - else - glyphs->glyphs[glyph_pos] = 0; - ++glyph_pos; - } - } - } - glyphs->numGlyphs = glyph_pos; - return glyph_pos; -} - -/*! - \class QWindowsFontEngine - \brief Standard Windows font engine. - \internal - \ingroup qt-lighthouse-win - - Will probably be superseded by a common Free Type font engine in Qt 5.X. -*/ - -QWindowsFontEngine::QWindowsFontEngine(const QString &name, - LOGFONT lf, - const QSharedPointer<QWindowsFontEngineData> &fontEngineData) - : QFontEngine(Win), - m_fontEngineData(fontEngineData), - _name(name), - m_logfont(lf), - ttf(0), - hasOutline(0) -{ - qCDebug(lcQpaFonts) << __FUNCTION__ << name << lf.lfHeight; - hfont = CreateFontIndirect(&m_logfont); - if (!hfont) { - qErrnoWarning("%s: CreateFontIndirect failed for family '%s'", __FUNCTION__, qPrintable(name)); - hfont = QWindowsFontDatabase::systemFont(); - } - - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - const BOOL res = GetTextMetrics(hdc, &tm); - if (!res) { - qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__); - ZeroMemory(&tm, sizeof(TEXTMETRIC)); - } - - fontDef.pixelSize = -lf.lfHeight; - fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); - - cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000; - getCMap(); - - if (!resolvedGetCharWidthI) - resolveGetCharWidthI(); - - // ### Properties accessed by QWin32PrintEngine (QtPrintSupport) - QVariantMap userData; - userData.insert(QStringLiteral("logFont"), QVariant::fromValue(m_logfont)); - userData.insert(QStringLiteral("hFont"), QVariant::fromValue(hfont)); - userData.insert(QStringLiteral("trueType"), QVariant(bool(ttf))); - setUserData(userData); - - hasUnreliableOutline = (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) == 0; -} - -QWindowsFontEngine::~QWindowsFontEngine() -{ - if (designAdvances) - free(designAdvances); - - if (widthCache) - free(widthCache); - - // make sure we aren't by accident still selected - SelectObject(m_fontEngineData->hdc, QWindowsFontDatabase::systemFont()); - - if (!DeleteObject(hfont)) - qErrnoWarning("%s: QFontEngineWin: failed to delete font...", __FUNCTION__); - qCDebug(lcQpaFonts) << __FUNCTION__ << _name; - - if (!uniqueFamilyName.isEmpty()) { - if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) { - QPlatformFontDatabase *pfdb = pi->fontDatabase(); - static_cast<QWindowsFontDatabase *>(pfdb)->derefUniqueFont(uniqueFamilyName); - } - } -} - -glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const -{ - glyph_t glyph = 0; - - if (symbol) { - glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); - if (glyph == 0 && ucs4 < 0x100) - glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000); - } else if (ttf) { - glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); - } else if (ucs4 >= tm.tmFirstChar && ucs4 <= tm.tmLastChar) { - glyph = ucs4; - } - - return glyph; -} - -HGDIOBJ QWindowsFontEngine::selectDesignFont() const -{ - LOGFONT f = m_logfont; - f.lfHeight = -unitsPerEm; - f.lfWidth = 0; - HFONT designFont = CreateFontIndirect(&f); - return SelectObject(m_fontEngineData->hdc, designFont); -} - -bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const -{ - Q_ASSERT(glyphs->numGlyphs >= *nglyphs); - if (*nglyphs < len) { - *nglyphs = len; - return false; - } - - glyphs->numGlyphs = *nglyphs; - *nglyphs = getGlyphIndexes(str, len, glyphs); - - if (!(flags & GlyphIndicesOnly)) - recalcAdvances(glyphs, flags); - - return true; -} - -inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width) -{ - if (ptrGetCharWidthI) - ptrGetCharWidthI(hdc, glyph, 1, 0, &width); -} - -void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const -{ - HGDIOBJ oldFont = 0; - HDC hdc = m_fontEngineData->hdc; - if (ttf && (flags & DesignMetrics)) { - for(int i = 0; i < glyphs->numGlyphs; i++) { - unsigned int glyph = glyphs->glyphs[i]; - if(int(glyph) >= designAdvancesSize) { - const int newSize = int(glyph + 256) >> 8 << 8; - designAdvances = reinterpret_cast<QFixed *>(realloc(designAdvances, size_t(newSize) * sizeof(QFixed))); - Q_CHECK_PTR(designAdvances); - for(int i = designAdvancesSize; i < newSize; ++i) - designAdvances[i] = -1000000; - designAdvancesSize = newSize; - } - if (designAdvances[glyph] < -999999) { - if (!oldFont) - oldFont = selectDesignFont(); - - int width = 0; - calculateTTFGlyphWidth(hdc, glyph, width); - designAdvances[glyph] = QFixed(width) / designToDevice; - } - glyphs->advances[i] = designAdvances[glyph]; - } - if(oldFont) - DeleteObject(SelectObject(hdc, oldFont)); - } else { - for(int i = 0; i < glyphs->numGlyphs; i++) { - unsigned int glyph = glyphs->glyphs[i]; - - if (glyph >= widthCacheSize) { - const uint newSize = (glyph + 256) >> 8 << 8; - widthCache = reinterpret_cast<unsigned char *>(realloc(widthCache, newSize * sizeof(QFixed))); - Q_CHECK_PTR(widthCache); - memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize); - widthCacheSize = newSize; - } - glyphs->advances[i] = widthCache[glyph]; - // font-width cache failed - if (glyphs->advances[i].value() == 0) { - int width = 0; - if (!oldFont) - oldFont = SelectObject(hdc, hfont); - - if (!ttf) { - QChar ch[2] = { ushort(glyph), 0 }; - int chrLen = 1; - if (QChar::requiresSurrogates(glyph)) { - ch[0] = QChar::highSurrogate(glyph); - ch[1] = QChar::lowSurrogate(glyph); - ++chrLen; - } - SIZE size = {0, 0}; - GetTextExtentPoint32(hdc, reinterpret_cast<const wchar_t *>(ch), chrLen, &size); - width = size.cx; - } else { - calculateTTFGlyphWidth(hdc, glyph, width); - } - glyphs->advances[i] = width; - // if glyph's within cache range, store it for later - if (width > 0 && width < 0x100) - widthCache[glyph] = uchar(width); - } - } - - if (oldFont) - SelectObject(hdc, oldFont); - } -} - -glyph_metrics_t QWindowsFontEngine::boundingBox(const QGlyphLayout &glyphs) -{ - if (glyphs.numGlyphs == 0) - return glyph_metrics_t(); - - QFixed w = 0; - for (int i = 0; i < glyphs.numGlyphs; ++i) - w += glyphs.effectiveAdvance(i); - - return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0); -} - -bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const -{ - Q_ASSERT(metrics != 0); - - HDC hdc = m_fontEngineData->hdc; - - GLYPHMETRICS gm; - DWORD res = 0; - MAT2 mat; - mat.eM11.value = mat.eM22.value = 1; - mat.eM11.fract = mat.eM22.fract = 0; - mat.eM21.value = mat.eM12.value = 0; - mat.eM21.fract = mat.eM12.fract = 0; - - if (t.type() > QTransform::TxTranslate) { - // We need to set the transform using the HDC's world - // matrix rather than using the MAT2 above, because the - // results provided when transforming via MAT2 does not - // match the glyphs that are drawn using a WorldTransform - XFORM xform; - xform.eM11 = FLOAT(t.m11()); - xform.eM12 = FLOAT(t.m12()); - xform.eM21 = FLOAT(t.m21()); - xform.eM22 = FLOAT(t.m22()); - xform.eDx = 0; - xform.eDy = 0; - SetGraphicsMode(hdc, GM_ADVANCED); - SetWorldTransform(hdc, &xform); - } - - uint format = GGO_METRICS; - if (ttf) - format |= GGO_GLYPH_INDEX; - res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat); - - if (t.type() > QTransform::TxTranslate) { - XFORM xform; - xform.eM11 = xform.eM22 = 1; - xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0; - SetWorldTransform(hdc, &xform); - SetGraphicsMode(hdc, GM_COMPATIBLE); - } - - if (res != GDI_ERROR) { - *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y, - int(gm.gmBlackBoxX), int(gm.gmBlackBoxY), - gm.gmCellIncX, gm.gmCellIncY); - return true; - } else { - return false; - } -} - -glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform &t) -{ - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - - glyph_metrics_t glyphMetrics; - bool success = getOutlineMetrics(glyph, t, &glyphMetrics); - - if (!ttf && !success) { - // Bitmap fonts - wchar_t ch = wchar_t(glyph); - ABCFLOAT abc; - GetCharABCWidthsFloat(hdc, ch, ch, &abc); - int width = qRound(abc.abcfB); - - return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t); - } - - return glyphMetrics; -} - -QFixed QWindowsFontEngine::ascent() const -{ - return tm.tmAscent; -} - -QFixed QWindowsFontEngine::descent() const -{ - return tm.tmDescent; -} - -QFixed QWindowsFontEngine::leading() const -{ - return tm.tmExternalLeading; -} - -namespace { -# pragma pack(1) - - struct OS2Table - { - quint16 version; - qint16 avgCharWidth; - quint16 weightClass; - quint16 widthClass; - quint16 type; - qint16 subscriptXSize; - qint16 subscriptYSize; - qint16 subscriptXOffset; - qint16 subscriptYOffset; - qint16 superscriptXSize; - qint16 superscriptYSize; - qint16 superscriptXOffset; - qint16 superscriptYOffset; - qint16 strikeOutSize; - qint16 strikeOutPosition; - qint16 familyClass; - quint8 panose[10]; - quint32 unicodeRanges[4]; - quint8 vendorID[4]; - quint16 selection; - quint16 firstCharIndex; - quint16 lastCharIndex; - qint16 typoAscender; - qint16 typoDescender; - qint16 typoLineGap; - quint16 winAscent; - quint16 winDescent; - quint32 codepageRanges[2]; - qint16 height; - qint16 capHeight; - quint16 defaultChar; - quint16 breakChar; - quint16 maxContext; - }; - -# pragma pack() -} - -QFixed QWindowsFontEngine::capHeight() const -{ - const QByteArray tableData = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); - if (size_t(tableData.size()) >= sizeof(OS2Table)) { - const OS2Table *table = reinterpret_cast<const OS2Table *>(tableData.constData()); - if (qFromBigEndian<quint16>(table->version) >= 2) { - qint16 capHeight = qFromBigEndian<qint16>(table->capHeight); - if (capHeight > 0) - return QFixed(capHeight) / designToDevice; - } - } - return calculatedCapHeight(); -} - -QFixed QWindowsFontEngine::xHeight() const -{ - if(x_height >= 0) - return x_height; - return QFontEngine::xHeight(); -} - -QFixed QWindowsFontEngine::averageCharWidth() const -{ - return tm.tmAveCharWidth; -} - -qreal QWindowsFontEngine::maxCharWidth() const -{ - return tm.tmMaxCharWidth; -} - -enum { max_font_count = 256 }; -static const ushort char_table[] = { - 40, - 67, - 70, - 75, - 86, - 88, - 89, - 91, - 102, - 114, - 124, - 127, - 205, - 645, - 884, - 922, - 1070, - 12386, - 0 -}; - -static const int char_table_entries = sizeof(char_table)/sizeof(ushort); - -#ifndef Q_CC_MINGW -void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing) -{ - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - - if (ttf) { - ABC abcWidths; - GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths); - if (leftBearing) - *leftBearing = abcWidths.abcA; - if (rightBearing) - *rightBearing = abcWidths.abcC; - } else { - QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing); - } -} -#endif // Q_CC_MINGW - -bool QWindowsFontEngine::hasUnreliableGlyphOutline() const -{ - return hasUnreliableOutline || QFontEngine::hasUnreliableGlyphOutline(); -} - -qreal QWindowsFontEngine::minLeftBearing() const -{ - if (lbearing == SHRT_MIN) - minRightBearing(); // calculates both - - return lbearing; -} - -qreal QWindowsFontEngine::minRightBearing() const -{ - if (rbearing == SHRT_MIN) { - int ml = 0; - int mr = 0; - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - if (ttf) { - ABC *abc = 0; - int n = tm.tmLastChar - tm.tmFirstChar; - if (n <= max_font_count) { - abc = new ABC[n+1]; - GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc); - } else { - abc = new ABC[char_table_entries+1]; - for(int i = 0; i < char_table_entries; i++) - GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i); - n = char_table_entries; - } - ml = abc[0].abcA; - mr = abc[0].abcC; - for (int i = 1; i < n; i++) { - if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) { - ml = qMin(ml,abc[i].abcA); - mr = qMin(mr,abc[i].abcC); - } - } - delete [] abc; - } else { - ABCFLOAT *abc = 0; - int n = tm.tmLastChar - tm.tmFirstChar+1; - if (n <= max_font_count) { - abc = new ABCFLOAT[n]; - GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc); - } else { - abc = new ABCFLOAT[char_table_entries]; - for(int i = 0; i < char_table_entries; i++) - GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i); - n = char_table_entries; - } - float fml = abc[0].abcfA; - float fmr = abc[0].abcfC; - for (int i=1; i<n; i++) { - if (abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0) { - fml = qMin(fml,abc[i].abcfA); - fmr = qMin(fmr,abc[i].abcfC); - } - } - ml = int(fml - 0.9999); - mr = int(fmr - 0.9999); - delete [] abc; - } - lbearing = ml; - rbearing = mr; - } - - return rbearing; -} - -static inline double qt_fixed_to_double(const FIXED &p) { - return ((p.value << 16) + p.fract) / 65536.0; -} - -static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale, qreal stretch) { - return QPointF(qt_fixed_to_double(pt.x) * scale * stretch, -qt_fixed_to_double(pt.y) * scale); -} - -#ifndef GGO_UNHINTED -#define GGO_UNHINTED 0x0100 -#endif - -static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, - QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, - qreal scale = 1.0, qreal stretch = 1.0) -{ - MAT2 mat; - mat.eM11.value = mat.eM22.value = 1; - mat.eM11.fract = mat.eM22.fract = 0; - mat.eM21.value = mat.eM12.value = 0; - mat.eM21.fract = mat.eM12.fract = 0; - - GLYPHMETRICS gMetric; - memset(&gMetric, 0, sizeof(GLYPHMETRICS)); - - if (metric) { - // If metrics requested, retrieve first using GGO_METRICS, because the returned - // values are incorrect for OpenType PS fonts if obtained at the same time as the - // glyph paths themselves (ie. with GGO_NATIVE as the format). - uint format = GGO_METRICS; - if (ttf) - format |= GGO_GLYPH_INDEX; - if (GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat) == GDI_ERROR) - return false; - // #### obey scale - *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y, - int(gMetric.gmBlackBoxX), int(gMetric.gmBlackBoxY), - gMetric.gmCellIncX, gMetric.gmCellIncY); - } - - uint glyphFormat = GGO_NATIVE; - - if (ttf) - glyphFormat |= GGO_GLYPH_INDEX; - - const DWORD bufferSize = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, 0, 0, &mat); - if (bufferSize == GDI_ERROR) - return false; - - char *dataBuffer = new char[bufferSize]; - DWORD ret = GDI_ERROR; - ret = GetGlyphOutline(hdc, glyph, glyphFormat, &gMetric, bufferSize, dataBuffer, &mat); - if (ret == GDI_ERROR) { - delete [] dataBuffer; - return false; - } - - DWORD offset = 0; - DWORD headerOffset = 0; - - QPointF oset = position.toPointF(); - while (headerOffset < bufferSize) { - const TTPOLYGONHEADER *ttph = reinterpret_cast<const TTPOLYGONHEADER *>(dataBuffer + headerOffset); - - QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch)); - path->moveTo(lastPoint + oset); - offset += sizeof(TTPOLYGONHEADER); - while (offset < headerOffset + ttph->cb) { - const TTPOLYCURVE *curve = reinterpret_cast<const TTPOLYCURVE *>(dataBuffer + offset); - switch (curve->wType) { - case TT_PRIM_LINE: { - for (int i=0; i<curve->cpfx; ++i) { - QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset; - path->lineTo(p); - } - break; - } - case TT_PRIM_QSPLINE: { - const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1); - QPointF prev(elm.x, elm.y); - QPointF endPoint; - for (int i=0; i<curve->cpfx - 1; ++i) { - QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset; - QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset; - if (i < curve->cpfx - 2) { - endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2); - } else { - endPoint = p2; - } - - path->quadTo(p1, endPoint); - prev = endPoint; - } - - break; - } - case TT_PRIM_CSPLINE: { - for (int i=0; i<curve->cpfx; ) { - QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; - QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; - QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; - path->cubicTo(p2, p3, p4); - } - break; - } - default: - qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case"); - } - offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX); - } - path->closeSubpath(); - headerOffset += ttph->cb; - } - delete [] dataBuffer; - - return true; -} - -void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags) -{ - LOGFONT lf = m_logfont; - // The sign must be negative here to make sure we match against character height instead of - // hinted cell height. This ensures that we get linear matching, and we need this for - // paths since we later on apply a scaling transform to the glyph outline to get the - // font at the correct pixel size. - lf.lfHeight = -unitsPerEm; - lf.lfWidth = 0; - HFONT hf = CreateFontIndirect(&lf); - HDC hdc = m_fontEngineData->hdc; - HGDIOBJ oldfont = SelectObject(hdc, hf); - - qreal scale = qreal(fontDef.pixelSize) / unitsPerEm; - qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0; - for(int i = 0; i < nglyphs; ++i) { - if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0, - scale, stretch)) { - // Some windows fonts, like "Modern", are vector stroke - // fonts, which are reported as TMPF_VECTOR but do not - // support GetGlyphOutline, and thus we set this bit so - // that addOutLineToPath can check it and return safely... - hasOutline = false; - break; - } - } - DeleteObject(SelectObject(hdc, oldfont)); -} - -void QWindowsFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, - QPainterPath *path, QTextItem::RenderFlags flags) -{ - if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) { - hasOutline = true; - QFontEngine::addOutlineToPath(x, y, glyphs, path, flags); - if (hasOutline) { - // has_outline is set to false if addGlyphToPath gets - // false from GetGlyphOutline, meaning its not an outline - // font. - return; - } - } - QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags); -} - -QFontEngine::FaceId QWindowsFontEngine::faceId() const -{ - return _faceId; -} - -QT_BEGIN_INCLUDE_NAMESPACE -#include <qdebug.h> -QT_END_INCLUDE_NAMESPACE - -int QWindowsFontEngine::synthesized() const -{ - if(synthesized_flags == -1) { - synthesized_flags = 0; - if(ttf) { - const DWORD HEAD = MAKE_LITTLE_ENDIAN_TAG('h', 'e', 'a', 'd'); - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - uchar data[4]; - GetFontData(hdc, HEAD, 44, &data, 4); - USHORT macStyle = qt_getUShort(data); - if (tm.tmItalic && !(macStyle & 2)) - synthesized_flags = SynthesizedItalic; - if (fontDef.stretch != 100 && ttf) - synthesized_flags |= SynthesizedStretch; - if (tm.tmWeight >= 500 && tm.tmWeight < 750 && !(macStyle & 1)) - synthesized_flags |= SynthesizedBold; - //qDebug() << "font is" << _name << - // "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags; - } - } - return synthesized_flags; -} - -QFixed QWindowsFontEngine::emSquareSize() const -{ - return unitsPerEm; -} - -QFontEngine::Properties QWindowsFontEngine::properties() const -{ - LOGFONT lf = m_logfont; - lf.lfHeight = unitsPerEm; - HFONT hf = CreateFontIndirect(&lf); - HDC hdc = m_fontEngineData->hdc; - HGDIOBJ oldfont = SelectObject(hdc, hf); - OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc); - Properties p; - p.emSquare = unitsPerEm; - p.italicAngle = otm->otmItalicAngle; - const QByteArray name = stringFromOutLineTextMetric(otm, otm->otmpFamilyName).toLatin1() - + stringFromOutLineTextMetric(otm, otm->otmpStyleName).toLatin1(); - p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(name); - p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top, - otm->otmrcFontBox.right - otm->otmrcFontBox.left, - otm->otmrcFontBox.top - otm->otmrcFontBox.bottom); - p.ascent = otm->otmAscent; - p.descent = -otm->otmDescent; - p.leading = int(otm->otmLineGap); - p.capHeight = 0; - p.lineWidth = otm->otmsUnderscoreSize; - free(otm); - DeleteObject(SelectObject(hdc, oldfont)); - return p; -} - -void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) -{ - LOGFONT lf = m_logfont; - lf.lfHeight = -unitsPerEm; - int flags = synthesized(); - if(flags & SynthesizedItalic) - lf.lfItalic = false; - lf.lfWidth = 0; - HFONT hf = CreateFontIndirect(&lf); - HDC hdc = m_fontEngineData->hdc; - HGDIOBJ oldfont = SelectObject(hdc, hf); - QFixedPoint p; - p.x = 0; - p.y = 0; - addGlyphToPath(glyph, p, hdc, path, ttf, metrics); - DeleteObject(SelectObject(hdc, oldfont)); -} - -bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const -{ - if (!ttf && !cffTable) - return false; - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - DWORD t = qbswap<quint32>(tag); - *length = GetFontData(hdc, t, 0, buffer, *length); - Q_ASSERT(*length == GDI_ERROR || int(*length) > 0); - return *length != GDI_ERROR; -} - -#if !defined(CLEARTYPE_QUALITY) -# define CLEARTYPE_QUALITY 5 -#endif - -QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int margin, - const QTransform &t, - QImage::Format mask_format) -{ - Q_UNUSED(mask_format) - glyph_metrics_t gm = boundingBox(glyph); - -// printf(" -> for glyph %4x\n", glyph); - - int gx = gm.x.toInt(); - int gy = gm.y.toInt(); - int iw = gm.width.toInt(); - int ih = gm.height.toInt(); - - if (iw <= 0 || ih <= 0) - return 0; - - bool has_transformation = t.type() > QTransform::TxTranslate; - - unsigned int options = ttf ? ETO_GLYPH_INDEX : 0; - XFORM xform; - - if (has_transformation) { - xform.eM11 = FLOAT(t.m11()); - xform.eM12 = FLOAT(t.m12()); - xform.eM21 = FLOAT(t.m21()); - xform.eM22 = FLOAT(t.m22()); - xform.eDx = margin; - xform.eDy = margin; - - const HDC hdc = m_fontEngineData->hdc; - - SetGraphicsMode(hdc, GM_ADVANCED); - SetWorldTransform(hdc, &xform); - HGDIOBJ old_font = SelectObject(hdc, font); - - const UINT ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0); - GLYPHMETRICS tgm; - MAT2 mat; - memset(&mat, 0, sizeof(mat)); - mat.eM11.value = mat.eM22.value = 1; - - const DWORD result = GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat); - - XFORM identity = {1, 0, 0, 1, 0, 0}; - SetWorldTransform(hdc, &identity); - SetGraphicsMode(hdc, GM_COMPATIBLE); - SelectObject(hdc, old_font); - - if (result == GDI_ERROR) { - const int errorCode = int(GetLastError()); - qErrnoWarning(errorCode, "QWinFontEngine: unable to query transformed glyph metrics (GetGlyphOutline() failed, error %d)...", errorCode); - return 0; - } - - iw = int(tgm.gmBlackBoxX); - ih = int(tgm.gmBlackBoxY); - - xform.eDx -= tgm.gmptGlyphOrigin.x; - xform.eDy += tgm.gmptGlyphOrigin.y; - } - - // The padding here needs to be kept in sync with the values in alphaMapBoundingBox. - QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin, - ih + 2 * margin, - QWindowsNativeImage::systemFormat()); - - /*If cleartype is enabled we use the standard system format even on Windows CE - and not the special textbuffer format we have to use if cleartype is disabled*/ - - ni->image().fill(0xffffffff); - - HDC hdc = ni->hdc(); - - SelectObject(hdc, GetStockObject(NULL_BRUSH)); - SelectObject(hdc, GetStockObject(BLACK_PEN)); - SetTextColor(hdc, RGB(0,0,0)); - SetBkMode(hdc, TRANSPARENT); - SetTextAlign(hdc, TA_BASELINE); - - HGDIOBJ old_font = SelectObject(hdc, font); - - if (has_transformation) { - SetGraphicsMode(hdc, GM_ADVANCED); - SetWorldTransform(hdc, &xform); - ExtTextOut(hdc, 0, 0, options, 0, reinterpret_cast<LPCWSTR>(&glyph), 1, 0); - } else { - ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, reinterpret_cast<LPCWSTR>(&glyph), 1, 0); - } - - SelectObject(hdc, old_font); - return ni; -} - -glyph_metrics_t QWindowsFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat format) -{ - int margin = 0; - if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB) - margin = glyphMargin(QFontEngine::Format_A32); - glyph_metrics_t gm = boundingBox(glyph, matrix); - gm.width += margin * 2; - gm.height += margin * 2; - return gm; -} - -QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform) -{ - HFONT font = hfont; - - bool clearTypeTemporarilyDisabled = (m_fontEngineData->clearTypeEnabled && m_logfont.lfQuality != NONANTIALIASED_QUALITY); - if (clearTypeTemporarilyDisabled) { - LOGFONT lf = m_logfont; - lf.lfQuality = ANTIALIASED_QUALITY; - font = CreateFontIndirect(&lf); - } - QImage::Format mask_format = QWindowsNativeImage::systemFormat(); - mask_format = QImage::Format_RGB32; - - const QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format); - if (mask == 0) { - if (m_fontEngineData->clearTypeEnabled) - DeleteObject(font); - return QImage(); - } - - QImage alphaMap(mask->width(), mask->height(), QImage::Format_Alpha8); - - - // Copy data... Cannot use QPainter here as GDI has messed up the - // Alpha channel of the ni.image pixels... - for (int y=0; y<mask->height(); ++y) { - uchar *dest = alphaMap.scanLine(y); - if (mask->image().format() == QImage::Format_RGB16) { - const qint16 *src = reinterpret_cast<const qint16 *>(mask->image().constScanLine(y)); - for (int x=0; x<mask->width(); ++x) - dest[x] = 255 - qGray(src[x]); - } else { - const uint *src = reinterpret_cast<const uint *>(mask->image().constScanLine(y)); - for (int x=0; x<mask->width(); ++x) { - if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16) - dest[x] = 255 - qGray(src[x]); - else - dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.); - } - } - } - - // Cleanup... - delete mask; - if (clearTypeTemporarilyDisabled) { - DeleteObject(font); - } - - return alphaMap; -} - -#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C -#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D - -QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTransform &t) -{ - HFONT font = hfont; - - UINT contrast; - SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0); - SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast<void *>(quintptr(1000)), 0); - - int margin = glyphMargin(QFontEngine::Format_A32); - QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32); - SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast<void *>(quintptr(contrast)), 0); - - if (mask == 0) - return QImage(); - - // Gracefully handle the odd case when the display is 16-bit - const QImage source = mask->image().depth() == 32 - ? mask->image() - : mask->image().convertToFormat(QImage::Format_RGB32); - - QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32); - for (int y=0; y<mask->height(); ++y) { - auto dest = reinterpret_cast<uint *>(rgbMask.scanLine(y)); - const uint *src = reinterpret_cast<const uint *>(source.constScanLine(y)); - for (int x=0; x<mask->width(); ++x) { - dest[x] = 0xffffffff - (0x00ffffff & src[x]); - } - } - - delete mask; - - return rgbMask; -} - -QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const -{ - QFontDef request = fontDef; - QString actualFontName = request.family; - if (!uniqueFamilyName.isEmpty()) - request.family = uniqueFamilyName; - request.pixelSize = pixelSize; - const QString faceName = QString::fromWCharArray(m_logfont.lfFaceName); - - QFontEngine *fontEngine = - QWindowsFontDatabase::createEngine(request, faceName, - QWindowsFontDatabase::defaultVerticalDPI(), - m_fontEngineData); - if (fontEngine) { - fontEngine->fontDef.family = actualFontName; - if (!uniqueFamilyName.isEmpty()) { - static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName); - if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) { - QPlatformFontDatabase *pfdb = pi->fontDatabase(); - static_cast<QWindowsFontDatabase *>(pfdb)->refUniqueFont(uniqueFamilyName); - } - } - } - return fontEngine; -} - -Qt::HANDLE QWindowsFontEngine::handle() const -{ - return hfont; -} - -void QWindowsFontEngine::initFontInfo(const QFontDef &request, - int dpi) -{ - fontDef = request; // most settings are equal - HDC dc = m_fontEngineData->hdc; - SelectObject(dc, hfont); - wchar_t n[64]; - GetTextFace(dc, 64, n); - fontDef.family = QString::fromWCharArray(n); - fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); - if (fontDef.pointSize < 0) { - fontDef.pointSize = fontDef.pixelSize * 72. / dpi; - } else if (fontDef.pixelSize == -1) { - fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.); - } -} - -bool QWindowsFontEngine::supportsTransformation(const QTransform &transform) const -{ - // Support all transformations for ttf files, and translations for raster fonts - return ttf || transform.type() <= QTransform::TxTranslate; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h deleted file mode 100644 index b1b9d828ac..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h +++ /dev/null @@ -1,175 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSFONTENGINE_H -#define QWINDOWSFONTENGINE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qfontengine_p.h> - -#include <QtGui/QImage> -#include <QtCore/QSharedPointer> -#include <QtCore/QMetaType> - -#include <QtCore/qt_windows.h> - -QT_BEGIN_NAMESPACE - -class QWindowsNativeImage; -class QWindowsFontEngineData; - -class QWindowsFontEngine : public QFontEngine -{ - Q_DISABLE_COPY_MOVE(QWindowsFontEngine) -public: - QWindowsFontEngine(const QString &name, LOGFONT lf, - const QSharedPointer<QWindowsFontEngineData> &fontEngineData); - - ~QWindowsFontEngine() override; - void initFontInfo(const QFontDef &request, - int dpi); - - QFixed lineThickness() const override; - Properties properties() const override; - void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override; - FaceId faceId() const override; - bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override; - int synthesized() const override; - QFixed emSquareSize() const override; - - glyph_t glyphIndex(uint ucs4) const override; - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override; - void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override; - - void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override; - void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags flags) override; - - HGDIOBJ selectDesignFont() const; - - glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; - glyph_metrics_t boundingBox(glyph_t g) override { return boundingBox(g, QTransform()); } - glyph_metrics_t boundingBox(glyph_t g, const QTransform &t) override; - - - QFixed ascent() const override; - QFixed descent() const override; - QFixed leading() const override; - QFixed xHeight() const override; - QFixed capHeight() const override; - QFixed averageCharWidth() const override; - qreal maxCharWidth() const override; - qreal minLeftBearing() const override; - qreal minRightBearing() const override; - - QImage alphaMapForGlyph(glyph_t t) override { return alphaMapForGlyph(t, QTransform()); } - QImage alphaMapForGlyph(glyph_t, const QTransform &xform) override; - QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) override; - glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) override; - - QFontEngine *cloneWithSize(qreal pixelSize) const override; - Qt::HANDLE handle() const override; - bool supportsTransformation(const QTransform &transform) const override; - -#ifndef Q_CC_MINGW - void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0) override; -#endif - - bool hasUnreliableGlyphOutline() const override; - - int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs) const; - void getCMap(); - - bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const; - - const QSharedPointer<QWindowsFontEngineData> &fontEngineData() const { return m_fontEngineData; } - - void setUniqueFamilyName(const QString &newName) { uniqueFamilyName = newName; } - -private: - QWindowsNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform, - QImage::Format mask_format); - bool hasCFFTable() const; - bool hasCMapTable() const; - - const QSharedPointer<QWindowsFontEngineData> m_fontEngineData; - - const QString _name; - QString uniqueFamilyName; - HFONT hfont = 0; - const LOGFONT m_logfont; - uint ttf : 1; - uint hasOutline : 1; - uint hasUnreliableOutline : 1; - uint cffTable : 1; - TEXTMETRIC tm; - const unsigned char *cmap = nullptr; - int cmapSize = 0; - QByteArray cmapTable; - mutable qreal lbearing = SHRT_MIN; - mutable qreal rbearing = SHRT_MIN; - QFixed designToDevice; - int unitsPerEm = 0; - QFixed x_height = -1; - FaceId _faceId; - - mutable int synthesized_flags = -1; - mutable QFixed lineWidth = -1; - mutable unsigned char *widthCache = nullptr; - mutable uint widthCacheSize = 0; - mutable QFixed *designAdvances = nullptr; - mutable int designAdvancesSize = 0; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(HFONT) -Q_DECLARE_METATYPE(LOGFONT) - -#endif // QWINDOWSFONTENGINE_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp deleted file mode 100644 index 5c999f455e..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp +++ /dev/null @@ -1,1035 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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$ -** -****************************************************************************/ - -#ifndef QT_NO_DIRECTWRITE - -#include "qwindowsfontenginedirectwrite_p.h" -#include "qwindowsfontdatabase_p.h" - -#include <QtCore/QtEndian> -#include <QtCore/QVarLengthArray> -#include <QtCore/QFile> -#include <private/qstringiterator_p.h> -#include <QtCore/private/qsystemlibrary_p.h> -#include <QtCore/private/qwinregistry_p.h> -#include <QtGui/private/qguiapplication_p.h> -#include <qpa/qplatformintegration.h> -#include <QtGui/private/qhighdpiscaling_p.h> - -#if defined(QT_USE_DIRECTWRITE2) -# include <dwrite_2.h> -#else -# include <dwrite.h> -#endif - -#include <d2d1.h> - -QT_BEGIN_NAMESPACE - -// Clang does not consider __declspec(nothrow) as nothrow -QT_WARNING_DISABLE_CLANG("-Wmicrosoft-exception-spec") - -// Convert from design units to logical pixels -#define DESIGN_TO_LOGICAL(DESIGN_UNIT_VALUE) \ - QFixed::fromReal((qreal(DESIGN_UNIT_VALUE) / qreal(m_unitsPerEm)) * fontDef.pixelSize) - -namespace { - - class GeometrySink: public IDWriteGeometrySink - { - Q_DISABLE_COPY_MOVE(GeometrySink) - public: - GeometrySink(QPainterPath *path) - : m_refCount(0), m_path(path) - { - Q_ASSERT(m_path != 0); - } - virtual ~GeometrySink() = default; - - IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount); - IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount); - IFACEMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin); - IFACEMETHOD(Close)(); - IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd); - IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode); - IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags); - - IFACEMETHOD_(unsigned long, AddRef)(); - IFACEMETHOD_(unsigned long, Release)(); - IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject); - - private: - inline static QPointF fromD2D1_POINT_2F(const D2D1_POINT_2F &inp) - { - return QPointF(inp.x, inp.y); - } - - unsigned long m_refCount; - QPointF m_startPoint; - QPainterPath *m_path; - }; - - void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, - UINT bezierCount) - { - for (uint i=0; i<bezierCount; ++i) { - QPointF c1 = fromD2D1_POINT_2F(beziers[i].point1); - QPointF c2 = fromD2D1_POINT_2F(beziers[i].point2); - QPointF p2 = fromD2D1_POINT_2F(beziers[i].point3); - - m_path->cubicTo(c1, c2, p2); - } - } - - void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) - { - for (uint i=0; i<pointsCount; ++i) - m_path->lineTo(fromD2D1_POINT_2F(points[i])); - } - - void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint, - D2D1_FIGURE_BEGIN /*figureBegin*/) - { - m_startPoint = fromD2D1_POINT_2F(startPoint); - m_path->moveTo(m_startPoint); - } - - IFACEMETHODIMP GeometrySink::Close() - { - return E_NOTIMPL; - } - - void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) - { - if (figureEnd == D2D1_FIGURE_END_CLOSED) - m_path->closeSubpath(); - } - - void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) - { - m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE - ? Qt::OddEvenFill - : Qt::WindingFill); - } - - void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/) - { - /* Not implemented */ - } - - IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef() - { - return InterlockedIncrement(&m_refCount); - } - - IFACEMETHODIMP_(unsigned long) GeometrySink::Release() - { - unsigned long newCount = InterlockedDecrement(&m_refCount); - if (newCount == 0) - { - delete this; - return 0; - } - - return newCount; - } - - IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject) - { - if (__uuidof(IDWriteGeometrySink) == riid) { - *ppvObject = this; - } else if (__uuidof(IUnknown) == riid) { - *ppvObject = this; - } else { - *ppvObject = NULL; - return E_FAIL; - } - - AddRef(); - return S_OK; - } - -} - -static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(QFont::HintingPreference hintingPreference) -{ - if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting) - hintingPreference = QFont::PreferVerticalHinting; - - switch (hintingPreference) { - case QFont::PreferNoHinting: - return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; - case QFont::PreferVerticalHinting: - return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL; - default: - return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; - } -} - -/*! - \class QWindowsFontEngineDirectWrite - \brief Windows font engine using Direct Write. - \internal - \ingroup qt-lighthouse-win - - Font engine for subpixel positioned text on Windows Vista - (with platform update) and Windows 7. If selected during - configuration, the engine will be selected only when the hinting - preference of a font is set to None or Vertical hinting. The font - database uses most of the same logic but creates a direct write - font based on the LOGFONT rather than a GDI handle. - - Will probably be superseded by a common Free Type font engine in Qt 5.X. -*/ - -QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, - qreal pixelSize, - const QSharedPointer<QWindowsFontEngineData> &d) - : QFontEngine(DirectWrite) - , m_fontEngineData(d) - , m_directWriteFontFace(directWriteFontFace) - , m_directWriteBitmapRenderTarget(0) - , m_lineThickness(-1) - , m_unitsPerEm(-1) - , m_ascent(-1) - , m_capHeight(-1) - , m_descent(-1) - , m_xHeight(-1) - , m_lineGap(-1) -{ - qCDebug(lcQpaFonts) << __FUNCTION__ << pixelSize; - - Q_ASSERT(m_directWriteFontFace); - - m_fontEngineData->directWriteFactory->AddRef(); - m_directWriteFontFace->AddRef(); - - fontDef.pixelSize = pixelSize; - collectMetrics(); - cache_cost = (m_ascent.toInt() + m_descent.toInt()) * m_xHeight.toInt() * 2000; -} - -QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite() -{ - qCDebug(lcQpaFonts) << __FUNCTION__; - - m_fontEngineData->directWriteFactory->Release(); - m_directWriteFontFace->Release(); - - if (m_directWriteBitmapRenderTarget != 0) - m_directWriteBitmapRenderTarget->Release(); - - if (!m_uniqueFamilyName.isEmpty()) { - QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); - static_cast<QWindowsFontDatabase *>(pfdb)->derefUniqueFont(m_uniqueFamilyName); - } -} - -#ifndef Q_CC_MINGW -typedef IDWriteLocalFontFileLoader QIdWriteLocalFontFileLoader; - -static UUID uuidIdWriteLocalFontFileLoader() -{ - return __uuidof(IDWriteLocalFontFileLoader); -} -#else // !Q_CC_MINGW -DECLARE_INTERFACE_(QIdWriteLocalFontFileLoader, IDWriteFontFileLoader) -{ - STDMETHOD(GetFilePathLengthFromKey)(THIS_ void const *, UINT32, UINT32*) PURE; - STDMETHOD(GetFilePathFromKey)(THIS_ void const *, UINT32, WCHAR *, UINT32) PURE; - STDMETHOD(GetLastWriteTimeFromKey)(THIS_ void const *, UINT32, FILETIME *) PURE; -}; - -static UUID uuidIdWriteLocalFontFileLoader() -{ - static const UUID result = { 0xb2d9f3ec, 0xc9fe, 0x4a11, {0xa2, 0xec, 0xd8, 0x62, 0x8, 0xf7, 0xc0, 0xa2}}; - return result; -} -#endif // Q_CC_MINGW - -QString QWindowsFontEngineDirectWrite::filenameFromFontFile(IDWriteFontFile *fontFile) -{ - IDWriteFontFileLoader *loader = nullptr; - - HRESULT hr = fontFile->GetLoader(&loader); - if (FAILED(hr)) { - qErrnoWarning("%s: GetLoader failed", __FUNCTION__); - return QString(); - } - - QIdWriteLocalFontFileLoader *localLoader = nullptr; - hr = loader->QueryInterface(uuidIdWriteLocalFontFileLoader(), - reinterpret_cast<void **>(&localLoader)); - - const void *fontFileReferenceKey = nullptr; - UINT32 fontFileReferenceKeySize = 0; - if (SUCCEEDED(hr)) { - hr = fontFile->GetReferenceKey(&fontFileReferenceKey, - &fontFileReferenceKeySize); - if (FAILED(hr)) - qErrnoWarning(hr, "%s: GetReferenceKey failed", __FUNCTION__); - } - - UINT32 filePathLength = 0; - if (SUCCEEDED(hr)) { - hr = localLoader->GetFilePathLengthFromKey(fontFileReferenceKey, - fontFileReferenceKeySize, - &filePathLength); - if (FAILED(hr)) - qErrnoWarning(hr, "GetFilePathLength failed", __FUNCTION__); - } - - QString ret; - if (SUCCEEDED(hr) && filePathLength > 0) { - QVarLengthArray<wchar_t> filePath(filePathLength + 1); - - hr = localLoader->GetFilePathFromKey(fontFileReferenceKey, - fontFileReferenceKeySize, - filePath.data(), - filePathLength + 1); - if (FAILED(hr)) - qErrnoWarning(hr, "%s: GetFilePathFromKey failed", __FUNCTION__); - else - ret = QString::fromWCharArray(filePath.data()); - } - - if (localLoader != nullptr) - localLoader->Release(); - - if (loader != nullptr) - loader->Release(); - return ret; -} - -void QWindowsFontEngineDirectWrite::collectMetrics() -{ - DWRITE_FONT_METRICS metrics; - - m_directWriteFontFace->GetMetrics(&metrics); - m_unitsPerEm = metrics.designUnitsPerEm; - - m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); - m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); - m_capHeight = DESIGN_TO_LOGICAL(metrics.capHeight); - m_descent = DESIGN_TO_LOGICAL(metrics.descent); - m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); - m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap); - m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition); - - IDWriteFontFile *fontFile = nullptr; - UINT32 numberOfFiles = 1; - if (SUCCEEDED(m_directWriteFontFace->GetFiles(&numberOfFiles, &fontFile))) { - m_faceId.filename = QFile::encodeName(filenameFromFontFile(fontFile)); - fontFile->Release(); - } - - QByteArray table = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a')); - const int advanceWidthMaxLocation = 10; - if (table.size() >= advanceWidthMaxLocation + int(sizeof(quint16))) { - quint16 advanceWidthMax = qFromBigEndian<quint16>(table.constData() + advanceWidthMaxLocation); - m_maxAdvanceWidth = DESIGN_TO_LOGICAL(advanceWidthMax); - } -} - -QFixed QWindowsFontEngineDirectWrite::underlinePosition() const -{ - if (m_underlinePosition > 0) - return m_underlinePosition; - else - return QFontEngine::underlinePosition(); -} - -QFixed QWindowsFontEngineDirectWrite::lineThickness() const -{ - if (m_lineThickness > 0) - return m_lineThickness; - else - return QFontEngine::lineThickness(); -} - -bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, uint *length) const -{ - bool ret = false; - - const void *tableData = 0; - UINT32 tableSize; - void *tableContext = 0; - BOOL exists; - HRESULT hr = m_directWriteFontFace->TryGetFontTable(qbswap<quint32>(tag), - &tableData, &tableSize, - &tableContext, &exists); - if (SUCCEEDED(hr)) { - if (exists) { - ret = true; - if (buffer && *length >= tableSize) - memcpy(buffer, tableData, tableSize); - *length = tableSize; - Q_ASSERT(int(*length) > 0); - } - m_directWriteFontFace->ReleaseFontTable(tableContext); - } else { - qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); - } - - return ret; -} - -QFixed QWindowsFontEngineDirectWrite::emSquareSize() const -{ - if (m_unitsPerEm > 0) - return m_unitsPerEm; - else - return QFontEngine::emSquareSize(); -} - -glyph_t QWindowsFontEngineDirectWrite::glyphIndex(uint ucs4) const -{ - UINT16 glyphIndex; - - HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(&ucs4, 1, &glyphIndex); - if (FAILED(hr)) { - qErrnoWarning("%s: glyphIndex failed", __FUNCTION__); - glyphIndex = 0; - } - - return glyphIndex; -} - -bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, - int *nglyphs, QFontEngine::ShaperFlags flags) const -{ - Q_ASSERT(glyphs->numGlyphs >= *nglyphs); - if (*nglyphs < len) { - *nglyphs = len; - return false; - } - - QVarLengthArray<UINT32> codePoints(len); - int actualLength = 0; - QStringIterator it(str, str + len); - while (it.hasNext()) - codePoints[actualLength++] = it.next(); - - QVarLengthArray<UINT16> glyphIndices(actualLength); - HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), actualLength, - glyphIndices.data()); - if (FAILED(hr)) { - qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); - return false; - } - - for (int i = 0; i < actualLength; ++i) - glyphs->glyphs[i] = glyphIndices.at(i); - - *nglyphs = actualLength; - glyphs->numGlyphs = actualLength; - - if (!(flags & GlyphIndicesOnly)) - recalcAdvances(glyphs, {}); - - return true; -} - -QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const -{ - return m_faceId; -} - -void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const -{ - QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs); - - // ### Caching? - for(int i=0; i<glyphs->numGlyphs; i++) - glyphIndices[i] = UINT16(glyphs->glyphs[i]); - - QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size()); - HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(), - glyphIndices.size(), - glyphMetrics.data()); - if (SUCCEEDED(hr)) { - qreal stretch = fontDef.stretch != QFont::AnyStretch ? fontDef.stretch / 100.0 : 1.0; - for (int i = 0; i < glyphs->numGlyphs; ++i) - glyphs->advances[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth * stretch); - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - for (int i = 0; i < glyphs->numGlyphs; ++i) - glyphs->advances[i] = glyphs->advances[i].round(); - } - } else { - qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); - } -} - -void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags flags) -{ - QVarLengthArray<UINT16> glyphIndices(nglyphs); - QVarLengthArray<DWRITE_GLYPH_OFFSET> glyphOffsets(nglyphs); - QVarLengthArray<FLOAT> glyphAdvances(nglyphs); - - for (int i=0; i<nglyphs; ++i) { - glyphIndices[i] = glyphs[i]; - glyphOffsets[i].advanceOffset = positions[i].x.toReal(); - glyphOffsets[i].ascenderOffset = -positions[i].y.toReal(); - glyphAdvances[i] = 0.0; - } - - GeometrySink geometrySink(path); - HRESULT hr = m_directWriteFontFace->GetGlyphRunOutline( - fontDef.pixelSize, - glyphIndices.data(), - glyphAdvances.data(), - glyphOffsets.data(), - nglyphs, - false, - flags & QTextItem::RightToLeft, - &geometrySink - ); - - if (FAILED(hr)) - qErrnoWarning("%s: GetGlyphRunOutline failed", __FUNCTION__); -} - -glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &glyphs) -{ - if (glyphs.numGlyphs == 0) - return glyph_metrics_t(); - - bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics; - - QFixed w = 0; - for (int i = 0; i < glyphs.numGlyphs; ++i) { - w += round ? glyphs.effectiveAdvance(i).round() : glyphs.effectiveAdvance(i); - - } - - return glyph_metrics_t(0, -m_ascent, w - lastRightBearing(glyphs), m_ascent + m_descent, w, 0); -} - -glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g) -{ - UINT16 glyphIndex = g; - - DWRITE_GLYPH_METRICS glyphMetrics; - HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(&glyphIndex, 1, &glyphMetrics); - if (SUCCEEDED(hr)) { - QFixed advanceWidth = DESIGN_TO_LOGICAL(glyphMetrics.advanceWidth); - QFixed leftSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.leftSideBearing); - QFixed rightSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.rightSideBearing); - QFixed advanceHeight = DESIGN_TO_LOGICAL(glyphMetrics.advanceHeight); - QFixed verticalOriginY = DESIGN_TO_LOGICAL(glyphMetrics.verticalOriginY); - QFixed topSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.topSideBearing); - QFixed bottomSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.bottomSideBearing); - - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - advanceWidth = advanceWidth.round(); - advanceHeight = advanceHeight.round(); - } - - QFixed width = advanceWidth - leftSideBearing - rightSideBearing; - QFixed height = advanceHeight - topSideBearing - bottomSideBearing; - return glyph_metrics_t(leftSideBearing, - -verticalOriginY + topSideBearing, - width, - height, - advanceWidth, - 0); - } else { - qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); - } - - return glyph_metrics_t(); -} - -QFixed QWindowsFontEngineDirectWrite::ascent() const -{ - return fontDef.styleStrategy & QFont::ForceIntegerMetrics - ? m_ascent.round() - : m_ascent; -} - -QFixed QWindowsFontEngineDirectWrite::capHeight() const -{ - if (m_capHeight <= 0) - return calculatedCapHeight(); - - return fontDef.styleStrategy & QFont::ForceIntegerMetrics - ? m_capHeight.round() - : m_capHeight; -} - -QFixed QWindowsFontEngineDirectWrite::descent() const -{ - return fontDef.styleStrategy & QFont::ForceIntegerMetrics - ? m_descent.round() - : m_descent; -} - -QFixed QWindowsFontEngineDirectWrite::leading() const -{ - return fontDef.styleStrategy & QFont::ForceIntegerMetrics - ? m_lineGap.round() - : m_lineGap; -} - -QFixed QWindowsFontEngineDirectWrite::xHeight() const -{ - return fontDef.styleStrategy & QFont::ForceIntegerMetrics - ? m_xHeight.round() - : m_xHeight; -} - -qreal QWindowsFontEngineDirectWrite::maxCharWidth() const -{ - return fontDef.styleStrategy & QFont::ForceIntegerMetrics - ? m_maxAdvanceWidth.round().toReal() - : m_maxAdvanceWidth.toReal(); -} - -QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) -{ - QImage im = alphaRGBMapForGlyph(glyph, subPixelPosition, t); - - QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8); - - for (int y=0; y<im.height(); ++y) { - const uint *src = reinterpret_cast<const uint *>(im.constScanLine(y)); - uchar *dst = alphaMap.scanLine(y); - for (int x=0; x<im.width(); ++x) { - *dst = 255 - (m_fontEngineData->pow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.); - ++dst; - ++src; - } - } - - return alphaMap; -} - -QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) -{ - return alphaMapForGlyph(glyph, subPixelPosition, QTransform()); -} - -bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const -{ - return true; -} - -QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, - QFixed subPixelPosition, - int margin, - const QTransform &originalTransform, - const QColor &color) -{ - UINT16 glyphIndex = t; - FLOAT glyphAdvance = 0; - - DWRITE_GLYPH_OFFSET glyphOffset; - glyphOffset.advanceOffset = 0; - glyphOffset.ascenderOffset = 0; - - DWRITE_GLYPH_RUN glyphRun; - glyphRun.fontFace = m_directWriteFontFace; - glyphRun.fontEmSize = fontDef.pixelSize; - glyphRun.glyphCount = 1; - glyphRun.glyphIndices = &glyphIndex; - glyphRun.glyphAdvances = &glyphAdvance; - glyphRun.isSideways = false; - glyphRun.bidiLevel = 0; - glyphRun.glyphOffsets = &glyphOffset; - - QTransform xform = originalTransform; - if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) - xform.scale(fontDef.stretch / 100.0, 1.0); - - DWRITE_MATRIX transform; - transform.dx = subPixelPosition.toReal(); - transform.dy = 0; - transform.m11 = xform.m11(); - transform.m12 = xform.m12(); - transform.m21 = xform.m21(); - transform.m22 = xform.m22(); - - DWRITE_RENDERING_MODE renderMode = - hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); - - IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; - HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( - &glyphRun, - 1.0f, - &transform, - renderMode, - DWRITE_MEASURING_MODE_NATURAL, - 0.0, 0.0, - &glyphAnalysis - ); - - if (SUCCEEDED(hr)) { - RECT rect; - glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); - - QRect boundingRect = QRect(QPoint(rect.left - margin, - rect.top - margin), - QPoint(rect.right + margin, - rect.bottom + margin)); - - - const int width = boundingRect.width() - 1; // -1 due to Qt's off-by-one definition of a QRect - const int height = boundingRect.height() - 1; - - QImage image; -#if defined(QT_USE_DIRECTWRITE2) - HRESULT hr = DWRITE_E_NOCOLOR; - IDWriteColorGlyphRunEnumerator *enumerator = 0; - IDWriteFactory2 *factory2 = nullptr; - if (glyphFormat == QFontEngine::Format_ARGB - && SUCCEEDED(m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), - reinterpret_cast<void **>(&factory2)))) { - hr = factory2->TranslateColorGlyphRun(0.0f, - 0.0f, - &glyphRun, - NULL, - DWRITE_MEASURING_MODE_NATURAL, - NULL, - 0, - &enumerator); - image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); - image.fill(0); - } else -#endif - { - image = QImage(width, height, QImage::Format_RGB32); - image.fill(0xffffffff); - } - -#if defined(QT_USE_DIRECTWRITE2) - BOOL ok = true; - - if (SUCCEEDED(hr)) { - while (SUCCEEDED(hr) && ok) { - const DWRITE_COLOR_GLYPH_RUN *colorGlyphRun = 0; - hr = enumerator->GetCurrentRun(&colorGlyphRun); - if (FAILED(hr)) { // No colored runs, only outline - qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::GetCurrentRun failed", __FUNCTION__); - break; - } - - IDWriteGlyphRunAnalysis *colorGlyphsAnalysis = NULL; - hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( - &colorGlyphRun->glyphRun, - 1.0f, - &transform, - renderMode, - DWRITE_MEASURING_MODE_NATURAL, - 0.0, 0.0, - &colorGlyphsAnalysis - ); - if (FAILED(hr)) { - qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed for color run", __FUNCTION__); - break; - } - - float r, g, b, a; - if (colorGlyphRun->paletteIndex == 0xFFFF) { - r = float(color.redF()); - g = float(color.greenF()); - b = float(color.blueF()); - a = float(color.alphaF()); - } else { - r = qBound(0.0f, colorGlyphRun->runColor.r, 1.0f); - g = qBound(0.0f, colorGlyphRun->runColor.g, 1.0f); - b = qBound(0.0f, colorGlyphRun->runColor.b, 1.0f); - a = qBound(0.0f, colorGlyphRun->runColor.a, 1.0f); - } - - if (!qFuzzyIsNull(a)) { - renderGlyphRun(&image, - r, - g, - b, - a, - colorGlyphsAnalysis, - boundingRect); - } - colorGlyphsAnalysis->Release(); - - hr = enumerator->MoveNext(&ok); - if (FAILED(hr)) { - qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::MoveNext failed", __FUNCTION__); - break; - } - } - } else -#endif - { - float r, g, b, a; - if (glyphFormat == QFontEngine::Format_ARGB) { - r = float(color.redF()); - g = float(color.greenF()); - b = float(color.blueF()); - a = float(color.alphaF()); - } else { - r = g = b = a = 0.0; - } - - renderGlyphRun(&image, - r, - g, - b, - a, - glyphAnalysis, - boundingRect); - } - - glyphAnalysis->Release(); - return image; - } else { - qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed", __FUNCTION__); - return QImage(); - } -} - - -void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, - float r, - float g, - float b, - float a, - IDWriteGlyphRunAnalysis *glyphAnalysis, - const QRect &boundingRect) -{ - const int width = destination->width(); - const int height = destination->height(); - - r *= 255.0; - g *= 255.0; - b *= 255.0; - - const int size = width * height * 3; - if (size > 0) { - RECT rect; - rect.left = boundingRect.left(); - rect.top = boundingRect.top(); - rect.right = boundingRect.right(); - rect.bottom = boundingRect.bottom(); - - QVarLengthArray<BYTE, 1024> alphaValueArray(size); - BYTE *alphaValues = alphaValueArray.data(); - memset(alphaValues, 0, size); - - HRESULT hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, - &rect, - alphaValues, - size); - if (SUCCEEDED(hr)) { - if (destination->hasAlphaChannel()) { - for (int y = 0; y < height; ++y) { - uint *dest = reinterpret_cast<uint *>(destination->scanLine(y)); - BYTE *src = alphaValues + width * 3 * y; - - for (int x = 0; x < width; ++x) { - float redAlpha = a * *src++ / 255.0; - float greenAlpha = a * *src++ / 255.0; - float blueAlpha = a * *src++ / 255.0; - float averageAlpha = (redAlpha + greenAlpha + blueAlpha) / 3.0; - - QRgb currentRgb = dest[x]; - dest[x] = qRgba(qRound(qRed(currentRgb) * (1.0 - averageAlpha) + averageAlpha * r), - qRound(qGreen(currentRgb) * (1.0 - averageAlpha) + averageAlpha * g), - qRound(qBlue(currentRgb) * (1.0 - averageAlpha) + averageAlpha * b), - qRound(qAlpha(currentRgb) * (1.0 - averageAlpha) + averageAlpha * 255)); - } - } - - } else { - for (int y = 0; y < height; ++y) { - uint *dest = reinterpret_cast<uint *>(destination->scanLine(y)); - BYTE *src = alphaValues + width * 3 * y; - - for (int x = 0; x < width; ++x) { - dest[x] = *(src + 0) << 16 - | *(src + 1) << 8 - | *(src + 2); - - src += 3; - } - } - } - } else { - qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); - } - } else { - glyphAnalysis->Release(); - qWarning("%s: Glyph has no bounds", __FUNCTION__); - } -} - -QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t, - QFixed subPixelPosition, - const QTransform &xform) -{ - QImage mask = imageForGlyph(t, - subPixelPosition, - glyphMargin(QFontEngine::Format_A32), - xform); - - return mask.depth() == 32 - ? mask - : mask.convertToFormat(QImage::Format_RGB32); -} - -QFontEngine *QWindowsFontEngineDirectWrite::cloneWithSize(qreal pixelSize) const -{ - QWindowsFontEngineDirectWrite *fontEngine = new QWindowsFontEngineDirectWrite(m_directWriteFontFace, - pixelSize, - m_fontEngineData); - - fontEngine->fontDef = fontDef; - fontEngine->fontDef.pixelSize = pixelSize; - if (!m_uniqueFamilyName.isEmpty()) { - fontEngine->setUniqueFamilyName(m_uniqueFamilyName); - QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); - static_cast<QWindowsFontDatabase *>(pfdb)->refUniqueFont(m_uniqueFamilyName); - } - - return fontEngine; -} - -Qt::HANDLE QWindowsFontEngineDirectWrite::handle() const -{ - return m_directWriteFontFace; -} - -void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request, - int dpi) -{ - fontDef = request; - - if (fontDef.pointSize < 0) - fontDef.pointSize = fontDef.pixelSize * 72. / dpi; - else if (fontDef.pixelSize == -1) - fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.); -} - -QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName) -{ - const QString substitute = - QWinRegistryKey(HKEY_LOCAL_MACHINE, - LR"(Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes)") - .stringValue(familyName); - return substitute.isEmpty() ? familyName : substitute; -} - -glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, - QFixed subPixelPosition, - const QTransform &originalTransform, - GlyphFormat format) -{ - Q_UNUSED(format); - - QTransform matrix = originalTransform; - if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) - matrix.scale(fontDef.stretch / 100.0, 1.0); - - glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance - - UINT16 glyphIndex = glyph; - FLOAT glyphAdvance = 0; - - DWRITE_GLYPH_OFFSET glyphOffset; - glyphOffset.advanceOffset = 0; - glyphOffset.ascenderOffset = 0; - - DWRITE_GLYPH_RUN glyphRun; - glyphRun.fontFace = m_directWriteFontFace; - glyphRun.fontEmSize = fontDef.pixelSize; - glyphRun.glyphCount = 1; - glyphRun.glyphIndices = &glyphIndex; - glyphRun.glyphAdvances = &glyphAdvance; - glyphRun.isSideways = false; - glyphRun.bidiLevel = 0; - glyphRun.glyphOffsets = &glyphOffset; - - DWRITE_MATRIX transform; - transform.dx = subPixelPosition.toReal(); - transform.dy = 0; - transform.m11 = matrix.m11(); - transform.m12 = matrix.m12(); - transform.m21 = matrix.m21(); - transform.m22 = matrix.m22(); - - DWRITE_RENDERING_MODE renderMode = - hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); - - IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; - HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( - &glyphRun, - 1.0f, - &transform, - renderMode, - DWRITE_MEASURING_MODE_NATURAL, - 0.0, 0.0, - &glyphAnalysis - ); - - if (SUCCEEDED(hr)) { - RECT rect; - glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); - glyphAnalysis->Release(); - - int margin = glyphMargin(QFontEngine::Format_A32); - - return glyph_metrics_t(rect.left - margin, - rect.top - margin, - rect.right - rect.left + margin * 2, - rect.bottom - rect.top + margin * 2, - bbox.xoff, bbox.yoff); - } else { - return glyph_metrics_t(); - } -} - -QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color) -{ - return imageForGlyph(glyph, subPixelPosition, glyphMargin(QFontEngine::Format_A32), t, color); -} - -QT_END_NAMESPACE - -#endif // QT_NO_DIRECTWRITE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h deleted file mode 100644 index c8c6b83bf9..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h +++ /dev/null @@ -1,156 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSFONTENGINEDIRECTWRITE_H -#define QWINDOWSFONTENGINEDIRECTWRITE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qglobal.h> - -#ifndef QT_NO_DIRECTWRITE - -#include <QtGui/private/qfontengine_p.h> -#include <QtCore/QSharedPointer> - -struct IDWriteFont; -struct IDWriteFontFace; -struct IDWriteFontFile; -struct IDWriteFactory; -struct IDWriteBitmapRenderTarget; -struct IDWriteGdiInterop; -struct IDWriteGlyphRunAnalysis; - -QT_BEGIN_NAMESPACE - -class QWindowsFontEngineData; - -class QWindowsFontEngineDirectWrite : public QFontEngine -{ - Q_DISABLE_COPY_MOVE(QWindowsFontEngineDirectWrite) -public: - explicit QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, - qreal pixelSize, - const QSharedPointer<QWindowsFontEngineData> &d); - ~QWindowsFontEngineDirectWrite() override; - - void initFontInfo(const QFontDef &request, int dpi); - - QFixed lineThickness() const override; - QFixed underlinePosition() const override; - bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override; - QFixed emSquareSize() const override; - - glyph_t glyphIndex(uint ucs4) const override; - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, - ShaperFlags flags) const override; - void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override; - - void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags flags) override; - - glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; - glyph_metrics_t boundingBox(glyph_t g) override; - glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, - const QTransform &matrix, GlyphFormat) override; - - QFixed ascent() const override; - QFixed capHeight() const override; - QFixed descent() const override; - QFixed leading() const override; - QFixed xHeight() const override; - qreal maxCharWidth() const override; - FaceId faceId() const override; - - bool supportsSubPixelPositions() const override; - - QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) override; - QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override; - QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) override; - QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override; - - QFontEngine *cloneWithSize(qreal pixelSize) const override; - Qt::HANDLE handle() const override; - - const QSharedPointer<QWindowsFontEngineData> &fontEngineData() const { return m_fontEngineData; } - - static QString fontNameSubstitute(const QString &familyName); - - IDWriteFontFace *directWriteFontFace() const { return m_directWriteFontFace; } - - void setUniqueFamilyName(const QString &newName) { m_uniqueFamilyName = newName; } - -private: - QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform, const QColor &color = QColor()); - void collectMetrics(); - void renderGlyphRun(QImage *destination, float r, float g, float b, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, const QRect &boundingRect); - static QString filenameFromFontFile(IDWriteFontFile *fontFile); - - const QSharedPointer<QWindowsFontEngineData> m_fontEngineData; - - IDWriteFontFace *m_directWriteFontFace; - IDWriteBitmapRenderTarget *m_directWriteBitmapRenderTarget; - - QFixed m_lineThickness; - QFixed m_underlinePosition; - int m_unitsPerEm; - QFixed m_ascent; - QFixed m_capHeight; - QFixed m_descent; - QFixed m_xHeight; - QFixed m_lineGap; - QFixed m_maxAdvanceWidth; - FaceId m_faceId; - QString m_uniqueFamilyName; -}; - -QT_END_NAMESPACE - -#endif // QT_NO_DIRECTWRITE - -#endif // QWINDOWSFONTENGINEDIRECTWRITE_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp deleted file mode 100644 index b1133dca22..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/**************************************************************************** -** -** 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 "qwindowsnativeimage_p.h" - -#include <QtGui/private/qpaintengine_p.h> -#include <QtGui/private/qpaintengine_raster_p.h> - -QT_BEGIN_NAMESPACE - -typedef struct { - BITMAPINFOHEADER bmiHeader; - DWORD redMask; - DWORD greenMask; - DWORD blueMask; -} BITMAPINFO_MASK; - -/*! - \class QWindowsNativeImage - \brief Windows Native image - - Note that size can be 0 (widget autotests with zero size), which - causes CreateDIBSection() to fail. - - \sa QWindowsBackingStore - \internal - \ingroup qt-lighthouse-win -*/ - -static inline HDC createDC() -{ - HDC display_dc = GetDC(0); - HDC hdc = CreateCompatibleDC(display_dc); - ReleaseDC(0, display_dc); - Q_ASSERT(hdc); - return hdc; -} - -static inline HBITMAP createDIB(HDC hdc, int width, int height, - QImage::Format format, - uchar **bitsIn) -{ - BITMAPINFO_MASK bmi; - memset(&bmi, 0, sizeof(bmi)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = width; - bmi.bmiHeader.biHeight = -height; // top-down. - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biSizeImage = 0; - - if (format == QImage::Format_RGB16) { - bmi.bmiHeader.biBitCount = 16; - bmi.bmiHeader.biCompression = BI_BITFIELDS; - bmi.redMask = 0xF800; - bmi.greenMask = 0x07E0; - bmi.blueMask = 0x001F; - } else { - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.redMask = 0; - bmi.greenMask = 0; - bmi.blueMask = 0; - } - - uchar *bits = nullptr; - HBITMAP bitmap = CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO *>(&bmi), - DIB_RGB_COLORS, reinterpret_cast<void **>(&bits), 0, 0); - if (Q_UNLIKELY(!bitmap || !bits)) { - qFatal("%s: CreateDIBSection failed (%dx%d, format: %d)", __FUNCTION__, - width, height, int(format)); - } - - *bitsIn = bits; - return bitmap; -} - -QWindowsNativeImage::QWindowsNativeImage(int width, int height, - QImage::Format format) : - m_hdc(createDC()) -{ - if (width != 0 && height != 0) { - uchar *bits; - m_bitmap = createDIB(m_hdc, width, height, format, &bits); - m_null_bitmap = static_cast<HBITMAP>(SelectObject(m_hdc, m_bitmap)); - m_image = QImage(bits, width, height, format); - Q_ASSERT(m_image.paintEngine()->type() == QPaintEngine::Raster); - static_cast<QRasterPaintEngine *>(m_image.paintEngine())->setDC(m_hdc); - } else { - m_image = QImage(width, height, format); - } - - GdiFlush(); -} - -QWindowsNativeImage::~QWindowsNativeImage() -{ - if (m_hdc) { - if (m_bitmap) { - if (m_null_bitmap) - SelectObject(m_hdc, m_null_bitmap); - DeleteObject(m_bitmap); - } - DeleteDC(m_hdc); - } -} - -QImage::Format QWindowsNativeImage::systemFormat() -{ - static int depth = -1; - if (depth == -1) { - if (HDC defaultDC = GetDC(0)) { - depth = GetDeviceCaps(defaultDC, BITSPIXEL); - ReleaseDC(0, defaultDC); - } else { - // FIXME Same remark as in QWindowsFontDatabase::defaultVerticalDPI() - // BONUS FIXME: Is 32 too generous/optimistic? - depth = 32; - } - } - return depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h deleted file mode 100644 index ed68ac2644..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSNATIVEIMAGE_H -#define QWINDOWSNATIVEIMAGE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/QtGlobal> -#include <QtCore/qt_windows.h> -#include <QtGui/QImage> - -QT_BEGIN_NAMESPACE - -class QWindowsNativeImage -{ - Q_DISABLE_COPY_MOVE(QWindowsNativeImage) -public: - QWindowsNativeImage(int width, int height, - QImage::Format format); - - ~QWindowsNativeImage(); - - inline int width() const { return m_image.width(); } - inline int height() const { return m_image.height(); } - - QImage &image() { return m_image; } - const QImage &image() const { return m_image; } - - HDC hdc() const { return m_hdc; } - - static QImage::Format systemFormat(); - -private: - const HDC m_hdc; - QImage m_image; - - HBITMAP m_bitmap = 0; - HBITMAP m_null_bitmap = 0; -}; - -QT_END_NAMESPACE - -#endif // QWINDOWSNATIVEIMAGE_H diff --git a/src/platformsupport/fontdatabases/windows/windows.pri b/src/platformsupport/fontdatabases/windows/windows.pri deleted file mode 100644 index 7ddfb2c281..0000000000 --- a/src/platformsupport/fontdatabases/windows/windows.pri +++ /dev/null @@ -1,34 +0,0 @@ -QT *= gui-private - -SOURCES += \ - $$PWD/qwindowsfontdatabase.cpp \ - $$PWD/qwindowsfontengine.cpp \ - $$PWD/qwindowsnativeimage.cpp - -HEADERS += \ - $$PWD/qwindowsfontdatabase_p.h \ - $$PWD/qwindowsfontengine_p.h \ - $$PWD/qwindowsnativeimage_p.h - -qtConfig(freetype) { - SOURCES += $$PWD/qwindowsfontdatabase_ft.cpp - HEADERS += $$PWD/qwindowsfontdatabase_ft_p.h -} - -qtConfig(directwrite):qtConfig(direct2d) { - qtConfig(directwrite2) { - QMAKE_USE_PRIVATE += dwrite_2 - DEFINES *= QT_USE_DIRECTWRITE2 - } else { - QMAKE_USE_PRIVATE += dwrite - } - QMAKE_USE_PRIVATE += d2d1 - - SOURCES += $$PWD/qwindowsfontenginedirectwrite.cpp - HEADERS += $$PWD/qwindowsfontenginedirectwrite_p.h -} else { - DEFINES *= QT_NO_DIRECTWRITE -} - -QMAKE_USE_PRIVATE += advapi32 ole32 user32 gdi32 -mingw: QMAKE_USE_PRIVATE += uuid diff --git a/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase.cpp b/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase.cpp deleted file mode 100644 index db58e49bb2..0000000000 --- a/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/**************************************************************************** -** -** 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 "qwinrtfontdatabase_p.h" - -#include <QtFontDatabaseSupport/private/qfontengine_ft_p.h> - -#include <QtCore/QCoreApplication> -#include <QtCore/QFile> - -#include <QtCore/QUuid> -#include <dwrite_1.h> -#include <wrl.h> -using namespace Microsoft::WRL; - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") - -QDebug operator<<(QDebug d, const QFontDef &def) -{ - QDebugStateSaver saver(d); - d.nospace(); - d << "Family=" << def.family << " Stylename=" << def.styleName - << " pointsize=" << def.pointSize << " pixelsize=" << def.pixelSize - << " styleHint=" << def.styleHint << " weight=" << def.weight - << " stretch=" << def.stretch << " hintingPreference=" - << def.hintingPreference; - return d; -} - -// Based on unicode range tables at http://www.microsoft.com/typography/otspec/os2.htm#ur -static QFontDatabase::WritingSystem writingSystemFromUnicodeRange(const DWRITE_UNICODE_RANGE &range) -{ - if (range.first >= 0x0000 && range.last <= 0x007F) - return QFontDatabase::Latin; - if (range.first >= 0x0370 && range.last <= 0x03FF) - return QFontDatabase::Greek; - if (range.first >= 0x0400 && range.last <= 0x04FF) - return QFontDatabase::Cyrillic; - if (range.first >= 0x0530 && range.last <= 0x058F) - return QFontDatabase::Armenian; - if (range.first >= 0x0590 && range.last <= 0x05FF) - return QFontDatabase::Hebrew; - if (range.first >= 0x0600 && range.last <= 0x06FF) - return QFontDatabase::Arabic; - if (range.first >= 0x0700 && range.last <= 0x074F) - return QFontDatabase::Syriac; - if (range.first >= 0x0780 && range.last <= 0x07BF) - return QFontDatabase::Thaana; - if (range.first >= 0x0900 && range.last <= 0x097F) - return QFontDatabase::Devanagari; - if (range.first >= 0x0980 && range.last <= 0x09FF) - return QFontDatabase::Bengali; - if (range.first >= 0x0A00 && range.last <= 0x0A7F) - return QFontDatabase::Gurmukhi; - if (range.first >= 0x0A80 && range.last <= 0x0AFF) - return QFontDatabase::Gujarati; - if (range.first >= 0x0B00 && range.last <= 0x0B7F) - return QFontDatabase::Oriya; - if (range.first >= 0x0B80 && range.last <= 0x0BFF) - return QFontDatabase::Tamil; - if (range.first >= 0x0C00 && range.last <= 0x0C7F) - return QFontDatabase::Telugu; - if (range.first >= 0x0C80 && range.last <= 0x0CFF) - return QFontDatabase::Kannada; - if (range.first >= 0x0D00 && range.last <= 0x0D7F) - return QFontDatabase::Malayalam; - if (range.first >= 0x0D80 && range.last <= 0x0DFF) - return QFontDatabase::Sinhala; - if (range.first >= 0x0E00 && range.last <= 0x0E7F) - return QFontDatabase::Thai; - if (range.first >= 0x0E80 && range.last <= 0x0EFF) - return QFontDatabase::Lao; - if (range.first >= 0x0F00 && range.last <= 0x0FFF) - return QFontDatabase::Tibetan; - if (range.first >= 0x1000 && range.last <= 0x109F) - return QFontDatabase::Myanmar; - if (range.first >= 0x10A0 && range.last <= 0x10FF) - return QFontDatabase::Georgian; - if (range.first >= 0x1780 && range.last <= 0x17FF) - return QFontDatabase::Khmer; - if (range.first >= 0x4E00 && range.last <= 0x9FFF) - return QFontDatabase::SimplifiedChinese; - if (range.first >= 0xAC00 && range.last <= 0xD7AF) - return QFontDatabase::Korean; - if (range.first >= 0x1680 && range.last <= 0x169F) - return QFontDatabase::Ogham; - if (range.first >= 0x16A0 && range.last <= 0x16FF) - return QFontDatabase::Runic; - if (range.first >= 0x07C0 && range.last <= 0x07FF) - return QFontDatabase::Nko; - - return QFontDatabase::Other; -} - -QWinRTFontDatabase::~QWinRTFontDatabase() -{ - qCDebug(lcQpaFonts) << __FUNCTION__; - - foreach (IDWriteFontFile *fontFile, m_fonts.keys()) - fontFile->Release(); - - foreach (IDWriteFontFamily *fontFamily, m_fontFamilies) - fontFamily->Release(); -} - -QString QWinRTFontDatabase::fontDir() const -{ - qCDebug(lcQpaFonts) << __FUNCTION__; - QString fontDirectory = QFreeTypeFontDatabase::fontDir(); - if (!QFile::exists(fontDirectory)) { - // Fall back to app directory + fonts, and just app directory after that - const QString applicationDirPath = QCoreApplication::applicationDirPath(); - fontDirectory = applicationDirPath + QLatin1String("/fonts"); - if (!QFile::exists(fontDirectory)) { - if (m_fontFamilies.isEmpty()) - qWarning("No fonts directory found in application package."); - fontDirectory = applicationDirPath; - } - } - return fontDirectory; -} - -QFont QWinRTFontDatabase::defaultFont() const -{ - return QFont(QStringLiteral("Segoe UI")); -} - -bool QWinRTFontDatabase::fontsAlwaysScalable() const -{ - return true; -} - -void QWinRTFontDatabase::populateFontDatabase() -{ - qCDebug(lcQpaFonts) << __FUNCTION__; - - ComPtr<IDWriteFactory1> factory; - HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory1), &factory); - if (FAILED(hr)) { - qWarning("Failed to create DirectWrite factory: %s", qPrintable(qt_error_string(hr))); - QFreeTypeFontDatabase::populateFontDatabase(); - return; - } - - ComPtr<IDWriteFontCollection> fontCollection; - hr = factory->GetSystemFontCollection(&fontCollection); - if (FAILED(hr)) { - qWarning("Failed to open system font collection: %s", qPrintable(qt_error_string(hr))); - QFreeTypeFontDatabase::populateFontDatabase(); - return; - } - - int fontFamilyCount = fontCollection->GetFontFamilyCount(); - for (int i = 0; i < fontFamilyCount; ++i) { - ComPtr<IDWriteFontFamily> fontFamily; - hr = fontCollection->GetFontFamily(i, &fontFamily); - if (FAILED(hr)) { - qWarning("Unable to get font family: %s", qPrintable(qt_error_string(hr))); - continue; - } - - ComPtr<IDWriteLocalizedStrings> names; - hr = fontFamily->GetFamilyNames(&names); - if (FAILED(hr)) { - qWarning("Unable to get font family names: %s", qPrintable(qt_error_string(hr))); - continue; - } - quint32 familyNameLength; - hr = names->GetStringLength(0, &familyNameLength); - if (FAILED(hr)) { - qWarning("Unable to get family name length: %s", qPrintable(qt_error_string(hr))); - continue; - } - QVector<wchar_t> familyBuffer(familyNameLength + 1); - hr = names->GetString(0, familyBuffer.data(), familyBuffer.size()); - if (FAILED(hr)) { - qWarning("Unable to create font family name: %s", qPrintable(qt_error_string(hr))); - continue; - } - QString familyName = QString::fromWCharArray(familyBuffer.data(), familyNameLength); - - m_fontFamilies.insert(familyName, fontFamily.Detach()); - - registerFontFamily(familyName); - } - - QFreeTypeFontDatabase::populateFontDatabase(); -} - -void QWinRTFontDatabase::populateFamily(const QString &familyName) -{ - qCDebug(lcQpaFonts) << __FUNCTION__ << familyName; - - IDWriteFontFamily *fontFamily = m_fontFamilies.value(familyName); - if (!fontFamily) { - qWarning("The font family %s was not found.", qPrintable(familyName)); - return; - } - - bool fontRegistered = false; - const int fontCount = fontFamily->GetFontCount(); - for (int j = 0; j < fontCount; ++j) { - ComPtr<IDWriteFont> font; - HRESULT hr = fontFamily->GetFont(j, &font); - if (FAILED(hr)) { - qWarning("Unable to get font: %s", qPrintable(qt_error_string(hr))); - continue; - } - - // Skip simulated faces - if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) - continue; - - ComPtr<IDWriteFontFace> baseFontFace; - hr = font->CreateFontFace(&baseFontFace); - if (FAILED(hr)) { - qWarning("Unable to create base font face: %s", qPrintable(qt_error_string(hr))); - continue; - } - ComPtr<IDWriteFontFace1> fontFace; - hr = baseFontFace.As(&fontFace); - if (FAILED(hr)) { - qWarning("Unable to create font face: %s", qPrintable(qt_error_string(hr))); - continue; - } - - // We can't deal with multi-file fonts - quint32 fileCount; - hr = fontFace->GetFiles(&fileCount, NULL); - if (FAILED(hr)) { - qWarning("Unable to get font file count: %s", qPrintable(qt_error_string(hr))); - continue; - } - if (fileCount != 1) - continue; - - ComPtr<IDWriteLocalizedStrings> informationalStrings; - BOOL exists; - hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_MANUFACTURER, - &informationalStrings, &exists); - if (FAILED(hr)) { - qWarning("Unable to get font foundry: %s", qPrintable(qt_error_string(hr))); - continue; - } - QString foundryName; - if (exists) { - quint32 length; - hr = informationalStrings->GetStringLength(0, &length); - if (FAILED(hr)) - qWarning("Unable to get foundry name length: %s", qPrintable(qt_error_string(hr))); - if (SUCCEEDED(hr)) { - QVector<wchar_t> buffer(length + 1); - hr = informationalStrings->GetString(0, buffer.data(), buffer.size()); - if (FAILED(hr)) - qWarning("Unable to get foundry name: %s", qPrintable(qt_error_string(hr))); - if (SUCCEEDED(hr)) - foundryName = QString::fromWCharArray(buffer.data(), length); - } - } - - QFont::Weight weight = QPlatformFontDatabase::weightFromInteger(font->GetWeight()); - - QFont::Style style; - switch (font->GetStyle()) { - default: - case DWRITE_FONT_STYLE_NORMAL: - style = QFont::StyleNormal; - break; - case DWRITE_FONT_STYLE_OBLIQUE: - style = QFont::StyleOblique; - break; - case DWRITE_FONT_STYLE_ITALIC: - style = QFont::StyleItalic; - break; - } - - QFont::Stretch stretch; - switch (font->GetStretch()) { - default: - case DWRITE_FONT_STRETCH_UNDEFINED: - case DWRITE_FONT_STRETCH_NORMAL: - stretch = QFont::Unstretched; - break; - case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: - stretch = QFont::UltraCondensed; - break; - case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: - stretch = QFont::ExtraCondensed; - break; - case DWRITE_FONT_STRETCH_CONDENSED: - stretch = QFont::Condensed; - break; - case DWRITE_FONT_STRETCH_SEMI_CONDENSED: - stretch = QFont::SemiCondensed; - break; - case DWRITE_FONT_STRETCH_SEMI_EXPANDED: - stretch = QFont::SemiExpanded; - break; - case DWRITE_FONT_STRETCH_EXPANDED: - stretch = QFont::Expanded; - break; - case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: - stretch = QFont::ExtraExpanded; - break; - case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: - stretch = QFont::UltraExpanded; - break; - } - - const bool fixedPitch = fontFace->IsMonospacedFont(); - - // Get writing systems from unicode ranges - quint32 actualRangeCount; - hr = fontFace->GetUnicodeRanges(0, nullptr, &actualRangeCount); - Q_ASSERT(hr == E_NOT_SUFFICIENT_BUFFER); - QVector<DWRITE_UNICODE_RANGE> unicodeRanges(actualRangeCount); - hr = fontFace->GetUnicodeRanges(actualRangeCount, unicodeRanges.data(), &actualRangeCount); - if (FAILED(hr)) { - qWarning("Unable to get font unicode range: %s", qPrintable(qt_error_string(hr))); - continue; - } - QSupportedWritingSystems writingSystems; - for (quint32 i = 0; i < actualRangeCount; ++i) { - const QFontDatabase::WritingSystem writingSystem = writingSystemFromUnicodeRange(unicodeRanges.at(i)); - writingSystems.setSupported(writingSystem); - } - if (writingSystems.supported(QFontDatabase::SimplifiedChinese)) { - writingSystems.setSupported(QFontDatabase::TraditionalChinese); - writingSystems.setSupported(QFontDatabase::Japanese); - } - if (writingSystems.supported(QFontDatabase::Latin)) - writingSystems.setSupported(QFontDatabase::Vietnamese); - - IDWriteFontFile *fontFile; - hr = fontFace->GetFiles(&fileCount, &fontFile); - if (FAILED(hr)) { - qWarning("Unable to get font file: %s", qPrintable(qt_error_string(hr))); - continue; - } - - FontDescription description = { fontFace->GetIndex(), QUuid::createUuid().toByteArray() }; - m_fonts.insert(fontFile, description); - registerFont(familyName, QString(), foundryName, weight, style, stretch, - true, true, 0, fixedPitch, writingSystems, fontFile); - fontRegistered = true; - } - - // Always populate something to avoid an assert - if (!fontRegistered) { - registerFont(familyName, QString(), QString(), QFont::Normal, QFont::StyleNormal, - QFont::Unstretched, false, false, 0, false, QSupportedWritingSystems(), 0); - } -} - -QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) -{ - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << handle; - - if (!handle) // Happens if a font family population failed - return 0; - - IDWriteFontFile *fontFile = reinterpret_cast<IDWriteFontFile *>(handle); - if (!m_fonts.contains(fontFile)) - return QFreeTypeFontDatabase::fontEngine(fontDef, handle); - - const void *referenceKey; - quint32 referenceKeySize; - HRESULT hr = fontFile->GetReferenceKey(&referenceKey, &referenceKeySize); - if (FAILED(hr)) { - qWarning("Unable to get font file reference key: %s", qPrintable(qt_error_string(hr))); - return 0; - } - - ComPtr<IDWriteFontFileLoader> loader; - hr = fontFile->GetLoader(&loader); - if (FAILED(hr)) { - qWarning("Unable to get font file loader: %s", qPrintable(qt_error_string(hr))); - return 0; - } - - ComPtr<IDWriteFontFileStream> stream; - hr =loader->CreateStreamFromKey(referenceKey, referenceKeySize, &stream); - if (FAILED(hr)) { - qWarning("Unable to get font file stream: %s", qPrintable(qt_error_string(hr))); - return 0; - } - - quint64 fileSize; - hr = stream->GetFileSize(&fileSize); - if (FAILED(hr)) { - qWarning("Unable to get font file size: %s", qPrintable(qt_error_string(hr))); - return 0; - } - - const void *data; - void *context; - hr = stream->ReadFileFragment(&data, 0, fileSize, &context); - if (FAILED(hr)) { - qWarning("Unable to get font file data: %s", qPrintable(qt_error_string(hr))); - return 0; - } - const QByteArray fontData((const char *)data, fileSize); - stream->ReleaseFileFragment(context); - - QFontEngine::FaceId faceId; - const FontDescription description = m_fonts.value(fontFile); - faceId.uuid = description.uuid; - faceId.index = description.index; - - return QFontEngineFT::create(fontDef, faceId, fontData); -} - -QString QWinRTFontDatabase::familyForStyleHint(QFont::StyleHint styleHint) -{ - switch (styleHint) { - case QFont::Times: - return QStringLiteral("Times New Roman"); - case QFont::Courier: - return QStringLiteral("Courier New"); - case QFont::Monospace: - return QStringLiteral("Courier New"); - case QFont::Cursive: - return QStringLiteral("Comic Sans MS"); - case QFont::Fantasy: - return QStringLiteral("Impact"); - case QFont::Decorative: - return QStringLiteral("Old English"); - case QFont::Helvetica: - return QStringLiteral("Segoe UI"); - case QFont::System: - default: - break; - } - return QStringLiteral("Segoe UI"); -} - -QStringList QWinRTFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, - QFont::StyleHint styleHint, - QChar::Script script) const -{ - Q_UNUSED(style) - Q_UNUSED(script) - - qCDebug(lcQpaFonts) << __FUNCTION__ << family; - - QStringList result; - result.append(QWinRTFontDatabase::familyForStyleHint(styleHint)); - result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script)); - return result; -} - -void QWinRTFontDatabase::releaseHandle(void *handle) -{ - qCDebug(lcQpaFonts) << __FUNCTION__ << handle; - - if (!handle) - return; - - IDWriteFontFile *fontFile = reinterpret_cast<IDWriteFontFile *>(handle); - if (m_fonts.contains(fontFile)) { - m_fonts.remove(fontFile); - fontFile->Release(); - return; - } - - QFreeTypeFontDatabase::releaseHandle(handle); -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase_p.h b/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase_p.h deleted file mode 100644 index c21f411fff..0000000000 --- a/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase_p.h +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QWINRTFONTDATABASE_H -#define QWINRTFONTDATABASE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h> -#include <QtCore/QLoggingCategory> - -struct IDWriteFontFile; -struct IDWriteFontFamily; - -QT_BEGIN_NAMESPACE - -Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts) - -struct FontDescription -{ - quint32 index; - QByteArray uuid; -}; - -class QWinRTFontDatabase : public QFreeTypeFontDatabase -{ -public: - ~QWinRTFontDatabase(); - QString fontDir() const override; - QFont defaultFont() const override; - bool fontsAlwaysScalable() const override; - void populateFontDatabase() override; - void populateFamily(const QString &familyName) override; - QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override; - QStringList fallbacksForFamily(const QString &family, QFont::Style style, - QFont::StyleHint styleHint, QChar::Script script) const override; - void releaseHandle(void *handle) override; - - static QString familyForStyleHint(QFont::StyleHint styleHint); -private: - QHash<IDWriteFontFile *, FontDescription> m_fonts; - QHash<QString, IDWriteFontFamily *> m_fontFamilies; -}; - -QT_END_NAMESPACE - -#endif // QWINRTFONTDATABASE_H diff --git a/src/platformsupport/fontdatabases/winrt/winrt.pri b/src/platformsupport/fontdatabases/winrt/winrt.pri deleted file mode 100644 index 1cd417c1fd..0000000000 --- a/src/platformsupport/fontdatabases/winrt/winrt.pri +++ /dev/null @@ -1,11 +0,0 @@ -QT *= gui-private - -SOURCES += \ - $$PWD/qwinrtfontdatabase.cpp - -HEADERS += \ - $$PWD/qwinrtfontdatabase_p.h - -DEFINES += __WRL_NO_DEFAULT_LIB__ - -QMAKE_USE_PRIVATE += dwrite_1 ws2_32 |