Coverage Report

Created: 2026-10-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/text/qtextengine_p.h
Line
Count
Source
1
// Copyright (C) 2016 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 QTEXTENGINE_P_H
5
#define QTEXTENGINE_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 for the convenience
12
// of other Qt classes.  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/qpaintengine.h"
20
#include "QtGui/qtextcursor.h"
21
#include "QtGui/qtextobject.h"
22
#include "QtGui/qtextoption.h"
23
#include "QtGui/qtextlayout.h"
24
25
#include "QtCore/qlist.h"
26
#include "QtCore/qnamespace.h"
27
#include "QtCore/qset.h"
28
#include <QtCore/qspan.h>
29
#include "QtCore/qstring.h"
30
#include "QtCore/qvarlengtharray.h"
31
32
#include "private/qfixed_p.h"
33
#include "private/qfont_p.h"
34
#include "private/qtextformat_p.h"
35
#include "private/qunicodetools_p.h"
36
#ifndef QT_BUILD_COMPAT_LIB
37
#include "private/qtextdocument_p.h"
38
#endif
39
40
#include <stdlib.h>
41
#include <vector>
42
43
QT_BEGIN_NAMESPACE
44
45
class QFontPrivate;
46
class QFontEngine;
47
48
class QString;
49
class QPainter;
50
51
class QAbstractTextDocumentLayout;
52
53
typedef quint32 glyph_t;
54
55
// this uses the same coordinate system as Qt, but a different one to freetype.
56
// * y is usually negative, and is equal to the ascent.
57
// * negative yoff means the following stuff is drawn higher up.
58
// the characters bounding rect is given by QRect(x,y,width,height), its advance by
59
// xoo and yoff
60
struct Q_GUI_EXPORT glyph_metrics_t
61
{
62
    inline glyph_metrics_t()
63
0
        : x(100000),  y(100000) {}
64
    inline glyph_metrics_t(QFixed _x, QFixed _y, QFixed _width, QFixed _height, QFixed _xoff, QFixed _yoff)
65
0
        : x(_x),
66
0
          y(_y),
67
0
          width(_width),
68
0
          height(_height),
69
0
          xoff(_xoff),
70
0
          yoff(_yoff)
71
0
        {}
72
    QFixed x;
73
    QFixed y;
74
    QFixed width;
75
    QFixed height;
76
    QFixed xoff;
77
    QFixed yoff;
78
79
    glyph_metrics_t transformed(const QTransform &xform) const;
80
0
    inline bool isValid() const {return x != 100000 && y != 100000;}
81
82
    inline QFixed leftBearing() const
83
0
    {
84
0
        if (!isValid())
85
0
            return QFixed();
86
87
0
        return x;
88
0
    }
89
90
    inline QFixed rightBearing() const
91
0
    {
92
0
        if (!isValid())
93
0
            return QFixed();
94
95
0
        return xoff - x - width;
96
0
    }
97
};
98
Q_DECLARE_TYPEINFO(glyph_metrics_t, Q_PRIMITIVE_TYPE);
99
100
struct Q_AUTOTEST_EXPORT QScriptAnalysis
101
{
102
    enum Flags {
103
        None = 0,
104
        Lowercase = 1,
105
        Uppercase = 2,
106
        SmallCaps = 3,
107
        LineOrParagraphSeparator = 4,
108
        Space = 5,
109
        SpaceTabOrObject = Space,
110
        Nbsp = 6,
111
        Tab = 7,
112
        TabOrObject = Tab,
113
        Object = 8
114
    };
115
    enum BidiFlags {
116
        BidiBN = 1,
117
        BidiMaybeResetToParagraphLevel = 2,
118
        BidiResetToParagraphLevel = 4,
119
        BidiMirrored = 8
120
    };
121
    unsigned short script    : 8;
122
    unsigned short flags     : 4;
123
    unsigned short bidiFlags : 4;
124
    unsigned short bidiLevel : 8;  // Unicode Bidi algorithm embedding level (0-125)
125
    QChar::Direction bidiDirection : 8; // used when running the bidi algorithm
126
0
    inline bool operator == (const QScriptAnalysis &other) const {
127
0
        return script == other.script && bidiLevel == other.bidiLevel && flags == other.flags;
128
0
    }
129
};
130
Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE);
131
132
struct QGlyphJustification
133
{
134
    inline QGlyphJustification()
135
        : type(0), nKashidas(0), space_18d6(0)
136
0
    {}
137
138
    enum JustificationType {
139
        JustifyNone,
140
        JustifySpace,
141
        JustifyKashida
142
    };
143
144
    uint type :2;
145
    uint nKashidas : 6; // more do not make sense...
146
    uint space_18d6 : 24;
147
};
148
Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE);
149
150
struct QGlyphAttributes {
151
    uchar clusterStart  : 1;
152
    uchar dontPrint     : 1;
153
    uchar justification : 4;
154
    uchar reserved      : 2;
155
};
156
static_assert(sizeof(QGlyphAttributes) == 1);
157
Q_DECLARE_TYPEINFO(QGlyphAttributes, Q_PRIMITIVE_TYPE);
158
159
struct QGlyphLayout
160
{
161
    static constexpr qsizetype SpaceNeeded = sizeof(glyph_t) + sizeof(QFixed) + sizeof(QFixedPoint)
162
            + sizeof(QGlyphAttributes) + sizeof(QGlyphJustification);
163
164
    // init to 0 not needed, done when shaping
165
    QFixedPoint *offsets; // 8 bytes per element
166
    glyph_t *glyphs; // 4 bytes per element
167
    QFixed *advances; // 4 bytes per element
168
    QGlyphJustification *justifications; // 4 bytes per element
169
    QGlyphAttributes *attributes; // 1 byte per element
170
171
    int numGlyphs;
172
173
0
    inline QGlyphLayout() : numGlyphs(0) {}
174
175
    inline explicit QGlyphLayout(char *address, int totalGlyphs)
176
0
    {
177
0
        offsets = reinterpret_cast<QFixedPoint *>(address);
178
0
        qsizetype offset = totalGlyphs * sizeof(QFixedPoint);
179
0
        glyphs = reinterpret_cast<glyph_t *>(address + offset);
180
0
        offset += totalGlyphs * sizeof(glyph_t);
181
0
        advances = reinterpret_cast<QFixed *>(address + offset);
182
0
        offset += totalGlyphs * sizeof(QFixed);
183
0
        justifications = reinterpret_cast<QGlyphJustification *>(address + offset);
184
0
        offset += totalGlyphs * sizeof(QGlyphJustification);
185
0
        attributes = reinterpret_cast<QGlyphAttributes *>(address + offset);
186
0
        numGlyphs = totalGlyphs;
187
0
    }
188
189
0
    inline QGlyphLayout mid(int position, int n = -1) const {
190
0
        QGlyphLayout copy = *this;
191
0
        copy.glyphs += position;
192
0
        copy.advances += position;
193
0
        copy.offsets += position;
194
0
        copy.justifications += position;
195
0
        copy.attributes += position;
196
0
        if (n == -1)
197
0
            copy.numGlyphs -= position;
198
0
        else
199
0
            copy.numGlyphs = n;
200
0
        return copy;
201
0
    }
202
203
    inline QFixed effectiveAdvance(int item) const
204
0
    { return (advances[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; }
205
206
0
    inline void clear(int first = 0, int last = -1) {
207
0
        if (last == -1)
208
0
            last = numGlyphs;
209
0
        if (first == 0 && last == numGlyphs
210
0
            && reinterpret_cast<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) {
211
0
            memset(static_cast<void *>(offsets), 0, qsizetype(numGlyphs) * SpaceNeeded);
212
0
        } else {
213
0
            const int num = last - first;
214
0
            memset(static_cast<void *>(offsets + first), 0, num * sizeof(QFixedPoint));
215
0
            memset(glyphs + first, 0, num * sizeof(glyph_t));
216
0
            memset(static_cast<void *>(advances + first), 0, num * sizeof(QFixed));
217
0
            memset(static_cast<void *>(justifications + first), 0, num * sizeof(QGlyphJustification));
218
0
            memset(attributes + first, 0, num * sizeof(QGlyphAttributes));
219
0
        }
220
0
    }
221
222
0
    inline char *data() {
223
0
        return reinterpret_cast<char *>(offsets);
224
0
    }
225
226
    void copy(QGlyphLayout *other);
227
    void grow(char *address, int totalGlyphs);
228
};
229
230
class QVarLengthGlyphLayoutArray : private QVarLengthArray<void *>, public QGlyphLayout
231
{
232
private:
233
    typedef QVarLengthArray<void *> Array;
234
public:
235
    QVarLengthGlyphLayoutArray(int totalGlyphs)
236
0
        : Array((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1)
237
0
        , QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs)
238
0
    {
239
0
        memset(Array::data(), 0, Array::size() * sizeof(void *));
240
0
    }
241
242
    void resize(int totalGlyphs)
243
0
    {
244
0
        Array::resize((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1);
245
0
246
0
        *((QGlyphLayout *)this) = QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs);
247
0
        memset(Array::data(), 0, Array::size() * sizeof(void *));
248
0
    }
249
};
250
251
template <int N> struct QGlyphLayoutArray : public QGlyphLayout
252
{
253
public:
254
    QGlyphLayoutArray()
255
        : QGlyphLayout(reinterpret_cast<char *>(buffer), N)
256
    {
257
        memset(buffer, 0, sizeof(buffer));
258
    }
259
260
private:
261
    void *buffer[(N * SpaceNeeded) / sizeof(void *) + 1];
262
};
263
264
struct QScriptItem;
265
/// Internal QTextItem
266
class QTextItemInt : public QTextItem
267
{
268
public:
269
0
    inline QTextItemInt() = default;
270
    QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat());
271
    QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars, int numChars, QFontEngine *fe,
272
                 const QTextCharFormat &format = QTextCharFormat());
273
274
    /// copy the structure items, adjusting the glyphs arrays to the right subarrays.
275
    /// the width of the returned QTextItemInt is not adjusted, for speed reasons
276
    QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const;
277
    void initWithScriptItem(const QScriptItem &si);
278
279
    QFixed descent;
280
    QFixed ascent;
281
    QFixed width;
282
283
    RenderFlags flags;
284
    bool justified = false;
285
    QTextCharFormat::UnderlineStyle underlineStyle = QTextCharFormat::NoUnderline;
286
    const QTextCharFormat charFormat;
287
    int num_chars = 0;
288
    const QChar *chars = nullptr;
289
    const unsigned short *logClusters = nullptr;
290
    const QFont *f = nullptr;
291
292
    QGlyphLayout glyphs;
293
    QFontEngine *fontEngine = nullptr;
294
};
295
296
struct QScriptItem
297
{
298
    constexpr QScriptItem(int p, QScriptAnalysis a) noexcept
299
0
        : position(p), analysis(a),
300
0
          num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1),
