Coverage Report

Created: 2026-09-14 07:15

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