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
4#ifndef QFONTENGINE_P_H
5#define QFONTENGINE_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtGui/private/qtguiglobal_p.h>
19#include "QtCore/qatomic.h"
20#include <QtCore/qvarlengtharray.h>
21#include <QtCore/qhashfunctions.h>
22#include "private/qtextengine_p.h"
23#include "private/qfont_p.h"
24
25QT_BEGIN_NAMESPACE
26
27class QPainterPath;
28class QFontEngineGlyphCache;
29
30struct QGlyphLayout;
31
32#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
33 (((quint32)(ch1)) << 24) | \
34 (((quint32)(ch2)) << 16) | \
35 (((quint32)(ch3)) << 8) | \
36 ((quint32)(ch4)) \
37 )
38
39// ### this only used in getPointInOutline(), refactor it and then remove these magic numbers
40enum HB_Compat_Error {
41 Err_Ok = 0x0000,
42 Err_Not_Covered = 0xFFFF,
43 Err_Invalid_Argument = 0x1A66,
44 Err_Invalid_SubTable_Format = 0x157F,
45 Err_Invalid_SubTable = 0x1570
46};
47
48typedef void (*qt_destroy_func_t) (void *user_data);
49typedef bool (*qt_get_font_table_func_t) (void *user_data, uint tag, uchar *buffer, uint *length);
50
51class Q_GUI_EXPORT QFontEngine
52{
53public:
54 enum Type {
55 Box,
56 Multi,
57
58 // MS Windows types
59 Win,
60
61 // Apple Mac OS types
62 Mac,
63
64 // QWS types
65 Freetype,
66 QPF1,
67 QPF2,
68 Proxy,
69
70 DirectWrite,
71
72 TestFontEngine = 0x1000
73 };
74
75 enum GlyphFormat {
76 Format_None,
77 Format_Render = Format_None,
78 Format_Mono,
79 Format_A8,
80 Format_A32,
81 Format_ARGB
82 };
83
84 enum ShaperFlag {
85 DesignMetrics = 0x0002,
86 GlyphIndicesOnly = 0x0004
87 };
88 Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
89
90 /* Used with the Freetype font engine. */
91 struct Glyph {
92 Glyph() = default;
93 ~Glyph() { delete [] data; }
94 short linearAdvance = 0;
95 unsigned short width = 0;
96 unsigned short height = 0;
97 short x = 0;
98 short y = 0;
99 short advance = 0;
100 signed char format = 0;
101 uchar *data = nullptr;
102 private:
103 Q_DISABLE_COPY(Glyph)
104 };
105
106 virtual ~QFontEngine();
107
108 inline Type type() const { return m_type; }
109
110 // all of these are in unscaled metrics if the engine supports uncsaled metrics,
111 // otherwise in design metrics
112 struct Properties {
113 QByteArray postscriptName;
114 QByteArray copyright;
115 QRectF boundingBox;
116 QFixed emSquare;
117 QFixed ascent;
118 QFixed descent;
119 QFixed leading;
120 QFixed italicAngle;
121 QFixed capHeight;
122 QFixed lineWidth;
123 };
124 virtual Properties properties() const;
125 virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics);
126 QByteArray getSfntTable(uint tag) const;
127 virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
128
129 struct FaceId {
130 FaceId() : index(0), encoding(0) {}
131 QByteArray filename;
132 QByteArray uuid;
133 int index;
134 int encoding;
135 };
136 virtual FaceId faceId() const { return FaceId(); }
137 enum SynthesizedFlags {
138 SynthesizedItalic = 0x1,
139 SynthesizedBold = 0x2,
140 SynthesizedStretch = 0x4
141 };
142 virtual int synthesized() const { return 0; }
143 inline bool supportsSubPixelPositions() const
144 {
145 return supportsHorizontalSubPixelPositions() || supportsVerticalSubPixelPositions();
146 }
147 virtual bool supportsHorizontalSubPixelPositions() const { return false; }
148 virtual bool supportsVerticalSubPixelPositions() const { return false; }
149 virtual QFixedPoint subPixelPositionFor(const QFixedPoint &position) const;
150 QFixed subPixelPositionForX(QFixed x) const
151 {
152 return subPixelPositionFor(position: QFixedPoint(x, 0)).x;
153 }
154
155 virtual QFixed emSquareSize() const { return ascent(); }
156
157 /* returns 0 as glyph index for non existent glyphs */
158 virtual glyph_t glyphIndex(uint ucs4) const = 0;
159 virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0;
160 virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const {}
161 virtual void doKerning(QGlyphLayout *, ShaperFlags) const;
162
163 virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
164 QPainterPath *path, QTextItem::RenderFlags flags);
165
166 void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags,
167 QVarLengthArray<glyph_t> &glyphs_out, QVarLengthArray<QFixedPoint> &positions);
168
169 virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags);
170 void addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags);
171 /**
172 * Create a qimage with the alpha values for the glyph.
173 * Returns an image indexed_8 with index values ranging from 0=fully transparent to 255=opaque
174 */
175 // ### Refactor this into a smaller and more flexible API.
176 virtual QImage alphaMapForGlyph(glyph_t);
177 virtual QImage alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition);
178 virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t);
179 virtual QImage alphaMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t);
180 virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t);
181 virtual QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color = QColor());
182 virtual Glyph *glyphData(glyph_t glyph, const QFixedPoint &subPixelPosition, GlyphFormat neededFormat, const QTransform &t);
183 virtual bool hasInternalCaching() const { return false; }
184
185 virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QFixedPoint &/*subPixelPosition*/, const QTransform &matrix, GlyphFormat /*format*/)
186 {
187 return boundingBox(glyph, matrix);
188 }
189
190 virtual void removeGlyphFromCache(glyph_t);
191
192 virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs);
193 virtual glyph_metrics_t boundingBox(glyph_t glyph) = 0;
194 virtual glyph_metrics_t boundingBox(glyph_t glyph, const QTransform &matrix);
195 glyph_metrics_t tightBoundingBox(const QGlyphLayout &glyphs);
196
197 virtual QFixed ascent() const;
198 virtual QFixed capHeight() const = 0;
199 virtual QFixed descent() const;
200 virtual QFixed leading() const;
201 virtual QFixed xHeight() const;
202 virtual QFixed averageCharWidth() const;
203
204 virtual QFixed lineThickness() const;
205 virtual QFixed underlinePosition() const;
206
207 virtual qreal maxCharWidth() const = 0;
208 virtual qreal minLeftBearing() const;
209 virtual qreal minRightBearing() const;
210
211 virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = nullptr, qreal *rightBearing = nullptr);
212
213 inline bool canRender(uint ucs4) const { return glyphIndex(ucs4) != 0; }
214 virtual bool canRender(const QChar *str, int len) const;
215
216 virtual bool supportsTransformation(const QTransform &transform) const;
217
218 virtual int glyphCount() const;
219 virtual int glyphMargin(GlyphFormat format) { return format == Format_A32 ? 2 : 0; }
220
221 virtual QFontEngine *cloneWithSize(qreal /*pixelSize*/) const { return nullptr; }
222
223 virtual Qt::HANDLE handle() const;
224
225 void *harfbuzzFont() const;
226 void *harfbuzzFace() const;
227 bool supportsScript(QChar::Script script) const;
228
229 inline static bool scriptRequiresOpenType(QChar::Script script)
230 {
231 return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)
232 || script == QChar::Script_Khmer || script == QChar::Script_Nko);
233 }
234
235 virtual int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints);
236
237 void clearGlyphCache(const void *key);
238 void setGlyphCache(const void *key, QFontEngineGlyphCache *data);
239 QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, const QTransform &transform, const QColor &color = QColor()) const;
240
241 static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize);
242 static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode);
243
244 static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily);
245
246 virtual bool hasUnreliableGlyphOutline() const;
247 virtual bool expectsGammaCorrectedBlending() const;
248
249 enum HintStyle {
250 HintNone,
251 HintLight,
252 HintMedium,
253 HintFull
254 };
255 virtual void setDefaultHintStyle(HintStyle) { }
256
257 enum SubpixelAntialiasingType {
258 Subpixel_None,
259 Subpixel_RGB,
260 Subpixel_BGR,
261 Subpixel_VRGB,
262 Subpixel_VBGR
263 };
264
265private:
266 const Type m_type;
267
268public:
269 QAtomicInt ref;
270 QFontDef fontDef;
271
272 class Holder { // replace by std::unique_ptr once available
273 void *ptr;
274 qt_destroy_func_t destroy_func;
275 public:
276 Holder() : ptr(nullptr), destroy_func(nullptr) {}
277 explicit Holder(void *p, qt_destroy_func_t d) : ptr(p), destroy_func(d) {}
278 ~Holder() { if (ptr && destroy_func) destroy_func(ptr); }
279 Holder(Holder &&other) noexcept
280 : ptr(std::exchange(obj&: other.ptr, new_val: nullptr)),
281 destroy_func(std::exchange(obj&: other.destroy_func, new_val: nullptr))
282 {
283 }
284 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(Holder)
285
286 void swap(Holder &other) noexcept
287 {
288 qSwap(value1&: ptr, value2&: other.ptr);
289 qSwap(value1&: destroy_func, value2&: other.destroy_func);
290 }
291
292 void *get() const noexcept { return ptr; }
293 void *release() noexcept {
294 void *result = ptr;
295 ptr = nullptr;
296 destroy_func = nullptr;
297 return result;
298 }
299 void reset() noexcept { Holder().swap(other&: *this); }
300 qt_destroy_func_t get_deleter() const noexcept { return destroy_func; }
301
302 bool operator!() const noexcept { return !ptr; }
303 };
304
305 mutable Holder font_; // \ NOTE: Declared before m_glyphCaches, so font_, face_
306 mutable Holder face_; // / are destroyed _after_ m_glyphCaches is destroyed.
307
308 struct FaceData {
309 void *user_data;
310 qt_get_font_table_func_t get_font_table;
311 } faceData;
312
313 uint cache_cost; // amount of mem used in bytes by the font
314 uint fsType : 16;
315 bool symbol;
316 bool isSmoothlyScalable;
317 struct KernPair {
318 uint left_right;
319 QFixed adjust;
320
321 inline bool operator<(const KernPair &other) const
322 {
323 return left_right < other.left_right;
324 }
325 };
326 QList<KernPair> kerning_pairs;
327 void loadKerningPairs(QFixed scalingFactor);
328
329 GlyphFormat glyphFormat;
330 int m_subPixelPositionCount; // Number of positions within a single pixel for this cache
331
332protected:
333 explicit QFontEngine(Type type);
334
335 QFixed firstLeftBearing(const QGlyphLayout &glyphs);
336 QFixed lastRightBearing(const QGlyphLayout &glyphs);
337
338 QFixed calculatedCapHeight() const;
339
340 mutable QFixed m_ascent;
341 mutable QFixed m_descent;
342 mutable QFixed m_leading;
343 mutable bool m_heightMetricsQueried;
344
345 virtual void initializeHeightMetrics() const;
346 bool processHheaTable() const;
347 bool processOS2Table() const;
348
349private:
350 struct GlyphCacheEntry {
351 GlyphCacheEntry();
352 GlyphCacheEntry(const GlyphCacheEntry &);
353 ~GlyphCacheEntry();
354
355 GlyphCacheEntry &operator=(const GlyphCacheEntry &);
356
357 QExplicitlySharedDataPointer<QFontEngineGlyphCache> cache;
358 bool operator==(const GlyphCacheEntry &other) const { return cache == other.cache; }
359 };
360 typedef std::list<GlyphCacheEntry> GlyphCaches;
361 mutable QHash<const void *, GlyphCaches> m_glyphCaches;
362
363private:
364 mutable qreal m_minLeftBearing;
365 mutable qreal m_minRightBearing;
366};
367Q_DECLARE_TYPEINFO(QFontEngine::KernPair, Q_PRIMITIVE_TYPE);
368
369Q_DECLARE_OPERATORS_FOR_FLAGS(QFontEngine::ShaperFlags)
370
371inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId &f2)
372{
373 return f1.index == f2.index && f1.encoding == f2.encoding && f1.filename == f2.filename && f1.uuid == f2.uuid;
374}
375
376inline size_t qHash(const QFontEngine::FaceId &f, size_t seed = 0)
377 noexcept(noexcept(qHash(key: f.filename)))
378{
379 return qHashMulti(seed, args: f.filename, args: f.uuid, args: f.index, args: f.encoding);
380}
381
382
383class QGlyph;
384
385
386
387class QFontEngineBox : public QFontEngine
388{
389public:
390 QFontEngineBox(int size);
391 ~QFontEngineBox();
392
393 virtual glyph_t glyphIndex(uint ucs4) const override;
394 virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
395 virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const override;
396
397 void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si);
398 virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override;
399
400 virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
401 virtual glyph_metrics_t boundingBox(glyph_t glyph) override;
402 virtual QFontEngine *cloneWithSize(qreal pixelSize) const override;
403
404 virtual QFixed ascent() const override;
405 virtual QFixed capHeight() const override;
406 virtual QFixed descent() const override;
407 virtual QFixed leading() const override;
408 virtual qreal maxCharWidth() const override;
409 virtual qreal minLeftBearing() const override { return 0; }
410 virtual qreal minRightBearing() const override { return 0; }
411 virtual QImage alphaMapForGlyph(glyph_t) override;
412
413 virtual bool canRender(const QChar *string, int len) const override;
414
415 inline int size() const { return _size; }
416
417protected:
418 explicit QFontEngineBox(Type type, int size);
419
420private:
421 friend class QFontPrivate;
422 int _size;
423};
424
425class Q_GUI_EXPORT QFontEngineMulti : public QFontEngine
426{
427public:
428 explicit QFontEngineMulti(QFontEngine *engine, int script, const QStringList &fallbackFamilies = QStringList());
429 ~QFontEngineMulti();
430
431 virtual glyph_t glyphIndex(uint ucs4) const override;
432 virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
433
434 virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
435 virtual glyph_metrics_t boundingBox(glyph_t glyph) override;
436
437 virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const override;
438 virtual void doKerning(QGlyphLayout *, ShaperFlags) const override;
439 virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags) override;
440 virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = nullptr, qreal *rightBearing = nullptr) override;
441
442 virtual QFixed ascent() const override;
443 virtual QFixed capHeight() const override;
444 virtual QFixed descent() const override;
445 virtual QFixed leading() const override;
446 virtual QFixed xHeight() const override;
447 virtual QFixed averageCharWidth() const override;
448 virtual QImage alphaMapForGlyph(glyph_t) override;
449 virtual QImage alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition) override;
450 virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t) override;
451 virtual QImage alphaMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override;
452 virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override;
453
454 virtual QFixed lineThickness() const override;
455 virtual QFixed underlinePosition() const override;
456 virtual qreal maxCharWidth() const override;
457 virtual qreal minLeftBearing() const override;
458 virtual qreal minRightBearing() const override;
459
460 virtual bool canRender(const QChar *string, int len) const override;
461
462 inline int fallbackFamilyCount() const { return m_fallbackFamilies.size(); }
463 inline QString fallbackFamilyAt(int at) const { return m_fallbackFamilies.at(i: at); }
464
465 void setFallbackFamiliesList(const QStringList &fallbackFamilies);
466
467 static uchar highByte(glyph_t glyph); // Used for determining engine
468
469 inline QFontEngine *engine(int at) const
470 { Q_ASSERT(at < m_engines.size()); return m_engines.at(i: at); }
471
472 void ensureEngineAt(int at);
473
474 static QFontEngine *createMultiFontEngine(QFontEngine *fe, int script);
475
476protected:
477 virtual void ensureFallbackFamiliesQueried();
478 virtual bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const;
479 virtual QFontEngine *loadEngine(int at);
480
481private:
482 QList<QFontEngine *> m_engines;
483 QStringList m_fallbackFamilies;
484 const int m_script;
485 bool m_fallbackFamiliesQueried;
486};
487
488class QTestFontEngine : public QFontEngineBox
489{
490public:
491 QTestFontEngine(int size);
492};
493
494QT_END_NAMESPACE
495
496
497
498#endif // QFONTENGINE_P_H
499

source code of qtbase/src/gui/text/qfontengine_p.h