301
0
          glyph_data_offset(0) {}
302
303
    int position;
304
    QScriptAnalysis analysis;
305
    unsigned short num_glyphs;
306
    QFixed descent;
307
    QFixed ascent;
308
    QFixed leading;
309
    QFixed width;
310
    int glyph_data_offset;
311
0
    constexpr QFixed height() const noexcept { return ascent + descent; }
312
private:
313
    friend class QList<QScriptItem>;
314
0
    QScriptItem() {} // for QList, don't use
315
};
316
Q_DECLARE_TYPEINFO(QScriptItem, Q_PRIMITIVE_TYPE);
317
318
typedef QList<QScriptItem> QScriptItemArray;
319
320
struct Q_AUTOTEST_EXPORT QScriptLine
321
{
322
    // created and filled in QTextLine::layout_helper
323
    QScriptLine()
324
0
        : from(0), trailingSpaces(0), length(0),
325
0
        justified(0), gridfitted(0),
326
0
        hasTrailingSpaces(0), leadingIncluded(0) {}
327
    QFixed descent;
328
    QFixed ascent;
329
    QFixed leading;
330
    QFixed x;
331
    QFixed y;
332
    QFixed width;
333
    QFixed textWidth;
334
    QFixed textAdvance;
335
    int from;
336
    unsigned short trailingSpaces;
337
    signed int length : 28;
338
    mutable uint justified : 1;
339
    mutable uint gridfitted : 1;
340
    uint hasTrailingSpaces : 1;
341
    uint leadingIncluded : 1;
342
0
    QFixed height() const { return ascent + descent
343
0
                            + (leadingIncluded?  qMax(QFixed(),leading) : QFixed()); }
344
0
    QFixed base() const { return ascent; }
345
    void setDefaultHeight(QTextEngine *eng);
346
    void operator+=(const QScriptLine &other);
347
};
348
Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE);
349
350
351
inline void QScriptLine::operator+=(const QScriptLine &other)
352
0
{
353
0
    leading= qMax(leading + ascent, other.leading + other.ascent) - qMax(ascent, other.ascent);
354
0
    descent = qMax(descent, other.descent);
355
0
    ascent = qMax(ascent, other.ascent);
356
0
    textWidth += other.textWidth;
357
0
    length += other.length;
358
0
}
359
360
typedef QList<QScriptLine> QScriptLineArray;
361
362
class QFontPrivate;
363
class QTextFormatCollection;
364
365
class Q_GUI_EXPORT QTextEngine {
366
public:
367
    enum LayoutState {
368
        LayoutEmpty,
369
        InLayout,
370
        LayoutFailed
371
    };
372
    struct Q_GUI_EXPORT LayoutData {
373
        LayoutData(const QString &str, void **stack_memory, qsizetype mem_size);
374
        LayoutData();
375
        ~LayoutData();
376
        mutable QScriptItemArray items;
377
        qsizetype allocated;
378
        qsizetype available_glyphs;
379
        void **memory;
380
        unsigned short *logClustersPtr;
381
        QGlyphLayout glyphLayout;
382
        mutable int used;
383
        uint hasBidi : 1;
384
        uint layoutState : 2;
385
        uint memory_on_stack : 1;
386
        uint haveCharAttributes : 1;
387
        QFixed currentMaxWidth;
388
        QString string;
389
        bool reallocate(int totalGlyphs);
390
    };
391
392
    struct ItemDecoration {
393
0
        ItemDecoration() { } // for QList, don't use
394
        ItemDecoration(qreal x1, qreal x2, qreal y, const QPen &pen):
395
0
            x1(x1), x2(x2), y(y), pen(pen) {}
396
397
        qreal x1;
398
        qreal x2;
399
        qreal y;
400
        QPen pen;
401
    };
402
403
    typedef QList<ItemDecoration> ItemDecorationList;
404
405
    QTextEngine();
406
    QTextEngine(const QString &str, const QFont &f);
407
    ~QTextEngine();
408
409
    enum Mode {
410
        WidthOnly = 0x07
411
    };
412
413
    void invalidate();
414
    void clearLineData();
415
416
    void validate() const;
417
    void itemize() const;
418
419
    bool isRightToLeft() const;
420
    static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
421
422
    const QCharAttributes *attributes() const;
423
424
    void shape(int item) const;
425
426
    void justify(const QScriptLine &si);
427
    QFixed alignLine(const QScriptLine &line);
428
429
    QFixed width(int charFrom, int numChars) const;
430
    glyph_metrics_t boundingBox(int from,  int len) const;
431
    glyph_metrics_t tightBoundingBox(int from,  int len) const;
432
433
0
    int length(int item) const {
434
0
        const QScriptItem &si = layoutData->items[item];
435
0
        int from = si.position;
436
0
        item++;
437
0
        return (item < layoutData->items.size() ? layoutData->items[item].position : layoutData->string.size()) - from;
438
0
    }
439
0
    int length(const QScriptItem *si) const {
440
0
        int end;
441
0
        if (si + 1 < layoutData->items.constData()+ layoutData->items.size())
442
0
            end = (si+1)->position;
443
0
        else
444
0
            end = layoutData->string.size();
445
0
        return end - si->position;
446
0
    }
447
448
    QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = nullptr, QFixed *descent = nullptr, QFixed *leading = nullptr) const;
