354 QString faceName = familyName;
355 faceName.truncate(LF_FACESIZE - 1);
357 HDC hdc = GetDC( 0 );
359 memset(&lf, 0,
sizeof(LOGFONT));
360 faceName.toWCharArray(lf.lfFaceName);
361 lf.lfFaceName[faceName.size()] = 0;
362 lf.lfCharSet = DEFAULT_CHARSET;
363 HFONT hfont = CreateFontIndirect(&lf);
370 HGDIOBJ oldobj = SelectObject( hdc, hfont );
372 const DWORD name_tag = qFromBigEndian(QFont::Tag(
"name").value());
375 unsigned char *table = 0;
377 DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
378 if ( bytes == GDI_ERROR ) {
384 table =
new unsigned char[bytes];
385 GetFontData(hdc, name_tag, 0, table, bytes);
386 if ( bytes == GDI_ERROR )
390 const QFontNames names = qt_getCanonicalFontNames(table, bytes);
391 i18n_name = names.name;
393 i18n_name += u' ' + names.style;
397 SelectObject( hdc, oldobj );
398 DeleteObject( hfont );
453 const LOGFONT &logFont,
454 const TEXTMETRIC *textmetric,
455 const FONTSIGNATURE *signature,
457 StoreFontPayload *sfp)
460 if (familyName.isEmpty() || familyName.at(0) == u'@' || familyName.startsWith(
"WST_"_L1))
463 uchar charSet = logFont.lfCharSet;
465 static const int SMOOTH_SCALABLE = 0xffff;
466 const QString foundryName;
467 const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH);
468 const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE);
469 const bool unreliableTextMetrics = type == 0;
470 const bool scalable = (textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE))
471 && !unreliableTextMetrics;
472 const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight;
473 const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal;
474 const bool antialias =
false;
475 const QFont::Weight weight =
static_cast<QFont::Weight>(textmetric->tmWeight);
476 const QFont::Stretch stretch = QFont::Unstretched;
478#ifndef QT_NO_DEBUG_OUTPUT
479 if (lcQpaFonts().isDebugEnabled()) {
481 QTextStream str(&message);
482 str <<
__FUNCTION__ <<
' ' << familyName <<
' ' << charSet <<
" TTF=" << ttf;
483 if (type & DEVICE_FONTTYPE)
485 if (type & RASTER_FONTTYPE)
487 if (type & TRUETYPE_FONTTYPE)
489 str <<
" scalable=" << scalable <<
" Size=" << size
490 <<
" Style=" << style <<
" Weight=" << weight
491 <<
" stretch=" << stretch <<
" styleName=" << styleName;
492 qCDebug(lcQpaFonts) << message;
498 QString subFamilyName;
499 QString subFamilyStyle;
501 QFontNames canonicalNames = qt_getCanonicalFontNames(logFont);
502 if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty())
503 englishName = canonicalNames.name;
504 if (!canonicalNames.preferredName.isEmpty()) {
505 subFamilyName = familyName;
506 subFamilyStyle = styleName;
507 faceName = familyName;
508 familyName = canonicalNames.preferredName;
514 if (!canonicalNames.preferredStyle.isEmpty())
515 styleName = canonicalNames.preferredStyle;
518 QSupportedWritingSystems writingSystems;
519 if (type & TRUETYPE_FONTTYPE) {
521 quint32 unicodeRange[4] = {
522 signature->fsUsb[0], signature->fsUsb[1],
523 signature->fsUsb[2], signature->fsUsb[3]
525 quint32 codePageRange[2] = {
526 signature->fsCsb[0], signature->fsCsb[1]
528 writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
534 if (writingSystems.supported(QFontDatabase::Thai) &&
535 familyName ==
"Segoe UI"_L1)
536 writingSystems.setSupported(QFontDatabase::Thai,
false);
538 const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet);
539 if (ws != QFontDatabase::Any)
540 writingSystems.setSupported(ws);
543 const bool wasPopulated = QPlatformFontDatabase::isFamilyPopulated(familyName);
544 QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight,
545 style, stretch, antialias, scalable, size, fixed,
false, writingSystems,
new QWindowsFontDatabase::FontHandle(faceName));
549 if (weight <= QFont::DemiBold && styleName.isEmpty())
550 QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
551 style, stretch, antialias, scalable, size, fixed,
false, writingSystems,
new QWindowsFontDatabase::FontHandle(faceName));
552 if (style != QFont::StyleItalic && styleName.isEmpty())
553 QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight,
554 QFont::StyleItalic, stretch, antialias, scalable, size, fixed,
false, writingSystems,
new QWindowsFontDatabase::FontHandle(faceName));
555 if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty())
556 QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
557 QFont::StyleItalic, stretch, antialias, scalable, size, fixed,
false, writingSystems,
new QWindowsFontDatabase::FontHandle(faceName));
562 if (!subFamilyName.isEmpty()
563 && familyName != subFamilyName
564 && sfp->populatedFontFamily != familyName
566 sfp->windowsFontDatabase->populateFamily(familyName);
569 if (!subFamilyName.isEmpty() && familyName != subFamilyName) {
570 QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight,
571 style, stretch, antialias, scalable, size, fixed,
false, writingSystems,
new QWindowsFontDatabase::FontHandle(faceName));
574 if (!englishName.isEmpty() && englishName != familyName)
575 QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName);
752QFontEngine *QWindowsFontDatabase::fontEngine(
const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
754 EmbeddedFont font(fontData);
755 QFontEngine *fontEngine = 0;
757#if QT_CONFIG(directwrite)
758 if (!useDirectWrite(hintingPreference))
765QT_WARNING_DISABLE_GCC(
"-Wstrict-aliasing")
766 QString uniqueFamilyName = u'f'
767 + QString::number(guid.Data1, 36) + u'-'
768 + QString::number(guid.Data2, 36) + u'-'
769 + QString::number(guid.Data3, 36) + u'-'
770 + QString::number(*
reinterpret_cast<quint64 *>(guid.Data4), 36);
773 QString actualFontName = font.changeFamilyName(uniqueFamilyName);
774 if (actualFontName.isEmpty()) {
775 qCWarning(lcQpaFonts,
"%s: Can't change family name of font",
__FUNCTION__);
780 QByteArray newFontData = font.data();
782 AddFontMemResourceEx(
const_cast<
char *>(newFontData.constData()),
783 DWORD(newFontData.size()), 0, &count);
784 if (count == 0 && fontHandle != 0) {
785 RemoveFontMemResourceEx(fontHandle);
789 if (fontHandle == 0) {
790 qCWarning(lcQpaFonts,
"%s: AddFontMemResourceEx failed",
__FUNCTION__);
793 request.families = QStringList(uniqueFamilyName);
794 request.pixelSize = pixelSize;
795 request.styleStrategy = QFont::PreferMatch;
796 request.hintingPreference = hintingPreference;
797 request.stretch = QFont::Unstretched;
799 fontEngine = QWindowsFontDatabase::createEngine(request, QString(),
800 defaultVerticalDPI(),
804 if (request.families != fontEngine->fontDef.families) {
805 qCWarning(lcQpaFonts,
"%s: Failed to load font. Got fallback instead: %s",
__FUNCTION__,
806 qPrintable(fontEngine->fontDef.families.constFirst()));
807 if (fontEngine->ref.loadRelaxed() == 0)
811 Q_ASSERT(fontEngine->ref.loadRelaxed() == 0);
814 switch (fontEngine->type()) {
815 case QFontEngine::Win:
816 static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
817 fontEngine->fontDef.families = QStringList(actualFontName);
819#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
820 case QFontEngine::DirectWrite:
821 static_cast<QWindowsFontEngineDirectWrite *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
822 fontEngine->fontDef.families = QStringList(actualFontName);
827 Q_ASSERT_X(
false, Q_FUNC_INFO,
"Unhandled font engine.");
830 UniqueFontData uniqueData{};
831 uniqueData.handle = fontHandle;
832 ++uniqueData.refCount;
834 const std::scoped_lock lock(m_uniqueFontDataMutex);
835 m_uniqueFontData[uniqueFamilyName] = uniqueData;
839 RemoveFontMemResourceEx(fontHandle);
844 if (fontEngine !=
nullptr)
845 font.updateFromOS2Table(fontEngine);
847#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
849 fontEngine = QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference);
853 qCDebug(lcQpaFonts) <<
__FUNCTION__ <<
"FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine;
928 QList<QFontNames> *families,
929 QList<FONTSIGNATURE> *signatures,
930 QList<QFontValues> *values)
932 const uchar *data =
reinterpret_cast<
const uchar *>(fontData.constData());
933 const uchar *dataEndSentinel = data + fontData.size();
935 QList<quint32> offsets = getTrueTypeFontOffsets(data, dataEndSentinel);
936 if (offsets.isEmpty())
939 for (
int i = 0; i < offsets.count(); ++i) {
940 const uchar *font = data + offsets.at(i);
943 getFontTable(data, dataEndSentinel, font,
944 qFromBigEndian(QFont::Tag(
"name").value()),
948 QFontNames names = qt_getCanonicalFontNames(table, length);
949 if (names.name.isEmpty())
952 families->append(
std::move(names));
954 if (values || signatures) {
955 getFontTable(data, dataEndSentinel, font,
956 qFromBigEndian(QFont::Tag(
"OS/2").value()),
962 if (table && length >= 64) {
964 fontValues.weight = qFromBigEndian<quint16>(table + 4);
966 quint16 fsSelection = qFromBigEndian<quint16>(table + 62);
967 fontValues
.isItalic = (fsSelection & 1) != 0;
971 values->append(
std::move(fontValues));
975 FONTSIGNATURE signature;
976 if (table && length >= 86) {
978 signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42);
979 signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46);
980 signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50);
981 signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54);
983 signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78);
984 signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82);
986 memset(&signature, 0,
sizeof(signature));
988 signatures->append(signature);
993QStringList QWindowsFontDatabase::addApplicationFont(
const QByteArray &fontData,
const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont)
995 WinApplicationFont font;
996 font.fileName = fileName;
997 QList<FONTSIGNATURE> signatures;
998 QList<QFontValues> fontValues;
999 QList<QFontNames> families;
1000 QStringList familyNames;
1002 if (!fontData.isEmpty()) {
1003 getFamiliesAndSignatures(fontData, &families, &signatures, &fontValues);
1004 if (families.isEmpty())
1009 AddFontMemResourceEx(
const_cast<
char *>(fontData.constData()),
1010 DWORD(fontData.size()), 0, &dummy);
1011 if (font.handle == 0)
1012 return QStringList();
1015 for (
int j = 0; j < families.count(); ++j) {
1016 const auto &family = families.at(j);
1017 const QString &familyName = family.name;
1018 const QString &styleName = family.style;
1019 familyNames << familyName;
1022 memset(&lf, 0,
sizeof(LOGFONT));
1023 memcpy(lf.lfFaceName, familyName.data(),
sizeof(
wchar_t) * qMin(LF_FACESIZE - 1, familyName.size()));
1024 lf.lfCharSet = DEFAULT_CHARSET;
1025 const QFontValues &values = fontValues.at(j);
1026 lf.lfWeight = values.weight;
1027 if (values.isItalic)
1029 if (values.isOverstruck)
1030 lf.lfStrikeOut = TRUE;
1031 if (values.isUnderlined)
1032 lf.lfUnderline = TRUE;
1033 HFONT hfont = CreateFontIndirect(&lf);
1034 HGDIOBJ oldobj = SelectObject(hdc, hfont);
1036 if (applicationFont !=
nullptr) {
1037 QFontDatabasePrivate::ApplicationFont::Properties properties;
1038 properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal;
1039 properties.weight =
static_cast<
int>(values.weight);
1040 properties.familyName = familyName;
1041 properties.styleName = styleName;
1043 applicationFont->properties.append(properties);
1046 TEXTMETRIC textMetrics;
1047 GetTextMetrics(hdc, &textMetrics);
1049 StoreFontPayload sfp(familyName,
this);
1050 addFontToDatabase(familyName, styleName, lf, &textMetrics, &signatures.at(j),
1051 TRUETYPE_FONTTYPE, &sfp);
1053 SelectObject(hdc, oldobj);
1054 DeleteObject(hfont);
1059 if (!f.open(QIODevice::ReadOnly))
1060 return QStringList();
1061 QByteArray data = f.readAll();
1065 getFamiliesAndSignatures(data, &families,
nullptr, applicationFont !=
nullptr ? &fontValues :
nullptr);
1067 if (families.isEmpty())
1068 return QStringList();
1070 if (AddFontResourceExW((
wchar_t*)fileName.utf16(), FR_PRIVATE, 0) == 0)
1071 return QStringList();
1076 for (
int j = 0; j < families.count(); ++j) {
1077 const QString familyName = families.at(j).name;
1078 familyNames << familyName;
1080 if (applicationFont !=
nullptr) {
1081 const QString &styleName = families.at(j).style;
1082 const QFontValues &values = fontValues.at(j);
1084 QFontDatabasePrivate::ApplicationFont::Properties properties;
1085 properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal;
1086 properties.weight =
static_cast<
int>(values.weight);
1087 properties.familyName = familyName;
1088 properties.styleName = styleName;
1090 applicationFont->properties.append(properties);
1093 populateFamily(familyName);
1097 m_applicationFonts << font;
1184QFontEngine *QWindowsFontDatabase::createEngine(
const QFontDef &request,
const QString &faceName,
1186 const QSharedPointer<QWindowsFontEngineData> &data)
1188 QFontEngine *fe =
nullptr;
1190 LOGFONT lf = fontDefToLOGFONT(request, faceName);
1191 const bool preferClearTypeAA = lf.lfQuality == CLEARTYPE_QUALITY;
1193 if (request.stretch != 100) {
1194 HFONT hfont = CreateFontIndirect(&lf);
1196 qErrnoWarning(
"%s: CreateFontIndirect failed",
__FUNCTION__);
1197 hfont = QWindowsFontDatabase::systemFont();
1200 HGDIOBJ oldObj = SelectObject(data->hdc, hfont);
1202 if (!GetTextMetrics(data->hdc, &tm))
1203 qErrnoWarning(
"%s: GetTextMetrics failed",
__FUNCTION__);
1205 lf.lfWidth = tm.tmAveCharWidth * request.stretch / 100;
1206 SelectObject(data->hdc, oldObj);
1208 DeleteObject(hfont);
1211#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
1212 if (data->directWriteFactory !=
nullptr) {
1213 const QString fam = QString::fromWCharArray(lf.lfFaceName);
1214 const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam);
1215 if (nameSubstitute != fam) {
1216 const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1);
1217 memcpy(lf.lfFaceName, nameSubstitute.data(), nameSubstituteLength *
sizeof(
wchar_t));
1218 lf.lfFaceName[nameSubstituteLength] = 0;
1221 HFONT hfont = CreateFontIndirect(&lf);
1223 qErrnoWarning(
"%s: CreateFontIndirect failed",
__FUNCTION__);
1225 HGDIOBJ oldFont = SelectObject(data->hdc, hfont);
1227 const QFont::HintingPreference hintingPreference =
1228 static_cast<QFont::HintingPreference>(request.hintingPreference);
1229 bool useDw = useDirectWrite(hintingPreference, fam);
1231 IDWriteFontFace *directWriteFontFace = NULL;
1232 HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace);
1233 if (SUCCEEDED(hr)) {
1234 bool isColorFont =
false;
1235 bool needsSimulation =
false;
1236#if QT_CONFIG(direct2d)
1237 IDWriteFontFace2 *directWriteFontFace2 =
nullptr;
1238 if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2),
1239 reinterpret_cast<
void **>(&directWriteFontFace2)))) {
1240 if (directWriteFontFace2->IsColorFont())
1241 isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0;
1243 needsSimulation = directWriteFontFace2->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE;
1245 directWriteFontFace2->Release();
1248 useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont) || needsSimulation;
1250 <<
__FUNCTION__ << request.families.first() << request.pointSize <<
"pt"
1251 <<
"hintingPreference=" << hintingPreference <<
"color=" << isColorFont
1253 <<
"useDirectWrite=" << useDw;
1255 QWindowsFontEngineDirectWrite *fedw =
new QWindowsFontEngineDirectWrite(directWriteFontFace,
1260 GetTextFace(data->hdc, 64, n);
1262 QFontDef fontDef = request;
1263 fontDef.families = QStringList(QString::fromWCharArray(n));
1264 fedw->initFontInfo(fontDef, dpi);
1267 directWriteFontFace->Release();
1269 const QString errorString = qt_error_string(
int(hr));
1270 qCWarning(lcQpaFonts).noquote().nospace() <<
"DirectWrite: CreateFontFaceFromHDC() failed ("
1271 << errorString <<
") for " << request <<
' ' << lf <<
" dpi=" << dpi;
1274 SelectObject(data->hdc, oldFont);
1275 DeleteObject(hfont);
1281 QWindowsFontEngine *few =
new QWindowsFontEngine(request.families.first(), lf, data);
1282 if (preferClearTypeAA)
1283 few->glyphFormat = QFontEngine::Format_A32;
1284 few->initFontInfo(request, dpi);