Coverage Report

Created: 2025-09-27 07:50

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