449
    QFont font(const QScriptItem &si) const;
450
0
    inline QFont font() const { return fnt; }
451
452
    /**
453
     * Returns a pointer to an array of log clusters, offset at the script item.
454
     * Each item in the array is a unsigned short.  For each character in the original string there is an entry in the table
455
     * so there is a one to one correlation in indexes between the original text and the index in the logcluster.
456
     * The value of each item is the position in the glyphs array. Multiple similar pointers in the logclusters array imply
457
     * that one glyph is used for more than one character.
458
     * \sa glyphs()
459
     */
460
    inline unsigned short *logClusters(const QScriptItem *si) const
461
0
        { return layoutData->logClustersPtr+si->position; }
462
    /**
463
     * Returns an array of QGlyphLayout items, offset at the script item.
464
     * Each item in the array matches one glyph in the text, storing the advance, position etc.
465
     * The returned item's length equals to the number of available glyphs. This may be more
466
     * than what was actually shaped.
467
     * \sa logClusters()
468
     */
469
0
    inline QGlyphLayout availableGlyphs(const QScriptItem *si) const {
470
0
        return layoutData->glyphLayout.mid(si->glyph_data_offset);
471
0
    }
472
    /**
473
     * Returns an array of QGlyphLayout items, offset at the script item.
474
     * Each item in the array matches one glyph in the text, storing the advance, position etc.
475
     * The returned item's length equals to the number of shaped glyphs.
476
     * \sa logClusters()
477
     */
