1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qfreetypefontdatabase_p.h"
5
6#include <QtGui/private/qguiapplication_p.h>
7#include <qpa/qplatformscreen.h>
8
9#include <QtCore/QFile>
10#include <QtCore/QLibraryInfo>
11#include <QtCore/QDir>
12#include <QtCore/QtEndian>
13
14#undef QT_NO_FREETYPE
15#include "qfontengine_ft_p.h"
16
17#include <ft2build.h>
18#include FT_TRUETYPE_TABLES_H
19#include FT_ERRORS_H
20
21QT_BEGIN_NAMESPACE
22
23using namespace Qt::StringLiterals;
24
25void QFreeTypeFontDatabase::populateFontDatabase()
26{
27 QString fontpath = fontDir();
28 QDir dir(fontpath);
29
30 if (!dir.exists()) {
31 qWarning(msg: "QFontDatabase: Cannot find font directory %s.\n"
32 "Note that Qt no longer ships fonts. Deploy some (from https://dejavu-fonts.github.io/ for example) or switch to fontconfig.",
33 qPrintable(fontpath));
34 return;
35 }
36
37 static const QString nameFilters[] = {
38 u"*.ttf"_s,
39 u"*.pfa"_s,
40 u"*.pfb"_s,
41 u"*.otf"_s,
42 };
43
44 const auto fis = dir.entryInfoList(nameFilters: QStringList::fromReadOnlyData(t: nameFilters), filters: QDir::Files);
45 for (const QFileInfo &fi : fis) {
46 const QByteArray file = QFile::encodeName(fileName: fi.absoluteFilePath());
47 QFreeTypeFontDatabase::addTTFile(fontData: QByteArray(), file);
48 }
49}
50
51QFontEngine *QFreeTypeFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPtr)
52{
53 FontFile *fontfile = static_cast<FontFile *>(usrPtr);
54 QFontEngine::FaceId faceId;
55 faceId.filename = QFile::encodeName(fileName: fontfile->fileName);
56 faceId.index = fontfile->indexValue;
57
58 return QFontEngineFT::create(fontDef, faceId, fontData: fontfile->data);
59}
60
61QFontEngine *QFreeTypeFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize,
62 QFont::HintingPreference hintingPreference)
63{
64 return QFontEngineFT::create(fontData, pixelSize, hintingPreference);
65}
66
67QStringList QFreeTypeFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont)
68{
69 return QFreeTypeFontDatabase::addTTFile(fontData, file: fileName.toLocal8Bit(), applicationFont);
70}
71
72void QFreeTypeFontDatabase::releaseHandle(void *handle)
73{
74 FontFile *file = static_cast<FontFile *>(handle);
75 delete file;
76}
77
78extern FT_Library qt_getFreetype();
79
80QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file, QFontDatabasePrivate::ApplicationFont *applicationFont)
81{
82 FT_Library library = qt_getFreetype();
83
84 int index = 0;
85 int numFaces = 0;
86 QStringList families;
87 do {
88 FT_Face face;
89 FT_Error error;
90 if (!fontData.isEmpty()) {
91 error = FT_New_Memory_Face(library, file_base: (const FT_Byte *)fontData.constData(), file_size: fontData.size(), face_index: index, aface: &face);
92 } else {
93 error = FT_New_Face(library, filepathname: file.constData(), face_index: index, aface: &face);
94 }
95 if (error != FT_Err_Ok) {
96 qDebug() << "FT_New_Face failed with index" << index << ':' << Qt::hex << error;
97 break;
98 }
99 numFaces = face->num_faces;
100
101 QFont::Weight weight = QFont::Normal;
102
103 QFont::Style style = QFont::StyleNormal;
104 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
105 style = QFont::StyleItalic;
106
107 if (face->style_flags & FT_STYLE_FLAG_BOLD)
108 weight = QFont::Bold;
109
110 bool fixedPitch = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH);
111 QSupportedWritingSystems writingSystems;
112 // detect symbol fonts
113 for (int i = 0; i < face->num_charmaps; ++i) {
114 FT_CharMap cm = face->charmaps[i];
115 if (cm->encoding == FT_ENCODING_ADOBE_CUSTOM
116 || cm->encoding == FT_ENCODING_MS_SYMBOL) {
117 writingSystems.setSupported(QFontDatabase::Symbol);
118 break;
119 }
120 }
121
122 QFont::Stretch stretch = QFont::Unstretched;
123 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
124 if (os2) {
125 quint32 unicodeRange[4] = {
126 quint32(os2->ulUnicodeRange1),
127 quint32(os2->ulUnicodeRange2),
128 quint32(os2->ulUnicodeRange3),
129 quint32(os2->ulUnicodeRange4)
130 };
131 quint32 codePageRange[2] = {
132 quint32(os2->ulCodePageRange1),
133 quint32(os2->ulCodePageRange2)
134 };
135
136 writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
137
138 if (os2->usWeightClass) {
139 weight = static_cast<QFont::Weight>(os2->usWeightClass);
140 } else if (os2->panose[2]) {
141 int w = os2->panose[2];
142 if (w <= 1)
143 weight = QFont::Thin;
144 else if (w <= 2)
145 weight = QFont::ExtraLight;
146 else if (w <= 3)
147 weight = QFont::Light;
148 else if (w <= 5)
149 weight = QFont::Normal;
150 else if (w <= 6)
151 weight = QFont::Medium;
152 else if (w <= 7)
153 weight = QFont::DemiBold;
154 else if (w <= 8)
155 weight = QFont::Bold;
156 else if (w <= 9)
157 weight = QFont::ExtraBold;
158 else if (w <= 10)
159 weight = QFont::Black;
160 }
161
162 switch (os2->usWidthClass) {
163 case 1:
164 stretch = QFont::UltraCondensed;
165 break;
166 case 2:
167 stretch = QFont::ExtraCondensed;
168 break;
169 case 3:
170 stretch = QFont::Condensed;
171 break;
172 case 4:
173 stretch = QFont::SemiCondensed;
174 break;
175 case 5:
176 stretch = QFont::Unstretched;
177 break;
178 case 6:
179 stretch = QFont::SemiExpanded;
180 break;
181 case 7:
182 stretch = QFont::Expanded;
183 break;
184 case 8:
185 stretch = QFont::ExtraExpanded;
186 break;
187 case 9:
188 stretch = QFont::UltraExpanded;
189 break;
190 }
191 }
192
193 QString family = QString::fromLatin1(ba: face->family_name);
194 FontFile *fontFile = new FontFile{
195 .fileName: QFile::decodeName(localFileName: file),
196 .indexValue: index,
197 .data: fontData
198 };
199
200 QString styleName = QString::fromLatin1(ba: face->style_name);
201
202 if (applicationFont != nullptr) {
203 QFontDatabasePrivate::ApplicationFont::Properties properties;
204 properties.familyName = family;
205 properties.styleName = styleName;
206 properties.weight = weight;
207 properties.stretch = stretch;
208 properties.style = style;
209
210 applicationFont->properties.append(t: properties);
211 }
212
213 registerFont(familyname: family, stylename: styleName, foundryname: QString(), weight, style, stretch, antialiased: true, scalable: true, pixelSize: 0, fixedPitch, writingSystems, handle: fontFile);
214 families.append(t: family);
215
216 FT_Done_Face(face);
217 ++index;
218 } while (index < numFaces);
219 return families;
220}
221
222QT_END_NAMESPACE
223

source code of qtbase/src/gui/text/freetype/qfreetypefontdatabase.cpp