1// Copyright (C) 2021 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#ifndef QFONTENGINE_FT_P_H
4#define QFONTENGINE_FT_P_H
5//
6// W A R N I N G
7// -------------
8//
9// This file is not part of the Qt API. It exists purely as an
10// implementation detail. This header file may change from version to
11// version without notice, or even be removed.
12//
13// We mean it.
14//
15
16#include "private/qfontengine_p.h"
17
18#ifndef QT_NO_FREETYPE
19
20#include <ft2build.h>
21#include FT_FREETYPE_H
22
23
24#ifndef Q_OS_WIN
25#include <unistd.h>
26#endif
27
28#include <qmutex.h>
29
30#include <string.h>
31
32QT_BEGIN_NAMESPACE
33
34class QFontEngineFTRawFont;
35class QFontconfigDatabase;
36
37/*
38 * This class represents one font file on disk (like Arial.ttf) and is shared between all the font engines
39 * that show this font file (at different pixel sizes).
40 */
41class Q_GUI_EXPORT QFreetypeFace
42{
43public:
44 void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing, QFixed *scalableBitmapScaleFactor);
45 QFontEngine::Properties properties() const;
46 bool getSfntTable(uint tag, uchar *buffer, uint *length) const;
47
48 static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id,
49 const QByteArray &fontData = QByteArray());
50 void release(const QFontEngine::FaceId &face_id);
51
52 static int getFaceIndexByStyleName(const QString &faceFileName, const QString &styleName);
53
54 // locks the struct for usage. Any read/write operations require locking.
55 void lock()
56 {
57 _lock.lock();
58 }
59 void unlock()
60 {
61 _lock.unlock();
62 }
63
64 FT_Face face;
65 int xsize; // 26.6
66 int ysize; // 26.6
67 FT_Matrix matrix;
68 FT_CharMap unicode_map;
69 FT_CharMap symbol_map;
70
71 enum { cmapCacheSize = 0x200 };
72 glyph_t cmapCache[cmapCacheSize];
73
74 int fsType() const;
75
76 int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints);
77
78 bool isScalableBitmap() const;
79
80 static void addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale);
81 static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path);
82
83private:
84 friend class QFontEngineFT;
85 friend class QtFreetypeData;
86 QFreetypeFace() = default;
87 ~QFreetypeFace() {}
88 void cleanup();
89 QAtomicInt ref;
90 QRecursiveMutex _lock;
91 QByteArray fontData;
92
93 QFontEngine::Holder hbFace;
94};
95
96class Q_GUI_EXPORT QFontEngineFT : public QFontEngine
97{
98public:
99 struct GlyphInfo {
100 int linearAdvance;
101 unsigned short width;
102 unsigned short height;
103 short x;
104 short y;
105 short xOff;
106 short yOff;
107 };
108
109 struct GlyphAndSubPixelPosition
110 {
111 GlyphAndSubPixelPosition(glyph_t g, const QFixedPoint spp) : glyph(g), subPixelPosition(spp) {}
112
113 bool operator==(const GlyphAndSubPixelPosition &other) const
114 {
115 return glyph == other.glyph && subPixelPosition == other.subPixelPosition;
116 }
117
118 glyph_t glyph;
119 QFixedPoint subPixelPosition;
120 };
121
122 struct QGlyphSet
123 {
124 QGlyphSet();
125 ~QGlyphSet();
126 FT_Matrix transformationMatrix;
127 bool outline_drawing;
128
129 void removeGlyphFromCache(glyph_t index, const QFixedPoint &subPixelPosition);
130 void clear();
131 inline bool useFastGlyphData(glyph_t index, const QFixedPoint &subPixelPosition) const {
132 return (index < 256 && subPixelPosition.x == 0 && subPixelPosition.y == 0);
133 }
134 inline Glyph *getGlyph(glyph_t index,
135 const QFixedPoint &subPixelPositionX = QFixedPoint()) const;
136 void setGlyph(glyph_t index, const QFixedPoint &spp, Glyph *glyph);
137
138 inline bool isGlyphMissing(glyph_t index) const { return missing_glyphs.contains(value: index); }
139 inline void setGlyphMissing(glyph_t index) const { missing_glyphs.insert(value: index); }
140private:
141 Q_DISABLE_COPY(QGlyphSet);
142 mutable QHash<GlyphAndSubPixelPosition, Glyph *> glyph_data; // maps from glyph index to glyph data
143 mutable QSet<glyph_t> missing_glyphs;
144 mutable Glyph *fast_glyph_data[256]; // for fast lookup of glyphs < 256
145 mutable int fast_glyph_count;
146 };
147
148 QFontEngine::FaceId faceId() const override;
149 QFontEngine::Properties properties() const override;
150 QFixed emSquareSize() const override;
151 bool supportsHorizontalSubPixelPositions() const override
152 {
153 return default_hint_style == HintLight ||
154 default_hint_style == HintNone;
155 }
156
157 bool supportsVerticalSubPixelPositions() const override
158 {
159 return supportsHorizontalSubPixelPositions();
160 }
161
162 bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override;
163 int synthesized() const override;
164
165 void initializeHeightMetrics() const override;
166 QFixed capHeight() const override;
167 QFixed xHeight() const override;
168 QFixed averageCharWidth() const override;
169
170 qreal maxCharWidth() const override;
171 QFixed lineThickness() const override;
172 QFixed underlinePosition() const override;
173
174 glyph_t glyphIndex(uint ucs4) const override;
175 void doKerning(QGlyphLayout *, ShaperFlags) const override;
176
177 void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override;
178
179 bool supportsTransformation(const QTransform &transform) const override;
180
181 void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
182 QPainterPath *path, QTextItem::RenderFlags flags) override;
183 void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
184 QPainterPath *path, QTextItem::RenderFlags flags) override;
185
186 bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
187
188 glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
189 glyph_metrics_t boundingBox(glyph_t glyph) override;
190 glyph_metrics_t boundingBox(glyph_t glyph, const QTransform &matrix) override;
191
192 void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags flags) const override;
193 QImage alphaMapForGlyph(glyph_t g) override { return alphaMapForGlyph(g, QFixedPoint()); }
194 QImage alphaMapForGlyph(glyph_t, const QFixedPoint &) override;
195 QImage alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &t) override;
196 QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override;
197 QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color) override;
198 glyph_metrics_t alphaMapBoundingBox(glyph_t glyph,
199 const QFixedPoint &subPixelPosition,
200 const QTransform &matrix,
201 QFontEngine::GlyphFormat format) override;
202 Glyph *glyphData(glyph_t glyph,
203 const QFixedPoint &subPixelPosition,
204 GlyphFormat neededFormat,
205 const QTransform &t) override;
206 bool hasInternalCaching() const override { return cacheEnabled; }
207 bool expectsGammaCorrectedBlending() const override;
208
209 void removeGlyphFromCache(glyph_t glyph) override;
210 int glyphMargin(QFontEngine::GlyphFormat /* format */) override { return 0; }
211
212 int glyphCount() const override;
213
214 enum Scaling {
215 Scaled,
216 Unscaled
217 };
218 FT_Face lockFace(Scaling scale = Scaled) const;
219 void unlockFace() const;
220
221 FT_Face non_locked_face() const;
222
223 inline bool drawAntialiased() const { return antialias; }
224 inline bool invalid() const { return xsize == 0 && ysize == 0; }
225 inline bool isBitmapFont() const { return defaultFormat == Format_Mono; }
226 inline bool isScalableBitmap() const { return freetype->isScalableBitmap(); }
227
228 inline Glyph *loadGlyph(uint glyph,
229 const QFixedPoint &subPixelPosition,
230 GlyphFormat format = Format_None,
231 bool fetchMetricsOnly = false,
232 bool disableOutlineDrawing = false) const
233 { return loadGlyph(set: cacheEnabled ? &defaultGlyphSet : nullptr, glyph, subPixelPosition, format, fetchMetricsOnly, disableOutlineDrawing); }
234 Glyph *loadGlyph(QGlyphSet *set,
235 uint glyph,
236 const QFixedPoint &subPixelPosition,
237 GlyphFormat = Format_None,
238 bool fetchMetricsOnly = false,
239 bool disableOutlineDrawing = false) const;
240 Glyph *loadGlyphFor(glyph_t g,
241 const QFixedPoint &subPixelPosition,
242 GlyphFormat format,
243 const QTransform &t,
244 bool fetchBoundingBox = false,
245 bool disableOutlineDrawing = false);
246
247 QGlyphSet *loadGlyphSet(const QTransform &matrix);
248
249 QFontEngineFT(const QFontDef &fd);
250 virtual ~QFontEngineFT();
251
252 bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None,
253 const QByteArray &fontData = QByteArray());
254 bool init(FaceId faceId, bool antialias, GlyphFormat format,
255 QFreetypeFace *freetypeFace);
256
257 int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) override;
258
259 void setQtDefaultHintStyle(QFont::HintingPreference hintingPreference);
260 void setDefaultHintStyle(HintStyle style) override;
261
262 QFontEngine *cloneWithSize(qreal pixelSize) const override;
263 Qt::HANDLE handle() const override;
264 bool initFromFontEngine(const QFontEngineFT *fontEngine);
265
266 HintStyle defaultHintStyle() const { return default_hint_style; }
267
268 static QFontEngineFT *create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData = QByteArray());
269 static QFontEngineFT *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
270
271protected:
272
273 QFreetypeFace *freetype;
274 mutable int default_load_flags;
275 HintStyle default_hint_style;
276 bool antialias;
277 bool transform;
278 bool embolden;
279 bool obliquen;
280 SubpixelAntialiasingType subpixelType;
281 int lcdFilterType;
282 bool embeddedbitmap;
283 bool cacheEnabled;
284 bool forceAutoHint;
285 bool stemDarkeningDriver;
286
287private:
288 friend class QFontEngineFTRawFont;
289 friend class QFontconfigDatabase;
290 friend class QFreeTypeFontDatabase;
291 friend class QFontEngineMultiFontConfig;
292
293 int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
294 bool shouldUseDesignMetrics(ShaperFlags flags) const;
295 QFixed scaledBitmapMetrics(QFixed m) const;
296 glyph_metrics_t scaledBitmapMetrics(const glyph_metrics_t &m, const QTransform &matrix) const;
297
298 GlyphFormat defaultFormat;
299 FT_Matrix matrix;
300
301 struct TransformedGlyphSets {
302 enum { nSets = 10 };
303 QGlyphSet *sets[nSets];
304
305 QGlyphSet *findSet(const QTransform &matrix, const QFontDef &fontDef);
306 TransformedGlyphSets() { std::fill(first: &sets[0], last: &sets[nSets], value: nullptr); }
307 ~TransformedGlyphSets() { qDeleteAll(begin: &sets[0], end: &sets[nSets]); }
308 private:
309 void moveToFront(int i);
310 Q_DISABLE_COPY(TransformedGlyphSets);
311 };
312 TransformedGlyphSets transformedGlyphSets;
313 mutable QGlyphSet defaultGlyphSet;
314
315 QFontEngine::FaceId face_id;
316
317 int xsize;
318 int ysize;
319
320 QFixed line_thickness;
321 QFixed underline_position;
322
323 FT_Size_Metrics metrics;
324 mutable bool kerning_pairs_loaded;
325 QFixed scalableBitmapScaleFactor;
326};
327
328
329inline size_t qHash(const QFontEngineFT::GlyphAndSubPixelPosition &g, size_t seed = 0)
330{
331 return qHashMulti(seed,
332 args: g.glyph,
333 args: g.subPixelPosition.x.value(),
334 args: g.subPixelPosition.y.value());
335}
336
337inline QFontEngineFT::Glyph *QFontEngineFT::QGlyphSet::getGlyph(glyph_t index,
338 const QFixedPoint &subPixelPosition) const
339{
340 if (useFastGlyphData(index, subPixelPosition))
341 return fast_glyph_data[index];
342 return glyph_data.value(key: GlyphAndSubPixelPosition(index, subPixelPosition));
343}
344
345Q_GUI_EXPORT FT_Library qt_getFreetype();
346
347QT_END_NAMESPACE
348
349#endif // QT_NO_FREETYPE
350
351#endif // QFONTENGINE_FT_P_H
352

source code of qtbase/src/gui/text/freetype/qfontengine_ft_p.h