Coverage Report

Created: 2026-05-31 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/text/qtextdocument_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 QTEXTDOCUMENT_P_H
5
#define QTEXTDOCUMENT_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/qtextcursor.h"
20
#include "QtGui/qtextdocument.h"
21
#include "QtGui/qtextlayout.h"
22
#include "QtGui/qtextobject.h"
23
#include "QtGui/qtextoption.h"
24
25
#include "QtCore/qlist.h"
26
#include "QtCore/qmap.h"
27
#include "QtCore/qset.h"
28
#include "QtCore/qstring.h"
29
#include "QtCore/qurl.h"
30
#include "QtCore/qvariant.h"
31
32
#if QT_CONFIG(cssparser)
33
#include "private/qcssparser_p.h"
34
#endif
35
#include "private/qfragmentmap_p.h"
36
#include "private/qobject_p.h"
37
#include "private/qtextformat_p.h"
38
39
// #define QT_QMAP_DEBUG
40
41
#ifdef QT_QMAP_DEBUG
42
#include <iostream>
43
#endif
44
45
QT_BEGIN_NAMESPACE
46
47
class QTextFormatCollection;
48
class QTextFormat;
49
class QTextBlockFormat;
50
class QTextCursorPrivate;
51
class QAbstractTextDocumentLayout;
52
class QTextDocument;
53
class QTextFrame;
54
55
7.43M
#define QTextBeginningOfFrame QChar(u'\xfdd0')
56
7.43M
#define QTextEndOfFrame QChar(u'\xfdd1')
57
58
class QTextFragmentData : public QFragment<>
59
{
60
public:
61
541k
    inline void initialize() {}
62
0
    inline void invalidate() const {}
63
541k
    inline void free() {}
64
    int stringPosition;
65
    int format;
66
};
67
68
class QTextBlockData : public QFragment<3>
69
{
70
public:
71
    inline void initialize()
72
415k
        { layout = nullptr; userData = nullptr; userState = -1; revision = 0; hidden = 0; }
73
    void invalidate() const;
74
    inline void free()
75
415k
    { delete layout; layout = nullptr; delete userData; userData = nullptr; }
76
77
    mutable int format;
78
    // ##### probably store a QTextEngine * here!
79
    mutable QTextLayout *layout;
80
    mutable QTextBlockUserData *userData;
81
    mutable int userState;
82
    mutable signed int revision : 31;
83
    mutable uint hidden : 1;
84
};
85
86
87
class QAbstractUndoItem;
88
89
class QTextUndoCommand
90
{
91
public:
92
    enum Command {
93
        Inserted = 0,
94
        Removed = 1,
95
        CharFormatChanged = 2,
96
        BlockFormatChanged = 3,
97
        BlockInserted = 4,
98
        BlockRemoved = 5,
99
        BlockAdded = 6,
100
        BlockDeleted = 7,
101
        GroupFormatChange = 8,
102
        CursorMoved = 9,
103
        Custom = 256
104
    };
105
    enum Operation {
106
        KeepCursor = 0,
107
        MoveCursor = 1
108
    };
109
    quint16 command;
110
    uint block_part : 1; // all commands that are part of an undo block (including the first and the last one) have this set to 1
111
    uint block_end : 1; // the last command in an undo block has this set to 1.
112
    uint block_padding : 6; // padding since block used to be a quint8
113
    quint8 operation;
114
    int format;
115
    quint32 strPos;
116
    quint32 pos;
117
    union {
118
        int blockFormat;
119
        quint32 length;
120
        QAbstractUndoItem *custom;
121
        int objectIndex;
122
    };
123
    quint32 revision;
124
125
    bool tryMerge(const QTextUndoCommand &other);
126
};
127
Q_DECLARE_TYPEINFO(QTextUndoCommand, Q_PRIMITIVE_TYPE);
128
129
class Q_GUI_EXPORT QTextDocumentPrivate : public QObjectPrivate
130
{
131
    Q_DECLARE_PUBLIC(QTextDocument)
132
public:
133
    typedef QFragmentMap<QTextFragmentData> FragmentMap;
134
    typedef FragmentMap::ConstIterator FragmentIterator;
135
    typedef QFragmentMap<QTextBlockData> BlockMap;
136
137
    QTextDocumentPrivate();
138
    ~QTextDocumentPrivate();
139
140
    void init();
141
    void clear();
142
143
    void setLayout(QAbstractTextDocumentLayout *layout);
144
145
    void insert(int pos, QStringView text, int format);
146
    void insert(int pos, QChar c, int format)
147
0
    { insert(pos, QStringView(&c, 1), format); }
148
    void insert(int pos, int strPos, int strLength, int format);
149
    int insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
150
    int insertBlock(QChar blockSeparator, int pos, int blockFormat, int charFormat,
151
                     QTextUndoCommand::Operation op = QTextUndoCommand::MoveCursor);
152
153
    void move(int from, int to, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
154
    void remove(int pos, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
155
156
    void aboutToRemoveCell(int cursorFrom, int cursorEnd);
157
158
    QTextFrame *insertFrame(int start, int end, const QTextFrameFormat &format);
159
    void removeFrame(QTextFrame *frame);
160
161
    enum FormatChangeMode { MergeFormat, SetFormat, SetFormatAndPreserveObjectIndices };
162
163
    void setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode = SetFormat);
164
    void setBlockFormat(const QTextBlock &from, const QTextBlock &to,
165
                        const QTextBlockFormat &newFormat, FormatChangeMode mode = SetFormat);
166
167
    void emitUndoAvailable(bool available);
168
    void emitRedoAvailable(bool available);
169
170
    int undoRedo(bool undo);
171
0
    inline void undo() { undoRedo(true); }
172
0
    inline void redo() { undoRedo(false); }
173
    void appendUndoItem(QAbstractUndoItem *);
174
477k
    inline void beginEditBlock() { if (0 == editBlock++) ++revision; }
175
    void joinPreviousEditBlock();
176
    void endEditBlock();
177
    void finishEdit();
178
55.8k
    inline bool isInEditBlock() const { return editBlock; }
179
    void enableUndoRedo(bool enable);
180
0
    inline bool isUndoRedoEnabled() const { return undoEnabled; }
181
182
0
    inline bool isUndoAvailable() const { return undoEnabled && undoState > 0; }
183
0
    inline bool isRedoAvailable() const { return undoEnabled && undoState < undoStack.size(); }
184
185
0
    inline int availableUndoSteps() const { return undoEnabled ? undoState : 0; }
186
0
    inline int availableRedoSteps() const { return undoEnabled ? qMax(undoStack.size() - undoState - 1, 0) : 0; }
187
188
1.71M
    inline QString buffer() const { return text; }
189
    QString plainText() const;
190
429k
    inline int length() const { return fragments.length(); }
191
192
3.19M
    inline QTextFormatCollection *formatCollection() { return &formats; }
193
10.9M
    inline const QTextFormatCollection *formatCollection() const { return &formats; }
194
13.0M
    inline QAbstractTextDocumentLayout *layout() const { return lout; }
195
196
7.28M
    inline FragmentIterator find(int pos) const { return fragments.find(pos); }
197
0
    inline FragmentIterator begin() const { return fragments.begin(); }
198
0
    inline FragmentIterator end() const { return fragments.end(); }
199
200
0
    inline QTextBlock blocksBegin() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.firstNode()); }