478
0
    inline QGlyphLayout shapedGlyphs(const QScriptItem *si) const {
479
0
        return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs);
480
0
    }
481
482
0
    inline bool ensureSpace(int nGlyphs) const {
483
0
        if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
484
0
            return layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
485
0
        return true;
486
0
    }
487
488
    void freeMemory();
489
490
    int findItem(int strPos, int firstItem = 0) const;
491
0
    inline QTextFormatCollection *formatCollection() const {
492
0
        if (QTextDocumentPrivate::get(block) != nullptr)
493
0
            return const_cast<QTextFormatCollection *>(QTextDocumentPrivate::get(block)->formatCollection());
494
0
        return specialData ? specialData->formatCollection.data() : nullptr;
495
0
    }
496
    QTextCharFormat format(const QScriptItem *si) const;
497
0
    inline QAbstractTextDocumentLayout *docLayout() const {
498
0
        Q_ASSERT(QTextDocumentPrivate::get(block) != nullptr);
499
0
        return QTextDocumentPrivate::get(block)->document()->documentLayout();
500
0
    }
501
    int formatIndex(const QScriptItem *si) const;
502
503
    /// returns the width of tab at index (in the tabs array) with the tab-start at position x
504
    QFixed calculateTabWidth(int index, QFixed x) const;
