1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #ifndef QTEXTDOCUMENT_P_H
43 #define QTEXTDOCUMENT_P_H
44 
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists purely as an
50 // implementation detail.  This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55 
56 #include "QtCore/qglobal.h"
57 #include "QtCore/qstring.h"
58 #include "QtCore/qvector.h"
59 #include "QtCore/qlist.h"
60 #include "private/qobject_p.h"
61 #include "private/qfragmentmap_p.h"
62 #include "QtGui/qtextlayout.h"
63 #include "QtGui/qtextoption.h"
64 #include "private/qtextformat_p.h"
65 #include "QtGui/qtextdocument.h"
66 #include "QtGui/qtextobject.h"
67 #include "QtGui/qtextcursor.h"
68 #include "QtCore/qmap.h"
69 #include "QtCore/qvariant.h"
70 #include "QtCore/qurl.h"
71 #include "private/qcssparser_p.h"
72 
73 // #define QT_QMAP_DEBUG
74 
75 #ifdef QT_QMAP_DEBUG
76 #include <iostream>
77 #endif
78 
79 QT_BEGIN_NAMESPACE
80 
81 class QTextFormatCollection;
82 class QTextFormat;
83 class QTextBlockFormat;
84 class QTextCursorPrivate;
85 class QAbstractTextDocumentLayout;
86 class QTextDocument;
87 class QTextFrame;
88 
89 #define QTextBeginningOfFrame QChar(0xfdd0)
90 #define QTextEndOfFrame QChar(0xfdd1)
91 
92 class QTextFragmentData : public QFragment<>
93 {
94 public:
initialize()95     inline void initialize() {}
invalidate()96     inline void invalidate() const {}
free()97     inline void free() {}
98     int stringPosition;
99     int format;
100 };
101 
102 class QTextBlockData : public QFragment<3>
103 {
104 public:
initialize()105     inline void initialize()
106         { layout = 0; userData = 0; userState = -1; revision = 0; hidden = 0; }
107     void invalidate() const;
free()108     inline void free()
109     { delete layout; layout = 0; delete userData; userData = 0; }
110 
111     mutable int format;
112     // ##### probably store a QTextEngine * here!
113     mutable QTextLayout *layout;
114     mutable QTextBlockUserData *userData;
115     mutable int userState;
116     mutable int revision : 31;
117     mutable uint hidden : 1;
118 };
119 
120 
121 class QAbstractUndoItem;
122 
123 class QTextUndoCommand
124 {
125 public:
126     enum Command {
127         Inserted = 0,
128         Removed = 1,
129         CharFormatChanged = 2,
130         BlockFormatChanged = 3,
131         BlockInserted = 4,
132         BlockRemoved = 5,
133         BlockAdded = 6,
134         BlockDeleted = 7,
135         GroupFormatChange = 8,
136         CursorMoved = 9,
137         Custom = 256
138     };
139     enum Operation {
140         KeepCursor = 0,
141         MoveCursor = 1
142     };
143     quint16 command;
144     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
145     uint block_end : 1; // the last command in an undo block has this set to 1.
146     uint block_padding : 6; // padding since block used to be a quint8
147     quint8 operation;
148     int format;
149     quint32 strPos;
150     quint32 pos;
151     union {
152         int blockFormat;
153         quint32 length;
154         QAbstractUndoItem *custom;
155         int objectIndex;
156     };
157     quint32 revision;
158 
159     bool tryMerge(const QTextUndoCommand &other);
160 };
161 Q_DECLARE_TYPEINFO(QTextUndoCommand, Q_PRIMITIVE_TYPE);
162 
163 class Q_AUTOTEST_EXPORT QTextDocumentPrivate : public QObjectPrivate
164 {
165     Q_DECLARE_PUBLIC(QTextDocument)
166 public:
167     typedef QFragmentMap<QTextFragmentData> FragmentMap;
168     typedef FragmentMap::ConstIterator FragmentIterator;
169     typedef QFragmentMap<QTextBlockData> BlockMap;
170 
171     QTextDocumentPrivate();
172     ~QTextDocumentPrivate();
173 
174     void init();
175     void clear();
176 
177     void setLayout(QAbstractTextDocumentLayout *layout);
178 
179     void insert(int pos, const QString &text, int format);
180     void insert(int pos, int strPos, int strLength, int format);
181     int insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
182     int insertBlock(const QChar &blockSeparator, int pos, int blockFormat, int charFormat,
183                      QTextUndoCommand::Operation op = QTextUndoCommand::MoveCursor);
184 
185     void move(int from, int to, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
186     void remove(int pos, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
187 
188     void aboutToRemoveCell(int cursorFrom, int cursorEnd);
189 
190     QTextFrame *insertFrame(int start, int end, const QTextFrameFormat &format);
191     void removeFrame(QTextFrame *frame);
192 
193     enum FormatChangeMode { MergeFormat, SetFormat, SetFormatAndPreserveObjectIndices };
194 
195     void setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode = SetFormat);
196     void setBlockFormat(const QTextBlock &from, const QTextBlock &to,
197 			const QTextBlockFormat &newFormat, FormatChangeMode mode = SetFormat);
198 
199     void emitUndoAvailable(bool available);
200     void emitRedoAvailable(bool available);
201 
202     int undoRedo(bool undo);
undo()203     inline void undo() { undoRedo(true); }
redo()204     inline void redo() { undoRedo(false); }
205     void appendUndoItem(QAbstractUndoItem *);
beginEditBlock()206     inline void beginEditBlock() { if (0 == editBlock++) ++revision; }
207     void joinPreviousEditBlock();
208     void endEditBlock();
209     void finishEdit();
isInEditBlock()210     inline bool isInEditBlock() const { return editBlock; }
211     void enableUndoRedo(bool enable);
isUndoRedoEnabled()212     inline bool isUndoRedoEnabled() const { return undoEnabled; }
213 
isUndoAvailable()214     inline bool isUndoAvailable() const { return undoEnabled && undoState > 0; }
isRedoAvailable()215     inline bool isRedoAvailable() const { return undoEnabled && undoState < undoStack.size(); }
216 
availableUndoSteps()217     inline int availableUndoSteps() const { return undoEnabled ? undoState : 0; }
availableRedoSteps()218     inline int availableRedoSteps() const { return undoEnabled ? qMax(undoStack.size() - undoState - 1, 0) : 0; }
219 
buffer()220     inline QString buffer() const { return text; }
221     QString plainText() const;
length()222     inline int length() const { return fragments.length(); }
223 
formatCollection()224     inline QTextFormatCollection *formatCollection() { return &formats; }
formatCollection()225     inline const QTextFormatCollection *formatCollection() const { return &formats; }
layout()226     inline QAbstractTextDocumentLayout *layout() const { return lout; }
227 
find(int pos)228     inline FragmentIterator find(int pos) const { return fragments.find(pos); }
begin()229     inline FragmentIterator begin() const { return fragments.begin(); }
end()230     inline FragmentIterator end() const { return fragments.end(); }
231 
blocksBegin()232     inline QTextBlock blocksBegin() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.firstNode()); }
blocksEnd()233     inline QTextBlock blocksEnd() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), 0); }
blocksFind(int pos)234     inline QTextBlock blocksFind(int pos) const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.findNode(pos)); }
235     int blockCharFormatIndex(int node) const;
236 
numBlocks()237     inline int numBlocks() const { return blocks.numNodes(); }
238 
blockMap()239     const BlockMap &blockMap() const { return blocks; }
fragmentMap()240     const FragmentMap &fragmentMap() const { return fragments; }
blockMap()241     BlockMap &blockMap() { return blocks; }
fragmentMap()242     FragmentMap &fragmentMap() { return fragments; }
243 
block(const QTextBlock & it)244     static const QTextBlockData *block(const QTextBlock &it) { return it.p->blocks.fragment(it.n); }
245 
246     int nextCursorPosition(int position, QTextLayout::CursorMode mode) const;
247     int previousCursorPosition(int position, QTextLayout::CursorMode mode) const;
248     int leftCursorPosition(int position) const;
249     int rightCursorPosition(int position) const;
250 
251     void changeObjectFormat(QTextObject *group, int format);
252 
253     void setModified(bool m);
isModified()254     inline bool isModified() const { return modified; }
255 
defaultFont()256     inline QFont defaultFont() const { return formats.defaultFont(); }
setDefaultFont(const QFont & f)257     inline void setDefaultFont(const QFont &f) { formats.setDefaultFont(f); }
258 
259     void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals = false);
260 
261 private:
262     bool split(int pos);
263     bool unite(uint f);
264 
265     void insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op);
266     int insert_block(int pos, uint strPos, int format, int blockformat, QTextUndoCommand::Operation op, int command);
267     int remove_string(int pos, uint length, QTextUndoCommand::Operation op);
268     int remove_block(int pos, int *blockformat, int command, QTextUndoCommand::Operation op);
269 
270     void insert_frame(QTextFrame *f);
271     void scan_frames(int pos, int charsRemoved, int charsAdded);
272     static void clearFrame(QTextFrame *f);
273 
274     void adjustDocumentChangesAndCursors(int from, int addedOrRemoved, QTextUndoCommand::Operation op);
275 
276     bool wasUndoAvailable;
277     bool wasRedoAvailable;
278 
279 public:
280     void documentChange(int from, int length);
281 
addCursor(QTextCursorPrivate * c)282     inline void addCursor(QTextCursorPrivate *c) { cursors.append(c); }
removeCursor(QTextCursorPrivate * c)283     inline void removeCursor(QTextCursorPrivate *c) { cursors.removeAll(c); }
284 
285     QTextFrame *frameAt(int pos) const;
286     QTextFrame *rootFrame() const;
287 
288     QTextObject *objectForIndex(int objectIndex) const;
289     QTextObject *objectForFormat(int formatIndex) const;
290     QTextObject *objectForFormat(const QTextFormat &f) const;
291 
292     QTextObject *createObject(const QTextFormat &newFormat, int objectIndex = -1);
293     void deleteObject(QTextObject *object);
294 
document()295     QTextDocument *document() { return q_func(); }
document()296     const QTextDocument *document() const { return q_func(); }
297 
298     bool ensureMaximumBlockCount();
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     QVector<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     QList<QTextCursorPrivate *> cursors;
336     QMap<int, QTextObject *> objects;
337     QMap<QUrl, QVariant> resources;
338     QMap<QUrl, QVariant> cachedResources;
339     QString defaultStyleSheet;
340 
341     int lastBlockCount;
342 
343 public:
344     QTextOption defaultTextOption;
345     Qt::CursorMoveStyle defaultCursorMoveStyle;
346 #ifndef QT_NO_CSSPARSER
347     QCss::StyleSheet parsedDefaultStyleSheet;
348 #endif
349     int maximumBlockCount;
350     uint needsEnsureMaximumBlockCount : 1;
351     uint inContentsChange : 1;
352     uint blockCursorAdjustment : 1;
353     QSizeF pageSize;
354     QString title;
355     QString url;
356     qreal indentWidth;
357     qreal documentMargin;
358 
359     void mergeCachedResources(const QTextDocumentPrivate *priv);
360 
361     friend class QTextHtmlExporter;
362     friend class QTextCursor;
363 };
364 
365 class QTextTable;
366 class QTextHtmlExporter
367 {
368 public:
369     QTextHtmlExporter(const QTextDocument *_doc);
370 
371     enum ExportMode {
372         ExportEntireDocument,
373         ExportFragment
374     };
375 
376     QString toHtml(const QByteArray &encoding, ExportMode mode = ExportEntireDocument);
377 
378 private:
379     enum StyleMode { EmitStyleTag, OmitStyleTag };
380     enum FrameType { TextFrame, TableFrame, RootFrame };
381 
382     void emitFrame(QTextFrame::Iterator frameIt);
383     void emitTextFrame(const QTextFrame *frame);
384     void emitBlock(const QTextBlock &block);
385     void emitTable(const QTextTable *table);
386     void emitFragment(const QTextFragment &fragment);
387 
388     void emitBlockAttributes(const QTextBlock &block);
389     bool emitCharFormatStyle(const QTextCharFormat &format);
390     void emitTextLength(const char *attribute, const QTextLength &length);
391     void emitAlignment(Qt::Alignment alignment);
392     void emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode = EmitStyleTag);
393     void emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right);
394     void emitAttribute(const char *attribute, const QString &value);
395     void emitFrameStyle(const QTextFrameFormat &format, FrameType frameType);
396     void emitBorderStyle(QTextFrameFormat::BorderStyle style);
397     void emitPageBreakPolicy(QTextFormat::PageBreakFlags policy);
398 
399     void emitFontFamily(const QString &family);
400 
401     void emitBackgroundAttribute(const QTextFormat &format);
402     QString findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap);
403 
404     QString html;
405     QTextCharFormat defaultCharFormat;
406     const QTextDocument *doc;
407     bool fragmentMarkers;
408 };
409 
410 QT_END_NAMESPACE
411 
412 #endif // QTEXTDOCUMENT_P_H
413