201
0
    inline QTextBlock blocksEnd() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), 0); }
202
0
    inline QTextBlock blocksFind(int pos) const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.findNode(pos)); }
203
    int blockCharFormatIndex(int node) const;
204
205
0
    inline int numBlocks() const { return blocks.numNodes(); }
206
207
1.41M
    const BlockMap &blockMap() const { return blocks; }
208
0
    const FragmentMap &fragmentMap() const { return fragments; }
209
38.9M
    BlockMap &blockMap() { return blocks; }
210
0
    FragmentMap &fragmentMap() { return fragments; }
211
212
0
    static const QTextBlockData *block(const QTextBlock &it) { return it.p->blocks.fragment(it.n); }
213
214
    int nextCursorPosition(int position, QTextLayout::CursorMode mode) const;
215
    int previousCursorPosition(int position, QTextLayout::CursorMode mode) const;
216
    int leftCursorPosition(int position) const;
217
    int rightCursorPosition(int position) const;
218
219
    void changeObjectFormat(QTextObject *group, int format);
220
221
    void setModified(bool m);
222
0
    inline bool isModified() const { return modified; }
223
224
0
    inline QFont defaultFont() const { return formats.defaultFont(); }
225
18.6k
    inline void setDefaultFont(const QFont &f) { formats.setDefaultFont(f); }