505
506
    mutable QScriptLineArray lines;
507
508
private:
509
    struct FontEngineCache {
510
        FontEngineCache();
511
        mutable QFontEngine *prevFontEngine;
512
        mutable QFontEngine *prevScaledFontEngine;
513
        mutable int prevScript;
514
        mutable int prevPosition;
515
        mutable int prevLength;
516
0
        inline void reset() {
517
0
            prevFontEngine = nullptr;
518
0
            prevScaledFontEngine = nullptr;
519
0
            prevScript = -1;
520
0
            prevPosition = -1;
521
0
            prevLength = -1;
522
0
        }
523
    };
524
    mutable FontEngineCache feCache;
525
526
public:
527
    QString text;
528
    mutable QFont fnt;
529
#ifndef QT_NO_RAWFONT
530
    QRawFont rawFont;
531
#endif
532
    QTextBlock block;
533
534
    QTextOption option;
535
536
    QFixed minWidth;
537
    QFixed maxWidth;
538
    QPointF position;
539
    uint ignoreBidi : 1;
540
    uint cacheGlyphs : 1;
541
    uint stackEngine : 1;
542
    uint forceJustification : 1;
543
    uint visualMovement : 1;
544
    uint delayDecorations: 1;
545
#ifndef QT_NO_RAWFONT
546
    uint useRawFont : 1;
547
#endif
548
549
    mutable LayoutData *layoutData;
550
551
    ItemDecorationList underlineList;
552
    ItemDecorationList strikeOutList;
553
    ItemDecorationList overlineList;
554
555
    inline bool visualCursorMovement() const
556
0
    { return visualMovement || (QTextDocumentPrivate::get(block) != nullptr && QTextDocumentPrivate::get(block)->defaultCursorMoveStyle == Qt::VisualMoveStyle); }
557
558
0
    inline int preeditAreaPosition() const { return specialData ? specialData->preeditPosition : -1; }
559
0
    inline QString preeditAreaText() const { return specialData ? specialData->preeditText : QString(); }
560
    void setPreeditArea(int position, const QString &text);
561
562
    inline bool hasFormats() const
563
0
    { return QTextDocumentPrivate::get(block) != nullptr || (specialData && !specialData->formats.isEmpty()); }
564
    inline QList<QTextLayout::FormatRange> formats() const
565
0
    {
566
0
        return specialData ? specialData->formats : QList<QTextLayout::FormatRange>();
567
0
    }
568
    void setFormats(const QList<QTextLayout::FormatRange> &formats);
569
570
private:
571
    static void init(QTextEngine *e);
