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 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | class QPainterPath; |
28 | class QFontEngineGlyphCache; |
29 | |
30 | struct 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 |
40 | enum 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 | |
48 | typedef void (*qt_destroy_func_t) (void *user_data); |
49 | typedef bool (*qt_get_font_table_func_t) (void *user_data, uint tag, uchar *buffer, uint *length); |
50 | |
51 | class Q_GUI_EXPORT QFontEngine |
52 | { |
53 | public: |
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 | |
265 | private: |
266 | const Type m_type; |
267 | |
268 | public: |
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 | |
332 | protected: |
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 | |
349 | private: |
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 | |
363 | private: |
364 | mutable qreal m_minLeftBearing; |
365 | mutable qreal m_minRightBearing; |
366 | }; |
367 | Q_DECLARE_TYPEINFO(QFontEngine::KernPair, Q_PRIMITIVE_TYPE); |
368 | |
369 | Q_DECLARE_OPERATORS_FOR_FLAGS(QFontEngine::ShaperFlags) |
370 | |
371 | inline 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 | |
376 | inline 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 | |
383 | class QGlyph; |
384 | |
385 | |
386 | |
387 | class QFontEngineBox : public QFontEngine |
388 | { |
389 | public: |
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 | |
417 | protected: |
418 | explicit QFontEngineBox(Type type, int size); |
419 | |
420 | private: |
421 | friend class QFontPrivate; |
422 | int _size; |
423 | }; |
424 | |
425 | class Q_GUI_EXPORT QFontEngineMulti : public QFontEngine |
426 | { |
427 | public: |
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 | |
476 | protected: |
477 | virtual void ensureFallbackFamiliesQueried(); |
478 | virtual bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const; |
479 | virtual QFontEngine *loadEngine(int at); |
480 | |
481 | private: |
482 | QList<QFontEngine *> m_engines; |
483 | QStringList m_fallbackFamilies; |
484 | const int m_script; |
485 | bool m_fallbackFamiliesQueried; |
486 | }; |
487 | |
488 | class QTestFontEngine : public QFontEngineBox |
489 | { |
490 | public: |
491 | QTestFontEngine(int size); |
492 | }; |
493 | |
494 | QT_END_NAMESPACE |
495 | |
496 | |
497 | |
498 | #endif // QFONTENGINE_P_H |
499 | |