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 | |
32 | QT_BEGIN_NAMESPACE |
33 | |
34 | class QFontEngineFTRawFont; |
35 | class 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 | */ |
41 | class Q_GUI_EXPORT QFreetypeFace |
42 | { |
43 | public: |
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 | |
83 | private: |
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 | |
96 | class Q_GUI_EXPORT QFontEngineFT : public QFontEngine |
97 | { |
98 | public: |
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); } |
140 | private: |
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 | |
271 | protected: |
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 | |
287 | private: |
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 | |
329 | inline 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 | |
337 | inline 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 | |
345 | Q_GUI_EXPORT FT_Library qt_getFreetype(); |
346 | |
347 | QT_END_NAMESPACE |
348 | |
349 | #endif // QT_NO_FREETYPE |
350 | |
351 | #endif // QFONTENGINE_FT_P_H |
352 | |