226
227
    void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals = false);
228
229
private:
230
    bool split(int pos);
231
    bool unite(uint f);
232
233
    void insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op);
234
    int insert_block(int pos, uint strPos, int format, int blockformat, QTextUndoCommand::Operation op, int command);
235
    int remove_string(int pos, uint length, QTextUndoCommand::Operation op);
236
    int remove_block(int pos, int *blockformat, int command, QTextUndoCommand::Operation op);
237
238
    void insert_frame(QTextFrame *f);
239
    void scan_frames(int pos, int charsRemoved, int charsAdded);
240
    static void clearFrame(QTextFrame *f);
241
242
    void adjustDocumentChangesAndCursors(int from, int addedOrRemoved, QTextUndoCommand::Operation op);
243
244
    bool wasUndoAvailable;
245
    bool wasRedoAvailable;
246
247
public:
248
    void documentChange(int from, int length);
249
250
    void addCursor(QTextCursorPrivate *c);
251
    void removeCursor(QTextCursorPrivate *c);
252
253
    QTextFrame *frameAt(int pos) const;
254
    QTextFrame *rootFrame() const;
255
256
    QTextObject *objectForIndex(int objectIndex) const;
257
    QTextObject *objectForFormat(int formatIndex) const;
258
    QTextObject *objectForFormat(const QTextFormat &f) const;
259
260
    QTextObject *createObject(const QTextFormat &newFormat, int objectIndex = -1);
261
    void deleteObject(QTextObject *object);
262
263
55.7k
    QTextDocument *document() { return q_func(); }
264
187k
    const QTextDocument *document() const { return q_func(); }
265
266
    bool ensureMaximumBlockCount();
267
268
    static inline const QTextDocumentPrivate *get(const QTextDocument *document)
269
0
    {
270
0
        return document->d_func();
271
0
    }
272
273
    static inline QTextDocumentPrivate *get(QTextDocument *document)
274
4.79M
    {
275
4.79M
        return document->d_func();
276
4.79M
    }
277
278
    static inline QTextDocumentPrivate *get(QTextBlock &block)
279
3.12M
    {
280
3.12M
        return block.p;
281
3.12M
    }
282
283
    static inline const QTextDocumentPrivate *get(const QTextBlock &block)
284
51.4M
    {
285
51.4M
        return block.p;
286
51.4M
    }
287
288
    static inline QTextDocumentPrivate *get(QTextObject *object)
289
4.64M
    {
290
4.64M
        return get(object->document());
291
4.64M
    }
292
293
    static inline const QTextDocumentPrivate *get(const QTextObject *object)
294
55.8k
    {
295
55.8k
        return get(object->document());
296
55.8k
    }
297
298
37.2k
    bool canLayout() const { return layoutEnabled && !pageSize.isNull(); }
299
300
private:
301
    QTextDocumentPrivate(const QTextDocumentPrivate& m);
302
    QTextDocumentPrivate& operator= (const QTextDocumentPrivate& m);
303
304
    void appendUndoItem(const QTextUndoCommand &c);
305
306
    void contentsChanged();
307
308
    void compressPieceTable();
309
310
    QString text;
311
    uint unreachableCharacterCount;
