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 QTEXTDOCUMENT_P_H 41 #define QTEXTDOCUMENT_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 purely as an 48 // implementation detail. 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/qvector.h" 57 #include "QtCore/qlist.h" 58 #include "private/qobject_p.h" 59 #include "private/qfragmentmap_p.h" 60 #include "QtGui/qtextlayout.h" 61 #include "QtGui/qtextoption.h" 62 #include "private/qtextformat_p.h" 63 #include "QtGui/qtextdocument.h" 64 #include "QtGui/qtextobject.h" 65 #include "QtGui/qtextcursor.h" 66 #include "QtCore/qmap.h" 67 #include "QtCore/qvariant.h" 68 #include "QtCore/qurl.h" 69 #include "private/qcssparser_p.h" 70 71 // #define QT_QMAP_DEBUG 72 73 #ifdef QT_QMAP_DEBUG 74 #include <iostream> 75 #endif 76 77 QT_BEGIN_NAMESPACE 78 79 class QTextFormatCollection; 80 class QTextFormat; 81 class QTextBlockFormat; 82 class QTextCursorPrivate; 83 class QAbstractTextDocumentLayout; 84 class QTextDocument; 85 class QTextFrame; 86 87 #define QTextBeginningOfFrame QChar(0xfdd0) 88 #define QTextEndOfFrame QChar(0xfdd1) 89 90 class QTextFragmentData : public QFragment<> 91 { 92 public: initialize()93 inline void initialize() {} invalidate()94 inline void invalidate() const {} free()95 inline void free() {} 96 int stringPosition; 97 int format; 98 }; 99 100 class QTextBlockData : public QFragment<3> 101 { 102 public: initialize()103 inline void initialize() 104 { layout = nullptr; userData = nullptr; userState = -1; revision = 0; hidden = 0; } 105 void invalidate() const; free()106 inline void free() 107 { delete layout; layout = nullptr; delete userData; userData = nullptr; } 108 109 mutable int format; 110 // ##### probably store a QTextEngine * here! 111 mutable QTextLayout *layout; 112 mutable QTextBlockUserData *userData; 113 mutable int userState; 114 mutable signed int revision : 31; 115 mutable uint hidden : 1; 116 }; 117 118 119 class QAbstractUndoItem; 120 121 class QTextUndoCommand 122 { 123 public: 124 enum Command { 125 Inserted = 0, 126 Removed = 1, 127 CharFormatChanged = 2, 128 BlockFormatChanged = 3, 129 BlockInserted = 4, 130 BlockRemoved = 5, 131 BlockAdded = 6, 132 BlockDeleted = 7, 133 GroupFormatChange = 8, 134 CursorMoved = 9, 135 Custom = 256 136 }; 137 enum Operation { 138 KeepCursor = 0, 139 MoveCursor = 1 140 }; 141 quint16 command; 142 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 143 uint block_end : 1; // the last command in an undo block has this set to 1. 144 uint block_padding : 6; // padding since block used to be a quint8 145 quint8 operation; 146 int format; 147 quint32 strPos; 148 quint32 pos; 149 union { 150 int blockFormat; 151 quint32 length; 152 QAbstractUndoItem *custom; 153 int objectIndex; 154 }; 155 quint32 revision; 156 157 bool tryMerge(const QTextUndoCommand &other); 158 }; 159 Q_DECLARE_TYPEINFO(QTextUndoCommand, Q_PRIMITIVE_TYPE); 160 161 class Q_GUI_EXPORT QTextDocumentPrivate : public QObjectPrivate 162 { 163 Q_DECLARE_PUBLIC(QTextDocument) 164 public: 165 typedef QFragmentMap<QTextFragmentData> FragmentMap; 166 typedef FragmentMap::ConstIterator FragmentIterator; 167 typedef QFragmentMap<QTextBlockData> BlockMap; 168 169 QTextDocumentPrivate(); 170 ~QTextDocumentPrivate(); 171 172 void init(); 173 void clear(); 174 175 void setLayout(QAbstractTextDocumentLayout *layout); 176 177 void insert(int pos, const QString &text, int format); 178 void insert(int pos, int strPos, int strLength, int format); 179 int insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor); 180 int insertBlock(QChar blockSeparator, int pos, int blockFormat, int charFormat, 181 QTextUndoCommand::Operation op = QTextUndoCommand::MoveCursor); 182 183 void move(int from, int to, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor); 184 void remove(int pos, int length, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor); 185 186 void aboutToRemoveCell(int cursorFrom, int cursorEnd); 187 188 QTextFrame *insertFrame(int start, int end, const QTextFrameFormat &format); 189 void removeFrame(QTextFrame *frame); 190 191 enum FormatChangeMode { MergeFormat, SetFormat, SetFormatAndPreserveObjectIndices }; 192 193 void setCharFormat(int pos, int length, const QTextCharFormat &newFormat, FormatChangeMode mode = SetFormat); 194 void setBlockFormat(const QTextBlock &from, const QTextBlock &to, 195 const QTextBlockFormat &newFormat, FormatChangeMode mode = SetFormat); 196 197 void emitUndoAvailable(bool available); 198 void emitRedoAvailable(bool available); 199 200 int undoRedo(bool undo); undo()201 inline void undo() { undoRedo(true); } redo()202 inline void redo() { undoRedo(false); } 203 void appendUndoItem(QAbstractUndoItem *); beginEditBlock()204 inline void beginEditBlock() { if (0 == editBlock++) ++revision; } 205 void joinPreviousEditBlock(); 206 void endEditBlock(); 207 void finishEdit(); isInEditBlock()208 inline bool isInEditBlock() const { return editBlock; } 209 void enableUndoRedo(bool enable); isUndoRedoEnabled()210 inline bool isUndoRedoEnabled() const { return undoEnabled; } 211 isUndoAvailable()212 inline bool isUndoAvailable() const { return undoEnabled && undoState > 0; } isRedoAvailable()213 inline bool isRedoAvailable() const { return undoEnabled && undoState < undoStack.size(); } 214 availableUndoSteps()215 inline int availableUndoSteps() const { return undoEnabled ? undoState : 0; } availableRedoSteps()216 inline int availableRedoSteps() const { return undoEnabled ? qMax(undoStack.size() - undoState - 1, 0) : 0; } 217 buffer()218 inline QString buffer() const { return text; } 219 QString plainText() const; length()220 inline int length() const { return fragments.length(); } 221 formatCollection()222 inline QTextFormatCollection *formatCollection() { return &formats; } formatCollection()223 inline const QTextFormatCollection *formatCollection() const { return &formats; } layout()224 inline QAbstractTextDocumentLayout *layout() const { return lout; } 225 find(int pos)226 inline FragmentIterator find(int pos) const { return fragments.find(pos); } begin()227 inline FragmentIterator begin() const { return fragments.begin(); } end()228 inline FragmentIterator end() const { return fragments.end(); } 229 blocksBegin()230 inline QTextBlock blocksBegin() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.firstNode()); } blocksEnd()231 inline QTextBlock blocksEnd() const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), 0); } blocksFind(int pos)232 inline QTextBlock blocksFind(int pos) const { return QTextBlock(const_cast<QTextDocumentPrivate *>(this), blocks.findNode(pos)); } 233 int blockCharFormatIndex(int node) const; 234 numBlocks()235 inline int numBlocks() const { return blocks.numNodes(); } 236 blockMap()237 const BlockMap &blockMap() const { return blocks; } fragmentMap()238 const FragmentMap &fragmentMap() const { return fragments; } blockMap()239 BlockMap &blockMap() { return blocks; } fragmentMap()240 FragmentMap &fragmentMap() { return fragments; } 241 block(const QTextBlock & it)242 static const QTextBlockData *block(const QTextBlock &it) { return it.p->blocks.fragment(it.n); } 243 244 int nextCursorPosition(int position, QTextLayout::CursorMode mode) const; 245 int previousCursorPosition(int position, QTextLayout::CursorMode mode) const; 246 int leftCursorPosition(int position) const; 247 int rightCursorPosition(int position) const; 248 249 void changeObjectFormat(QTextObject *group, int format); 250 251 void setModified(bool m); isModified()252 inline bool isModified() const { return modified; } 253 defaultFont()254 inline QFont defaultFont() const { return formats.defaultFont(); } setDefaultFont(const QFont & f)255 inline void setDefaultFont(const QFont &f) { formats.setDefaultFont(f); } 256 257 void clearUndoRedoStacks(QTextDocument::Stacks stacksToClear, bool emitSignals = false); 258 259 private: 260 bool split(int pos); 261 bool unite(uint f); 262 263 void insert_string(int pos, uint strPos, uint length, int format, QTextUndoCommand::Operation op); 264 int insert_block(int pos, uint strPos, int format, int blockformat, QTextUndoCommand::Operation op, int command); 265 int remove_string(int pos, uint length, QTextUndoCommand::Operation op); 266 int remove_block(int pos, int *blockformat, int command, QTextUndoCommand::Operation op); 267 268 void insert_frame(QTextFrame *f); 269 void scan_frames(int pos, int charsRemoved, int charsAdded); 270 static void clearFrame(QTextFrame *f); 271 272 void adjustDocumentChangesAndCursors(int from, int addedOrRemoved, QTextUndoCommand::Operation op); 273 274 bool wasUndoAvailable; 275 bool wasRedoAvailable; 276 277 public: 278 void documentChange(int from, int length); 279 addCursor(QTextCursorPrivate * c)280 inline void addCursor(QTextCursorPrivate *c) { cursors.insert(c); } removeCursor(QTextCursorPrivate * c)281 inline void removeCursor(QTextCursorPrivate *c) { cursors.remove(c); } 282 283 QTextFrame *frameAt(int pos) const; 284 QTextFrame *rootFrame() const; 285 286 QTextObject *objectForIndex(int objectIndex) const; 287 QTextObject *objectForFormat(int formatIndex) const; 288 QTextObject *objectForFormat(const QTextFormat &f) const; 289 290 QTextObject *createObject(const QTextFormat &newFormat, int objectIndex = -1); 291 void deleteObject(QTextObject *object); 292 document()293 QTextDocument *document() { return q_func(); } document()294 const QTextDocument *document() const { return q_func(); } 295 296 bool ensureMaximumBlockCount(); 297 298 private: 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 QVector<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 QString defaultStyleSheet; 338 339 int lastBlockCount; 340 341 public: 342 bool inContentsChange; 343 QTextOption defaultTextOption; 344 Qt::CursorMoveStyle defaultCursorMoveStyle; 345 #ifndef QT_NO_CSSPARSER 346 QCss::StyleSheet parsedDefaultStyleSheet; 347 #endif 348 int maximumBlockCount; 349 uint needsEnsureMaximumBlockCount : 1; 350 uint blockCursorAdjustment : 1; 351 QSizeF pageSize; 352 QString title; 353 QString url; 354 qreal indentWidth; 355 qreal documentMargin; 356 QUrl baseUrl; 357 358 void mergeCachedResources(const QTextDocumentPrivate *priv); 359 360 friend struct QTextHtmlParserNode; 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(const 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 QStringList &families); 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