Coverage Report

Created: 2026-01-25 07:18

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