312
313
    QList<QTextUndoCommand> undoStack;
314
    bool undoEnabled;
315
    int undoState;
316
    int revision;
317
    // position in undo stack of the last setModified(false) call
318
    int modifiedState;
319
    bool modified;
320
321
    int editBlock;
322
    int editBlockCursorPosition;
323
    int docChangeFrom;
324
    int docChangeOldLength;
325
    int docChangeLength;
326
    bool framesDirty;
327
328
    QTextFormatCollection formats;
329
    mutable QTextFrame *rtFrame;
330
    QAbstractTextDocumentLayout *lout;
331
    FragmentMap fragments;
332
    BlockMap blocks;
333
    int initialBlockCharFormatIndex;
334
335
    QSet<QTextCursorPrivate *> cursors;
336
    QMap<int, QTextObject *> objects;
337
    QMap<QUrl, QVariant> resources;
338
    QMap<QUrl, QVariant> cachedResources;
339
    QTextDocument::ResourceProvider resourceProvider;
340
    QString defaultStyleSheet;
341
342
    int lastBlockCount;
343
344
public:
345
    bool inContentsChange;
346
    bool layoutEnabled = true;
347
    QTextOption defaultTextOption;
348
    Qt::CursorMoveStyle defaultCursorMoveStyle;
349
#ifndef QT_NO_CSSPARSER
350
    QCss::StyleSheet parsedDefaultStyleSheet;
351
#endif
352
    int maximumBlockCount;
353
    uint needsEnsureMaximumBlockCount : 1;
354
    uint blockCursorAdjustment : 1;
355
    QSizeF pageSize;
356
    QString title;
357
    QString url;
358
    QString cssMedia;
359
    QString frontMatter;
360
    qreal indentWidth;
361
    qreal documentMargin;
362
    QUrl baseUrl;
363
364
    void mergeCachedResources(const QTextDocumentPrivate *priv);
365
366
    friend struct QTextHtmlParserNode;
367
    friend class QTextHtmlExporter;
368
    friend class QTextCursor;
369
};
370
371
class QTextTable;
372
class QTextHtmlExporter
373
{
374
public:
375
    QTextHtmlExporter(const QTextDocument *_doc);
376
377
    enum ExportMode {
378
        ExportEntireDocument,
379
        ExportFragment
380
    };
381
382
    QString toHtml(ExportMode mode = ExportEntireDocument);
383
384
private:
385
    enum StyleMode { EmitStyleTag, OmitStyleTag };
386
    enum FrameType { TextFrame, TableFrame, RootFrame };
387
388
    void emitFrame(const QTextFrame::Iterator &frameIt);
389
    void emitTextFrame(const QTextFrame *frame);
390
    void emitBlock(const QTextBlock &block);
391
    void emitTable(const QTextTable *table);
392
    void emitFragment(const QTextFragment &fragment);
393
394
    void emitBlockAttributes(const QTextBlock &block);
395
    bool emitCharFormatStyle(const QTextCharFormat &format);
396
    void emitTextLength(const char *attribute, const QTextLength &length);
397
    void emitAlignment(Qt::Alignment alignment);
398
    void emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode = EmitStyleTag);
399
    void emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right);
400
    void emitAttribute(const char *attribute, const QString &value);
401
    void emitFrameStyle(const QTextFrameFormat &format, FrameType frameType);
402
    void emitBorderStyle(QTextFrameFormat::BorderStyle style);
403
    void emitPageBreakPolicy(QTextFormat::PageBreakFlags policy);
404
405
    void emitFontFamily(const QStringList &families);
406
407
    void emitBackgroundAttribute(const QTextFormat &format);
408
    QString findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap);
409
410
    QString html;
411
    QTextCharFormat defaultCharFormat;
412
    const QTextDocument *doc;
413
    bool fragmentMarkers;
414
    QStringList closingTags;
415
};
416
417
QT_END_NAMESPACE
418
419
#endif // QTEXTDOCUMENT_P_H