572
573
    struct SpecialData {
574
        int preeditPosition;
575
        QString preeditText;
576
        QList<QTextLayout::FormatRange> formats;
577
        QList<QTextCharFormat> resolvedFormats;
578
        // only used when no QTextDocumentPrivate is available
579
        QScopedPointer<QTextFormatCollection> formatCollection;
580
    };
581
    SpecialData *specialData;
582
583
    void indexFormats();
584
    void resolveFormats() const;
585
586
public:
587
    bool atWordSeparator(int position) const;
588
589
    QString elidedText(Qt::TextElideMode mode, QFixed width, int flags = 0, int from = 0, int count = -1) const;
590
591
    void shapeLine(const QScriptLine &line);
592
    QFixed leadingSpaceWidth(const QScriptLine &line);
593
594
    QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos);
595
    int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter);
596
    int previousLogicalPosition(int oldPos) const;
597
    int nextLogicalPosition(int oldPos) const;
598
    int lineNumberForTextPosition(int pos);
599
    int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op);
600
    std::vector<int> insertionPointsForLine(int lineNum);
601
    void resetFontEngineCache();
602
603
0
    void enableDelayDecorations(bool enable = true) { delayDecorations = enable; }
604
605
    void addUnderline(QPainter *painter, const QLineF &line);
606
    void addStrikeOut(QPainter *painter, const QLineF &line);
607
    void addOverline(QPainter *painter, const QLineF &line);
608
609
    void drawDecorations(QPainter *painter);
610
    void clearDecorations();
611
    void adjustUnderlines();
612
613
private:
614
    void addItemDecoration(QPainter *painter, const QLineF &line, ItemDecorationList *decorationList);
615
    void adjustUnderlines(ItemDecorationList::iterator start,
616
                          ItemDecorationList::iterator end,
617
                          qreal underlinePos, qreal penWidth);
618
    void drawItemDecorationList(QPainter *painter, const ItemDecorationList &decorationList);
619
    void setBoundary(int strPos) const;
620
    void addRequiredBoundaries() const;
621
    void shapeText(int item) const;
622
#if QT_CONFIG(harfbuzz)
623
    int shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *string, int stringBaseIndex,
624
                                int stringLength, int itemLength, QFontEngine *fontEngine,
625
                                QSpan<uint> itemBoundaries, bool kerningEnabled,
626
                                bool hasLetterSpacing,
627
                                const QMap<QFont::Tag, quint32> &features) const;
628
#endif
629
630
    int endOfLine(int lineNum);
631
    int beginningOfLine(int lineNum);
632
    int getClusterLength(unsigned short *logClusters, const QCharAttributes *attributes, int from, int to, int glyph_pos, int *start);
633
};
634
635
class Q_GUI_EXPORT QStackTextEngine : public QTextEngine {
636
public:
637
    enum { MemSize = 256*40/sizeof(void *) };
638
    QStackTextEngine(const QString &string, const QFont &f);
639
    LayoutData _layoutData;
640
    void *_memory[MemSize];
641
};
642
Q_DECLARE_TYPEINFO(QTextEngine::ItemDecoration, Q_RELOCATABLE_TYPE);
643
644
struct QTextLineItemIterator
645
{
646
    QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(),
647
                          const QTextLayout::FormatRange *_selection = nullptr);
648
649
0
    inline bool atEnd() const { return logicalItem >= nItems - 1; }
650
0
    inline bool atBeginning() const { return logicalItem <= 0; }
651
    QScriptItem &next();
652
653
    bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const;
654
0
    inline bool isOutsideSelection() const {
655
0
        QFixed tmp1, tmp2;
656
0
        return !getSelectionBounds(&tmp1, &tmp2);
657
0
    }
658
659
    QTextEngine *eng;
660
661
    QFixed x;
662
    const QScriptLine &line;
663
    QScriptItem *si;
664
665
    const int lineNum;
666
    const int lineEnd;
667
    const int firstItem;
668
    const int lastItem;
669
    const int nItems;
670
    int logicalItem;
671
    int item;
672
    int itemLength;
673
674
    int glyphsStart;
675
    int glyphsEnd;
676
    int itemStart;
677
    int itemEnd;
678
679
    QFixed itemWidth;
680
681
    QVarLengthArray<int> visualOrder;
682
683
    const QTextLayout::FormatRange *selection;
684
};
685
686
QT_END_NAMESPACE
687
688
#endif // QTEXTENGINE_P_H