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
45QT_BEGIN_NAMESPACE
46
47class QTextFormatCollection;
48class QTextFormat;
49class QTextBlockFormat;
50class QTextCursorPrivate;
51class QAbstractTextDocumentLayout;
52class QTextDocument;
53class QTextFrame;
54
55#define QTextBeginningOfFrame QChar(u'\xfdd0')
56#define QTextEndOfFrame QChar(u'\xfdd1')
57
58class QTextFragmentData : public QFragment<>
59{
60public:
61 inline void initialize() {}
62 inline void invalidate() const {}
63 inline void free() {}
64 int stringPosition;
65 int format;
66};
67
68class QTextBlockData : public QFragment<3>
69{
70public:
71 inline void initialize()
72 { layout = nullptr; userData = nullptr; userState = -1; revision = 0; hidden = 0; }
73 void invalidate() const;
74 inline void free()
75 { 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
87class QAbstractUndoItem;
88
89class QTextUndoCommand
90{
91public:
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};
127Q_DECLARE_TYPEINFO(QTextUndoCommand, Q_PRIMITIVE_TYPE);
128
129class Q_GUI_EXPORT QTextDocumentPrivate : public QObjectPrivate
130{
131 Q_DECLARE_PUBLIC(QTextDocument)
132public:
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, const QString &text, int format);
146 void insert(int pos, int strPos, int strLength, int format);
147 int insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
148 int insertBlock(QChar blockSeparator, int pos, int blockFormat, int charFormat,
149 QTextUndoCommand::Operation op = QTextUndoCommand::MoveCursor);
150
151 void move(int from, int to, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
152 void remove(int pos, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
153
154 void aboutToRemoveCell(int cursorFrom, int cursorEnd);
155
156 QTextFrame *insertFrame(int start, int end, const QTextFrameFormat &format);
157 void removeFrame(QTextFrame *frame);
158
159 enum FormatChangeMode { MergeFormat, SetFormat, SetFormatAndPreserveObjectIndices };
160
161 void setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode = SetFormat);
162 void setBlockFormat(const QTextBlock &from, const QTextBlock &to,
163 const QTextBlockFormat &newFormat, FormatChangeMode mode = SetFormat);
164
165 void emitUndoAvailable(bool available);
166 void emitRedoAvailable(bool available);
167
168 int undoRedo(bool undo);
169 inline void undo() { undoRedo(undo: true); }
170 inline void redo() { undoRedo(undo: false); }
171 void appendUndoItem(QAbstractUndoItem *);
172 inline void beginEditBlock() { if (0 == editBlock++) ++revision; }
173 void joinPreviousEditBlock();
174 void endEditBlock();
175 void finishEdit();
176 inline bool isInEditBlock() const { return editBlock; }
177 void enableUndoRedo(bool enable);
178 inline bool isUndoRedoEnabled() const { return undoEnabled; }
179
180 inline bool isUndoAvailable() const { return undoEnabled && undoState > 0; }
181 inline bool isRedoAvailable() const { return undoEnabled && undoState < undoStack.size(); }
182
183 inline int availableUndoSteps() const { return undoEnabled ? undoState : 0; }
184 inline int availableRedoSteps() const { return undoEnabled ? qMax(a: undoStack.size() - undoState - 1, b: 0) : 0; }
185
186 inline QString buffer() const { return text; }
187 QString plainText() const;
188 inline int length() const { return fragments.length(); }
189
190 inline QTextFormatCollection *formatCollection() { return &formats; }
191 inline const QTextFormatCollection *formatCollection() const { return &formats; }
192 inline QAbstractTextDocumentLayout *layout() const { return lout; }
193
194 inline FragmentIterator find(int pos) const { return fragments.find(k: pos); }
195 inline FragmentIterator begin() const { return fragments.begin(); }
196 inline FragmentIterator end() const { return fragments.end(); }
197
198 inline QTextBlock blocksBegin() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.firstNode()); }
199 inline QTextBlock blocksEnd() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), 0); }
200 inline QTextBlock blocksFind(int pos) const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.findNode(k: pos)); }
201 int blockCharFormatIndex(int node) const;
202
203 inline int numBlocks() const { return blocks.numNodes(); }
204
205 const BlockMap &blockMap() const { return blocks; }
206 const FragmentMap &fragmentMap() const { return fragments; }
207 BlockMap &blockMap() { return blocks; }
208 FragmentMap &fragmentMap() { return fragments; }
209
210 static const QTextBlockData *block(const QTextBlock &it) { return it.p->blocks.fragment(index: it.n); }
211
212 int nextCursorPosition(int position, QTextLayout::CursorMode mode) const;
213 int previousCursorPosition(int position, QTextLayout::CursorMode mode) const;
214 int leftCursorPosition(int position) const;
215 int rightCursorPosition(int position) const;
216
217 void changeObjectFormat(QTextObject *group, int format);
218
219 void setModified(bool m);
220 inline bool isModified() const { return modified; }
221
222 inline QFont defaultFont() const { return formats.defaultFont(); }
223 inline void setDefaultFont(const QFont &f) { formats.setDefaultFont(f); }
224
225 void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals = false);
226
227private:
228 bool split(int pos);
229 bool unite(uint f);
230
231 void insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op);
232 int insert_block(int pos, uint strPos, int format, int blockformat, QTextUndoCommand::Operation op, int command);
233 int remove_string(int pos, uint length, QTextUndoCommand::Operation op);
234 int remove_block(int pos, int *blockformat, int command, QTextUndoCommand::Operation op);
235
236 void insert_frame(QTextFrame *f);
237 void scan_frames(int pos, int charsRemoved, int charsAdded);
238 static void clearFrame(QTextFrame *f);
239
240 void adjustDocumentChangesAndCursors(int from, int addedOrRemoved, QTextUndoCommand::Operation op);
241
242 bool wasUndoAvailable;
243 bool wasRedoAvailable;
244
245public:
246 void documentChange(int from, int length);
247
248 void addCursor(QTextCursorPrivate *c);
249 void removeCursor(QTextCursorPrivate *c);
250
251 QTextFrame *frameAt(int pos) const;
252 QTextFrame *rootFrame() const;
253
254 QTextObject *objectForIndex(int objectIndex) const;
255 QTextObject *objectForFormat(int formatIndex) const;
256 QTextObject *objectForFormat(const QTextFormat &f) const;
257
258 QTextObject *createObject(const QTextFormat &newFormat, int objectIndex = -1);
259 void deleteObject(QTextObject *object);
260
261 QTextDocument *document() { return q_func(); }
262 const QTextDocument *document() const { return q_func(); }
263
264 bool ensureMaximumBlockCount();
265
266 static inline const QTextDocumentPrivate *get(const QTextDocument *document)
267 {
268 return document->d_func();
269 }
270
271 static inline QTextDocumentPrivate *get(QTextDocument *document)
272 {
273 return document->d_func();
274 }
275
276 static inline QTextDocumentPrivate *get(QTextBlock &block)
277 {
278 return block.p;
279 }
280
281 static inline const QTextDocumentPrivate *get(const QTextBlock &block)
282 {
283 return block.p;
284 }
285
286 static inline QTextDocumentPrivate *get(QTextObject *object)
287 {
288 return get(document: object->document());
289 }
290
291 static inline const QTextDocumentPrivate *get(const QTextObject *object)
292 {
293 return get(document: object->document());
294 }
295
296 bool canLayout() const { return layoutEnabled && !pageSize.isNull(); }
297
298private:
299 QTextDocumentPrivate(const QTextDocumentPrivate& m);
300 QTextDocumentPrivate& operator= (const QTextDocumentPrivate& m);
301
302 void appendUndoItem(const QTextUndoCommand &c);
303
304 void contentsChanged();
305
306 void compressPieceTable();
307
308 QString text;
309 uint unreachableCharacterCount;
310
311 QList<QTextUndoCommand> undoStack;
312 bool undoEnabled;
313 int undoState;
314 int revision;
315 // position in undo stack of the last setModified(false) call
316 int modifiedState;
317 bool modified;
318
319 int editBlock;
320 int editBlockCursorPosition;
321 int docChangeFrom;
322 int docChangeOldLength;
323 int docChangeLength;
324 bool framesDirty;
325
326 QTextFormatCollection formats;
327 mutable QTextFrame *rtFrame;
328 QAbstractTextDocumentLayout *lout;
329 FragmentMap fragments;
330 BlockMap blocks;
331 int initialBlockCharFormatIndex;
332
333 QSet<QTextCursorPrivate *> cursors;
334 QMap<int, QTextObject *> objects;
335 QMap<QUrl, QVariant> resources;
336 QMap<QUrl, QVariant> cachedResources;
337 QTextDocument::ResourceProvider resourceProvider;
338 QString defaultStyleSheet;
339
340 int lastBlockCount;
341
342public:
343 bool inContentsChange;
344 bool layoutEnabled = true;
345 QTextOption defaultTextOption;
346 Qt::CursorMoveStyle defaultCursorMoveStyle;
347#ifndef QT_NO_CSSPARSER
348 QCss::StyleSheet parsedDefaultStyleSheet;
349#endif
350 int maximumBlockCount;
351 uint needsEnsureMaximumBlockCount : 1;
352 uint blockCursorAdjustment : 1;
353 QSizeF pageSize;
354 QString title;
355 QString url;
356 QString cssMedia;
357 qreal indentWidth;
358 qreal documentMargin;
359 QUrl baseUrl;
360
361 void mergeCachedResources(const QTextDocumentPrivate *priv);
362
363 friend struct QTextHtmlParserNode;
364 friend class QTextHtmlExporter;
365 friend class QTextCursor;
366};
367
368class QTextTable;
369class QTextHtmlExporter
370{
371public:
372 QTextHtmlExporter(const QTextDocument *_doc);
373
374 enum ExportMode {
375 ExportEntireDocument,
376 ExportFragment
377 };
378
379 QString toHtml(ExportMode mode = ExportEntireDocument);
380
381private:
382 enum StyleMode { EmitStyleTag, OmitStyleTag };
383 enum FrameType { TextFrame, TableFrame, RootFrame };
384
385 void emitFrame(const QTextFrame::Iterator &frameIt);
386 void emitTextFrame(const QTextFrame *frame);
387 void emitBlock(const QTextBlock &block);
388 void emitTable(const QTextTable *table);
389 void emitFragment(const QTextFragment &fragment);
390
391 void emitBlockAttributes(const QTextBlock &block);
392 bool emitCharFormatStyle(const QTextCharFormat &format);
393 void emitTextLength(const char *attribute, const QTextLength &length);
394 void emitAlignment(Qt::Alignment alignment);
395 void emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode = EmitStyleTag);
396 void emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right);
397 void emitAttribute(const char *attribute, const QString &value);
398 void emitFrameStyle(const QTextFrameFormat &format, FrameType frameType);
399 void emitBorderStyle(QTextFrameFormat::BorderStyle style);
400 void emitPageBreakPolicy(QTextFormat::PageBreakFlags policy);
401
402 void emitFontFamily(const QStringList &families);
403
404 void emitBackgroundAttribute(const QTextFormat &format);
405 QString findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap);
406
407 QString html;
408 QTextCharFormat defaultCharFormat;
409 const QTextDocument *doc;
410 bool fragmentMarkers;
411 QStringList closingTags;
412};
413
414QT_END_NAMESPACE
415
416#endif // QTEXTDOCUMENT_P_H
417

source code of qtbase/src/gui/text/qtextdocument_p.h