Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qtextdocument.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 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#include "qtextdocument.h"
5#include <qtextformat.h>
6#include "qtextcursor_p.h"
7#include "qtextdocument_p.h"
11#include "qtexttable.h"
12#include "qtextlist.h"
13#include <qdebug.h>
14#if QT_CONFIG(regularexpression)
15#include <qregularexpression.h>
16#endif
17#include <qvarlengtharray.h>
18#include <qthread.h>
19#include <qcoreapplication.h>
20#include <qmetaobject.h>
21
22#include "qtexthtmlparser_p.h"
23#include "qpainter.h"
24#include <qfile.h>
25#include <qfileinfo.h>
26#include <qdir.h>
27#include "qfont_p.h"
28#include "private/qdataurl_p.h"
29
30#include "qtextdocument_p.h"
31#include <private/qabstracttextdocumentlayout_p.h>
32#include "qpagedpaintdevice.h"
33#include "private/qpagedpaintdevice_p.h"
34#if QT_CONFIG(textmarkdownreader)
35#include <private/qtextmarkdownimporter_p.h>
36#endif
37#if QT_CONFIG(textmarkdownwriter)
38#include <private/qtextmarkdownwriter_p.h>
39#endif
40
41#include <limits.h>
42
44
45using namespace Qt::StringLiterals;
46
47Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n);
48
49namespace {
50 QTextDocument::ResourceProvider qt_defaultResourceProvider;
51};
52
65{
66 if (text.isEmpty())
67 return false;
68 int start = 0;
69
70 while (start < text.size() && text.at(start).isSpace())
71 ++start;
72
73 // skip a leading <?xml ... ?> as for example with xhtml
74 if (QStringView{text}.mid(start, 5).compare("<?xml"_L1) == 0) {
75 while (start < text.size()) {
76 if (text.at(start) == u'?'
77 && start + 2 < text.size()
78 && text.at(start + 1) == u'>') {
79 start += 2;
80 break;
81 }
82 ++start;
83 }
84
85 while (start < text.size() && text.at(start).isSpace())
86 ++start;
87 }
88
89 if (QStringView{text}.mid(start, 5).compare("<!doc"_L1, Qt::CaseInsensitive) == 0)
90 return true;
91 int open = start;
92 while (open < text.size() && text.at(open) != u'<'
93 && text.at(open) != u'\n') {
94 if (text.at(open) == u'&' && QStringView{text}.mid(open + 1, 3) == "lt;"_L1)
95 return true; // support desperate attempt of user to see <...>
96 ++open;
97 }
98 if (open < text.size() && text.at(open) == u'<') {
99 const int close = text.indexOf(u'>', open);
100 if (close > -1) {
101 QString tag;
102 for (int i = open+1; i < close; ++i) {
103 if (text[i].isDigit() || text[i].isLetter())
104 tag += text[i];
105 else if (!tag.isEmpty() && text[i].isSpace())
106 break;
107 else if (!tag.isEmpty() && text[i] == u'/' && i + 1 == close)
108 break;
109 else if (!text[i].isSpace() && (!tag.isEmpty() || text[i] != u'!'))
110 return false; // that's not a tag
111 }
112#ifndef QT_NO_TEXTHTMLPARSER
113 return QTextHtmlParser::lookupElement(std::move(tag).toLower()) != -1;
114#else
115 return false;
116#endif // QT_NO_TEXTHTMLPARSER
117 }
118 }
119 return false;
120}
121
133{
134 int col = 0;
135 QString rich;
136 rich += "<p>"_L1;
137 for (int i = 0; i < plain.size(); ++i) {
138 if (plain[i] == u'\n'){
139 int c = 1;
140 while (i+1 < plain.size() && plain[i+1] == u'\n') {
141 i++;
142 c++;
143 }
144 if (c == 1)
145 rich += "<br>\n"_L1;
146 else {
147 rich += "</p>\n"_L1;
148 while (--c > 1)
149 rich += "<br>\n"_L1;
150 rich += "<p>"_L1;
151 }
152 col = 0;
153 } else {
154 if (mode == Qt::WhiteSpacePre && plain[i] == u'\t'){
155 rich += QChar::Nbsp;
156 ++col;
157 while (col % 8) {
158 rich += QChar::Nbsp;
159 ++col;
160 }
161 }
162 else if (mode == Qt::WhiteSpacePre && plain[i].isSpace())
163 rich += QChar::Nbsp;
164 else if (plain[i] == u'<')
165 rich += "&lt;"_L1;
166 else if (plain[i] == u'>')
167 rich += "&gt;"_L1;
168 else if (plain[i] == u'&')
169 rich += "&amp;"_L1;
170 else
171 rich += plain[i];
172 ++col;
173 }
174 }
175 if (col != 0)
176 rich += "</p>"_L1;
177 return rich;
178}
179
260{
261 Q_D(QTextDocument);
262 d->init();
263}
264
271{
272 Q_D(QTextDocument);
273 d->init();
275}
276
281 : QObject(dd, parent)
282{
283 Q_D(QTextDocument);
284 d->init();
285}
286
291{
292}
293
294
300{
301 Q_D(const QTextDocument);
303 if (isEmpty()) {
304 const QTextCursor thisCursor(const_cast<QTextDocument *>(this));
305
306 const auto blockFormat = thisCursor.blockFormat();
307 if (blockFormat.isValid() && !blockFormat.isEmpty())
308 QTextCursor(doc).setBlockFormat(blockFormat);
309
310 const auto blockCharFormat = thisCursor.blockCharFormat();
311 if (blockCharFormat.isValid() && !blockCharFormat.isEmpty())
312 QTextCursor(doc).setBlockCharFormat(blockCharFormat);
313 } else {
315 }
316 doc->rootFrame()->setFrameFormat(rootFrame()->frameFormat());
317 QTextDocumentPrivate *priv = doc->d_func();
318 priv->title = d->title;
319 priv->url = d->url;
320 priv->cssMedia = d->cssMedia;
321 priv->pageSize = d->pageSize;
322 priv->indentWidth = d->indentWidth;
323 priv->defaultTextOption = d->defaultTextOption;
324 priv->setDefaultFont(d->defaultFont());
325 priv->resources = d->resources;
326 priv->cachedResources.clear();
327 priv->resourceProvider = d->resourceProvider;
328#ifndef QT_NO_CSSPARSER
329 priv->defaultStyleSheet = d->defaultStyleSheet;
330 priv->parsedDefaultStyleSheet = d->parsedDefaultStyleSheet;
331#endif
332 return doc;
333}
334
339{
340 Q_D(const QTextDocument);
341 /* because if we're empty we still have one single paragraph as
342 * one single fragment */
343 return d->length() <= 1;
344}
345
350{
351 Q_D(QTextDocument);
352 d->clear();
353 d->resources.clear();
354}
355
369{
370 Q_D(QTextDocument);
371 const int pos = d->undoRedo(true);
372 if (cursor && pos >= 0) {
373 *cursor = QTextCursor(this);
374 cursor->setPosition(pos);
375 }
376}
377
386{
387 Q_D(QTextDocument);
388 const int pos = d->undoRedo(false);
389 if (cursor && pos >= 0) {
390 *cursor = QTextCursor(this);
391 cursor->setPosition(pos);
392 }
393}
394
414{
415 Q_D(QTextDocument);
416 d->clearUndoRedoStacks(stacksToClear, true);
417}
418
424{
425 Q_D(QTextDocument);
426 d->undoRedo(true);
427}
428
434{
435 Q_D(QTextDocument);
436 d->undoRedo(false);
437}
438
445{
446 Q_D(QTextDocument);
447 d->appendUndoItem(item);
448}
449
458{
459 Q_D(QTextDocument);
460 d->enableUndoRedo(enable);
461}
462
464{
465 Q_D(const QTextDocument);
466 return d->isUndoRedoEnabled();
467}
468
491{
492 Q_D(const QTextDocument);
493 return d->maximumBlockCount;
494}
495
497{
498 Q_D(QTextDocument);
499 d->maximumBlockCount = maximum;
500 d->ensureMaximumBlockCount();
501 setUndoRedoEnabled(false);
502}
503
512{
513 Q_D(const QTextDocument);
514 return d->defaultTextOption;
515}
516
523{
524 Q_D(QTextDocument);
525 d->defaultTextOption = option;
526 if (d->lout)
527 d->lout->documentChanged(0, 0, d->length());
528}
529
547{
548 Q_D(const QTextDocument);
549 return d->baseUrl;
550}
551
553{
554 Q_D(QTextDocument);
555 if (d->baseUrl != url) {
556 d->baseUrl = url;
557 if (d->lout)
558 d->lout->documentChanged(0, 0, d->length());
560 }
561}
562
570{
571 Q_D(const QTextDocument);
572 return d->defaultCursorMoveStyle;
573}
574
581{
582 Q_D(QTextDocument);
583 d->defaultCursorMoveStyle = style;
584}
585
594{
595 Q_D(QTextDocument);
596 d->documentChange(from, length);
597 if (!d->inContentsChange) {
598 if (d->lout) {
599 d->lout->documentChanged(d->docChangeFrom, d->docChangeOldLength, d->docChangeLength);
600 d->docChangeFrom = -1;
601 }
602 }
603}
604
622{
623 Q_D(QTextDocument);
624 if (b == d->defaultTextOption.useDesignMetrics())
625 return;
626 d->defaultTextOption.setUseDesignMetrics(b);
627 if (d->lout)
628 d->lout->documentChanged(0, 0, d->length());
629}
630
632{
633 Q_D(const QTextDocument);
634 return d->defaultTextOption.useDesignMetrics();
635}
636
656{
657 Q_D(QTextDocument);
658 if (d->layoutEnabled == b)
659 return;
660 d->layoutEnabled = b;
661 if (b && d->lout)
662 d->lout->documentChanged(0, 0, d->length());
663}
664
666{
667 Q_D(const QTextDocument);
668 return d->layoutEnabled;
669}
670
678{
679 p->save();
681 if (rect.isValid()) {
682 p->setClipRect(rect);
683 ctx.clip = rect;
684 }
686 p->restore();
687}
688
711{
712 Q_D(QTextDocument);
713 QSizeF sz = d->pageSize;
714 sz.setWidth(width);
715 sz.setHeight(-1);
716 setPageSize(sz);
717}
718
720{
721 Q_D(const QTextDocument);
722 return d->pageSize.width();
723}
724
734{
735 if (QTextDocumentLayout *lout = qobject_cast<QTextDocumentLayout *>(documentLayout()))
736 return lout->idealWidth();
737 return textWidth();
738}
739
747{
748 Q_D(const QTextDocument);
749 return d->documentMargin;
750}
751
753{
754 Q_D(QTextDocument);
755 if (d->documentMargin != margin) {
756 d->documentMargin = margin;
757
758 QTextFrame* root = rootFrame();
760 format.setMargin(margin);
761 root->setFrameFormat(format);
762
763 if (d->lout)
764 d->lout->documentChanged(0, 0, d->length());
765 }
766}
767
768
779{
780 Q_D(const QTextDocument);
781 return d->indentWidth;
782}
783
784
796{
797 Q_D(QTextDocument);
798 if (d->indentWidth != width) {
799 d->indentWidth = width;
800 if (d->lout)
801 d->lout->documentChanged(0, 0, d->length());
802 }
803}
804
805
806
807
816{
817 // Pull this private function in from qglobal.cpp
818 QFont f = defaultFont();
819 QFontMetrics fm(f);
820 int mw = fm.horizontalAdvance(u'x') * 80;
821 int w = mw;
824 if (size.width() != 0) {
825 w = qt_int_sqrt((uint)(5 * size.height() * size.width() / 3));
826 setTextWidth(qMin(w, mw));
827
829 if (w*3 < 5*size.height()) {
830 w = qt_int_sqrt((uint)(2 * size.height() * size.width()));
831 setTextWidth(qMin(w, mw));
832 }
833 }
835}
836
855{
856 return documentLayout()->documentSize();
857}
858
871{
872 Q_D(const QTextDocument);
873 return d->blockMap().numNodes();
874}
875
876
886{
887 Q_D(const QTextDocument);
888 return d->blockMap().length(2);
889}
890
902{
903 Q_D(const QTextDocument);
904 return d->length();
905}
906
916{
917 Q_D(const QTextDocument);
918 if (pos < 0 || pos >= d->length())
919 return QChar();
921 const QTextFragmentData * const frag = fragIt.value();
922 const int offsetInFragment = qMax(0, pos - fragIt.position());
923 return d->text.at(frag->stringPosition + offsetInFragment);
924}
925
926
942#ifndef QT_NO_CSSPARSER
944{
945 Q_D(QTextDocument);
946 d->defaultStyleSheet = sheet;
947 QCss::Parser parser(sheet);
948 d->parsedDefaultStyleSheet = QCss::StyleSheet();
949 d->parsedDefaultStyleSheet.origin = QCss::StyleSheetOrigin_UserAgent;
950 parser.parse(&d->parsedDefaultStyleSheet);
951}
952
954{
955 Q_D(const QTextDocument);
956 return d->defaultStyleSheet;
957}
958#endif // QT_NO_CSSPARSER
959
1042{
1043 Q_D(const QTextDocument);
1044 return d->isUndoAvailable();
1045}
1046
1053{
1054 Q_D(const QTextDocument);
1055 return d->isRedoAvailable();
1056}
1057
1065{
1066 Q_D(const QTextDocument);
1067 return d->availableUndoSteps();
1068}
1069
1077{
1078 Q_D(const QTextDocument);
1079 return d->availableRedoSteps();
1080}
1081
1092{
1093 Q_D(const QTextDocument);
1094 return d->revision;
1095}
1096
1097
1098
1106{
1107 Q_D(QTextDocument);
1108 d->setLayout(layout);
1109}
1110
1115{
1116 Q_D(const QTextDocument);
1117 if (!d->lout) {
1118 QTextDocument *that = const_cast<QTextDocument *>(this);
1119 that->d_func()->setLayout(new QTextDocumentLayout(that));
1120 }
1121 return d->lout;
1122}
1123
1124
1132{
1133 Q_D(const QTextDocument);
1134 switch (info) {
1135 case DocumentTitle:
1136 return d->title;
1137 case DocumentUrl:
1138 return d->url;
1139 case CssMedia:
1140 return d->cssMedia;
1141 }
1142 return QString();
1143}
1144
1152{
1153 Q_D(QTextDocument);
1154 switch (info) {
1155 case DocumentTitle:
1156 d->title = string;
1157 break;
1158 case DocumentUrl:
1159 d->url = string;
1160 break;
1161 case CssMedia:
1162 d->cssMedia = string;
1163 break;
1164 }
1165}
1166
1176{
1177 Q_D(const QTextDocument);
1178 return d->plainText();
1179}
1180
1199{
1200 Q_D(const QTextDocument);
1201 QString txt = d->plainText();
1202
1203 QChar *uc = txt.data();
1204 QChar *e = uc + txt.size();
1205
1206 for (; uc != e; ++uc) {
1207 switch (uc->unicode()) {
1208 case 0xfdd0: // QTextBeginningOfFrame
1209 case 0xfdd1: // QTextEndOfFrame
1212 *uc = u'\n';
1213 break;
1214 case QChar::Nbsp:
1215 *uc = u' ';
1216 break;
1217 default:
1218 ;
1219 }
1220 }
1221 return txt;
1222}
1223
1231{
1232 Q_D(QTextDocument);
1233 bool previousState = d->isUndoRedoEnabled();
1234 d->enableUndoRedo(false);
1235 d->beginEditBlock();
1236 d->clear();
1238 d->endEditBlock();
1239 d->enableUndoRedo(previousState);
1240}
1241
1261#ifndef QT_NO_TEXTHTMLPARSER
1262
1264{
1265 Q_D(QTextDocument);
1266 bool previousState = d->isUndoRedoEnabled();
1267 d->enableUndoRedo(false);
1268 d->beginEditBlock();
1269 d->clear();
1271 d->endEditBlock();
1272 d->enableUndoRedo(previousState);
1273}
1274
1275#endif // QT_NO_TEXTHTMLPARSER
1276
1305static bool findInBlock(const QTextBlock &block, const QString &expression, int offset,
1306 QTextDocument::FindFlags options, QTextCursor *cursor)
1307{
1308 QString text = block.text();
1309 text.replace(QChar::Nbsp, u' ');
1311 int idx = -1;
1312
1313 while (offset >= 0 && offset <= text.size()) {
1314 idx = (options & QTextDocument::FindBackward) ?
1315 text.lastIndexOf(expression, offset, sensitivity) : text.indexOf(expression, offset, sensitivity);
1316 if (idx == -1)
1317 return false;
1318
1319 if (options & QTextDocument::FindWholeWords) {
1320 const int start = idx;
1321 const int end = start + expression.size();
1322 if ((start != 0 && text.at(start - 1).isLetterOrNumber())
1323 || (end != text.size() && text.at(end).isLetterOrNumber())) {
1324 //if this is not a whole word, continue the search in the string
1325 offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;
1326 idx = -1;
1327 continue;
1328 }
1329 }
1330 //we have a hit, return the cursor for that.
1332 block.position() + idx);
1333 cursor->setPosition(cursor->position() + expression.size(), QTextCursor::KeepAnchor);
1334 return true;
1335 }
1336 return false;
1337}
1338
1355QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags options) const
1356{
1357 Q_D(const QTextDocument);
1358
1359 if (subString.isEmpty())
1360 return QTextCursor();
1361
1362 int pos = from;
1363 //the cursor is positioned between characters, so for a backward search
1364 //do not include the character given in the position.
1365 if (options & FindBackward) {
1366 --pos ;
1367 if (pos < 0)
1368 return QTextCursor();
1369 }
1370
1372 QTextBlock block = d->blocksFind(pos);
1373 int blockOffset = pos - block.position();
1374
1375 if (!(options & FindBackward)) {
1376 while (block.isValid()) {
1377 if (findInBlock(block, subString, blockOffset, options, &cursor))
1378 return cursor;
1379 block = block.next();
1380 blockOffset = 0;
1381 }
1382 } else {
1383 if (blockOffset == block.length() - 1)
1384 --blockOffset; // make sure to skip end-of-paragraph character
1385 while (block.isValid()) {
1386 if (findInBlock(block, subString, blockOffset, options, &cursor))
1387 return cursor;
1388 block = block.previous();
1389 blockOffset = block.length() - 2;
1390 }
1391 }
1392
1393 return QTextCursor();
1394}
1395
1411QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &cursor, FindFlags options) const
1412{
1413 int pos = 0;
1414 if (!cursor.isNull()) {
1415 if (options & QTextDocument::FindBackward)
1416 pos = cursor.selectionStart();
1417 else
1418 pos = cursor.selectionEnd();
1419 }
1420
1421 return find(subString, pos, options);
1422}
1423
1424#if QT_CONFIG(regularexpression)
1425static bool findInBlock(const QTextBlock &block, const QRegularExpression &expr, int offset,
1426 QTextDocument::FindFlags options, QTextCursor *cursor)
1427{
1428 QString text = block.text();
1429 text.replace(QChar::Nbsp, u' ');
1431 int idx = -1;
1432
1433 while (offset >= 0 && offset <= text.size()) {
1434 idx = (options & QTextDocument::FindBackward) ?
1435 text.lastIndexOf(expr, offset, &match) : text.indexOf(expr, offset, &match);
1436 if (idx == -1)
1437 return false;
1438
1439 if (options & QTextDocument::FindWholeWords) {
1440 const int start = idx;
1441 const int end = start + match.capturedLength();
1442 if ((start != 0 && text.at(start - 1).isLetterOrNumber())
1443 || (end != text.size() && text.at(end).isLetterOrNumber())) {
1444 //if this is not a whole word, continue the search in the string
1445 offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;
1446 idx = -1;
1447 continue;
1448 }
1449 }
1450 //we have a hit, return the cursor for that.
1452 block.position() + idx);
1453 cursor->setPosition(cursor->position() + match.capturedLength(), QTextCursor::KeepAnchor);
1454 return true;
1455 }
1456 return false;
1457}
1458
1475QTextCursor QTextDocument::find(const QRegularExpression &expr, int from, FindFlags options) const
1476{
1477 Q_D(const QTextDocument);
1478
1479 if (!expr.isValid())
1480 return QTextCursor();
1481
1482 int pos = from;
1483 //the cursor is positioned between characters, so for a backward search
1484 //do not include the character given in the position.
1485 if (options & FindBackward) {
1486 --pos ;
1487 if (pos < 0)
1488 return QTextCursor();
1489 }
1490
1492 QTextBlock block = d->blocksFind(pos);
1493 int blockOffset = pos - block.position();
1494
1495 QRegularExpression expression(expr);
1496 if (!(options & QTextDocument::FindCaseSensitively))
1497 expression.setPatternOptions(expr.patternOptions() | QRegularExpression::CaseInsensitiveOption);
1498 else
1499 expression.setPatternOptions(expr.patternOptions() & ~QRegularExpression::CaseInsensitiveOption);
1500
1501 if (!(options & FindBackward)) {
1502 while (block.isValid()) {
1503 if (findInBlock(block, expression, blockOffset, options, &cursor))
1504 return cursor;
1505 block = block.next();
1506 blockOffset = 0;
1507 }
1508 } else {
1509 while (block.isValid()) {
1510 if (findInBlock(block, expression, blockOffset, options, &cursor))
1511 return cursor;
1512 block = block.previous();
1513 blockOffset = block.length() - 1;
1514 }
1515 }
1516
1517 return QTextCursor();
1518}
1519
1539QTextCursor QTextDocument::find(const QRegularExpression &expr, const QTextCursor &cursor, FindFlags options) const
1540{
1541 int pos = 0;
1542 if (!cursor.isNull()) {
1543 if (options & QTextDocument::FindBackward)
1544 pos = cursor.selectionStart();
1545 else
1546 pos = cursor.selectionEnd();
1547 }
1548 return find(expr, pos, options);
1549}
1550#endif // QT_CONFIG(regularexpression)
1551
1562{
1563 QTextObject *obj = nullptr;
1564 if (f.isListFormat())
1565 obj = new QTextList(this);
1566 else if (f.isTableFormat())
1567 obj = new QTextTable(this);
1568 else if (f.isFrameFormat())
1569 obj = new QTextFrame(this);
1570
1571 return obj;
1572}
1573
1580{
1581 Q_D(const QTextDocument);
1582 return d->frameAt(pos);
1583}
1584
1589{
1590 Q_D(const QTextDocument);
1591 return d->rootFrame();
1592}
1593
1597QTextObject *QTextDocument::object(int objectIndex) const
1598{
1599 Q_D(const QTextDocument);
1600 return d->objectForIndex(objectIndex);
1601}
1602
1607{
1608 Q_D(const QTextDocument);
1609 return d->objectForFormat(f);
1610}
1611
1612
1617{
1618 Q_D(const QTextDocument);
1619 return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(pos));
1620}
1621
1629{
1630 Q_D(const QTextDocument);
1631 return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(blockNumber, 1));
1632}
1633
1641{
1642 Q_D(const QTextDocument);
1643 return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(lineNumber, 2));
1644}
1645
1652{
1653 Q_D(const QTextDocument);
1654 return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().begin().n);
1655}
1656
1670{
1671 Q_D(const QTextDocument);
1672 return QTextBlock(const_cast<QTextDocumentPrivate *>(d), 0);
1673}
1674
1680{
1681 Q_D(const QTextDocument);
1682 return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().begin().n);
1683}
1684
1690{
1691 Q_D(const QTextDocument);
1692 return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().last().n);
1693}
1694
1710{
1711 Q_D(QTextDocument);
1712 d->pageSize = size;
1713 if (d->lout)
1714 d->lout->documentChanged(0, 0, d->length());
1715}
1716
1718{
1719 Q_D(const QTextDocument);
1720 return d->pageSize;
1721}
1722
1727{
1728 return documentLayout()->pageCount();
1729}
1730
1735{
1736 Q_D(QTextDocument);
1737 d->setDefaultFont(font);
1738 if (d->lout)
1739 d->lout->documentChanged(0, 0, d->length());
1740}
1741
1746{
1747 Q_D(const QTextDocument);
1748 return d->defaultFont();
1749}
1750
1761{
1762 Q_D(QTextDocument);
1763 d->formats.setSuperScriptBaseline(baseline);
1764}
1765
1775{
1776 Q_D(const QTextDocument);
1777 return d->formats.defaultTextFormat().superScriptBaseline();
1778}
1779
1790{
1791 Q_D(QTextDocument);
1792 d->formats.setSubScriptBaseline(baseline);
1793}
1794
1804{
1805 Q_D(const QTextDocument);
1806 return d->formats.defaultTextFormat().subScriptBaseline();
1807}
1808
1820{
1821 Q_D(QTextDocument);
1822 d->formats.setBaselineOffset(baseline);
1823}
1824
1835{
1836 Q_D(const QTextDocument);
1837 return d->formats.defaultTextFormat().baselineOffset();
1838}
1839
1864{
1865 Q_D(const QTextDocument);
1866 return d->isModified();
1867}
1868
1870{
1871 Q_D(QTextDocument);
1872 d->setModified(m);
1873}
1874
1875#ifndef QT_NO_PRINTER
1876static void printPage(int index, QPainter *painter, const QTextDocument *doc, const QRectF &body, const QPointF &pageNumberPos)
1877{
1878 painter->save();
1879 painter->translate(body.left(), body.top() - (index - 1) * body.height());
1880 QRectF view(0, (index - 1) * body.height(), body.width(), body.height());
1881
1884
1886 ctx.clip = view;
1887
1888 // don't use the system palette text as default text color, on HP/UX
1889 // for example that's white, and white text on white paper doesn't
1890 // look that nice
1891 ctx.palette.setColor(QPalette::Text, Qt::black);
1892
1893 layout->draw(painter, ctx);
1894
1895 if (!pageNumberPos.isNull()) {
1896 painter->setClipping(false);
1897 painter->setFont(QFont(doc->defaultFont()));
1898 const QString pageString = QString::number(index);
1899
1900 painter->drawText(qRound(pageNumberPos.x() - painter->fontMetrics().horizontalAdvance(pageString)),
1901 qRound(pageNumberPos.y() + view.top()),
1902 pageString);
1903 }
1904
1905 painter->restore();
1906}
1907
1927{
1928 Q_D(const QTextDocument);
1929
1930 if (!printer)
1931 return;
1932
1933 bool documentPaginated = d->pageSize.isValid() && !d->pageSize.isNull()
1934 && d->pageSize.height() != INT_MAX;
1935
1936 // ### set page size to paginated size?
1938 if (!documentPaginated && m.left() == 0. && m.right() == 0. && m.top() == 0. && m.bottom() == 0.) {
1939 m.setLeft(2);
1940 m.setRight(2);
1941 m.setTop(2);
1942 m.setBottom(2);
1944 }
1945 // ### use the margins correctly
1946
1947 QPainter p(printer);
1948
1949 // Check that there is a valid device to print to.
1950 if (!p.isActive())
1951 return;
1952
1953 const QTextDocument *doc = this;
1955 (void)doc->documentLayout(); // make sure that there is a layout
1956
1957 QRectF body = QRectF(QPointF(0, 0), d->pageSize);
1958 QPointF pageNumberPos;
1959
1960 qreal sourceDpiX = qt_defaultDpiX();
1961 qreal sourceDpiY = qt_defaultDpiY();
1962 const qreal dpiScaleX = qreal(printer->logicalDpiX()) / sourceDpiX;
1963 const qreal dpiScaleY = qreal(printer->logicalDpiY()) / sourceDpiY;
1964
1965 if (documentPaginated) {
1966
1967 QPaintDevice *dev = doc->documentLayout()->paintDevice();
1968 if (dev) {
1969 sourceDpiX = dev->logicalDpiX();
1970 sourceDpiY = dev->logicalDpiY();
1971 }
1972
1973 // scale to dpi
1974 p.scale(dpiScaleX, dpiScaleY);
1975
1976 QSizeF scaledPageSize = d->pageSize;
1977 scaledPageSize.rwidth() *= dpiScaleX;
1978 scaledPageSize.rheight() *= dpiScaleY;
1979
1980 const QSizeF printerPageSize(printer->width(), printer->height());
1981
1982 // scale to page
1983 p.scale(printerPageSize.width() / scaledPageSize.width(),
1984 printerPageSize.height() / scaledPageSize.height());
1985 } else {
1986 doc = clone(const_cast<QTextDocument *>(this));
1987 clonedDoc.reset(const_cast<QTextDocument *>(doc));
1988
1989 for (QTextBlock srcBlock = firstBlock(), dstBlock = clonedDoc->firstBlock();
1990 srcBlock.isValid() && dstBlock.isValid();
1991 srcBlock = srcBlock.next(), dstBlock = dstBlock.next()) {
1992 dstBlock.layout()->setFormats(srcBlock.layout()->formats());
1993 }
1994
1996 layout->setPaintDevice(p.device());
1997
1998 // copy the custom object handlers
1999 layout->d_func()->handlers = documentLayout()->d_func()->handlers;
2000
2001 // 2 cm margins, scaled to device in QTextDocumentLayoutPrivate::layoutFrame
2002 const int horizontalMargin = int((2/2.54)*sourceDpiX);
2003 const int verticalMargin = int((2/2.54)*sourceDpiY);
2005 fmt.setLeftMargin(horizontalMargin);
2006 fmt.setRightMargin(horizontalMargin);
2007 fmt.setTopMargin(verticalMargin);
2008 fmt.setBottomMargin(verticalMargin);
2009 doc->rootFrame()->setFrameFormat(fmt);
2010
2011 // pageNumberPos must be in device coordinates, so scale to device here
2012 const int dpiy = p.device()->logicalDpiY();
2013 body = QRectF(0, 0, printer->width(), printer->height());
2014 pageNumberPos = QPointF(body.width() - horizontalMargin * dpiScaleX,
2015 body.height() - verticalMargin * dpiScaleY
2016 + QFontMetrics(doc->defaultFont(), p.device()).ascent()
2017 + 5 * dpiy / 72.0);
2018 clonedDoc->setPageSize(body.size());
2019 }
2020
2021 const QPageRanges pageRanges = printer->pageRanges();
2022 int fromPage = pageRanges.firstPage();
2023 int toPage = pageRanges.lastPage();
2024
2025 if (fromPage == 0 && toPage == 0) {
2026 fromPage = 1;
2027 toPage = doc->pageCount();
2028 }
2029 // paranoia check
2030 fromPage = qMax(1, fromPage);
2031 toPage = qMin(doc->pageCount(), toPage);
2032
2033 if (toPage < fromPage) {
2034 // if the user entered a page range outside the actual number
2035 // of printable pages, just return
2036 return;
2037 }
2038
2039// bool ascending = true;
2040// if (printer->pageOrder() == QPrinter::LastPageFirst) {
2041// int tmp = fromPage;
2042// fromPage = toPage;
2043// toPage = tmp;
2044// ascending = false;
2045// }
2046
2047 int page = fromPage;
2048 while (true) {
2049 if (pageRanges.isEmpty() || pageRanges.contains(page))
2050 printPage(page, &p, doc, body, pageNumberPos);
2051
2052 if (page == toPage)
2053 break;
2054 ++page;
2055 if (!printer->newPage())
2056 return;
2057 }
2058}
2059#endif
2060
2105{
2106 Q_D(const QTextDocument);
2107 const QUrl url = d->baseUrl.resolved(name);
2108 QVariant r = d->resources.value(url);
2109 if (!r.isValid()) {
2110 r = d->cachedResources.value(url);
2111 if (!r.isValid()) {
2112 r = const_cast<QTextDocument *>(this)->loadResource(type, url);
2113 if (!r.isValid()) {
2114 if (d->resourceProvider)
2115 r = d->resourceProvider(url);
2116 else if (auto defaultProvider = defaultResourceProvider())
2117 r = defaultProvider(url);
2118 }
2119 }
2120 }
2121 return r;
2122}
2123
2142void QTextDocument::addResource(int type, const QUrl &name, const QVariant &resource)
2143{
2144 Q_UNUSED(type);
2145 Q_D(QTextDocument);
2146 d->resources.insert(name, resource);
2147}
2148
2157{
2158 Q_D(const QTextDocument);
2159 return d->resourceProvider;
2160}
2161
2177{
2178 Q_D(QTextDocument);
2179 d->resourceProvider = provider;
2180}
2181
2193{
2194 qt_defaultResourceProvider = provider;
2195}
2196
2205{
2206 return qt_defaultResourceProvider;
2207}
2208
2229{
2230 Q_D(QTextDocument);
2231 QVariant r;
2232
2233 QObject *p = parent();
2234 if (p) {
2235 const QMetaObject *me = p->metaObject();
2236 int index = me->indexOfMethod("loadResource(int,QUrl)");
2237 if (index >= 0) {
2239 // don't invoke() via a queued connection: this function needs to return a value
2241 }
2242 }
2243
2244 // handle data: URLs
2245 if (r.isNull() && name.scheme().compare("data"_L1, Qt::CaseInsensitive) == 0) {
2246 QString mimetype;
2247 QByteArray payload;
2248 if (qDecodeDataUrl(name, mimetype, payload))
2249 r = payload;
2250 }
2251
2252 // if resource was not loaded try to load it here
2253 if (!qobject_cast<QTextDocument *>(p) && r.isNull()) {
2254 QUrl resourceUrl = name;
2255
2256 if (name.isRelative()) {
2257 QUrl currentURL = d->url;
2258 // For the second case QUrl can merge "#someanchor" with "foo.html"
2259 // correctly to "foo.html#someanchor"
2260 if (!(currentURL.isRelative()
2261 || (currentURL.scheme() == "file"_L1
2262 && !QFileInfo(currentURL.toLocalFile()).isAbsolute()))
2263 || (name.hasFragment() && name.path().isEmpty())) {
2264 resourceUrl = currentURL.resolved(name);
2265 } else {
2266 // this is our last resort when current url and new url are both relative
2267 // we try to resolve against the current working directory in the local
2268 // file system.
2269 QFileInfo fi(currentURL.toLocalFile());
2270 if (fi.exists()) {
2271 resourceUrl =
2273 } else if (currentURL.isEmpty()) {
2274 resourceUrl.setScheme("file"_L1);
2275 }
2276 }
2277 }
2278
2279 QString s = resourceUrl.toLocalFile();
2280 QFile f(s);
2281 if (!s.isEmpty() && f.open(QFile::ReadOnly)) {
2282 r = f.readAll();
2283 f.close();
2284 }
2285 }
2286
2287 if (!r.isNull()) {
2288 if (type == ImageResource && r.userType() == QMetaType::QByteArray) {
2289 if (qApp->thread() != QThread::currentThread()) {
2290 // must use images in non-GUI threads
2291 QImage image;
2292 image.loadFromData(r.toByteArray());
2293 if (!image.isNull())
2294 r = image;
2295 } else {
2296 QPixmap pm;
2297 pm.loadFromData(r.toByteArray());
2298 if (!pm.isNull())
2299 r = pm;
2300 }
2301 }
2302 d->cachedResources.insert(name, r);
2303 }
2304 return r;
2305}
2306
2308{
2309 QTextFormat diff = to;
2310
2313 it != end; ++it)
2314 if (it.value() == from.property(it.key()))
2315 diff.clearProperty(it.key());
2316
2317 return diff;
2318}
2319
2321{
2323
2324 if (color.alpha() == 255) {
2325 result = color.name();
2326 } else if (color.alpha()) {
2327 QString alphaValue = QString::number(color.alphaF(), 'f', 6);
2328 while (alphaValue.size() > 1 && alphaValue.at(alphaValue.size() - 1) == u'0')
2329 alphaValue.chop(1);
2330 if (alphaValue.at(alphaValue.size() - 1) == u'.')
2331 alphaValue.chop(1);
2332 result = QString::fromLatin1("rgba(%1,%2,%3,%4)").arg(color.red())
2333 .arg(color.green())
2334 .arg(color.blue())
2335 .arg(alphaValue);
2336 } else {
2337 result = "transparent"_L1;
2338 }
2339
2340 return result;
2341}
2342
2344 : doc(_doc), fragmentMarkers(false)
2345{
2346 const QFont defaultFont = doc->defaultFont();
2347 defaultCharFormat.setFont(defaultFont);
2348}
2349
2351{
2352 return format.fontFamilies().toStringList();
2353}
2354
2361{
2362 html = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
2363 "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
2364 "<html><head><meta name=\"qrichtext\" content=\"1\" />"_L1;
2366
2367 fragmentMarkers = (mode == ExportFragment);
2368
2369 html += QString::fromLatin1("<meta charset=\"utf-8\" />");
2370
2372 if (!title.isEmpty())
2373 html += QString::fromLatin1("<title>") + title + QString::fromLatin1("</title>");
2374 html += "<style type=\"text/css\">\n"_L1;
2375 html += "p, li { white-space: pre-wrap; }\n"_L1;
2376 html += "hr { height: 1px; border-width: 0; }\n"_L1;
2377 html += "li.unchecked::marker { content: \"\\2610\"; }\n"_L1;
2378 html += "li.checked::marker { content: \"\\2612\"; }\n"_L1;
2379 html += "</style>"_L1;
2380 html += "</head><body"_L1;
2381
2382 if (mode == ExportEntireDocument) {
2383 html += " style=\""_L1;
2384
2385 emitFontFamily(resolvedFontFamilies(defaultCharFormat));
2386
2387 if (defaultCharFormat.hasProperty(QTextFormat::FontPointSize)) {
2388 html += " font-size:"_L1;
2389 html += QString::number(defaultCharFormat.fontPointSize());
2390 html += "pt;"_L1;
2391 } else if (defaultCharFormat.hasProperty(QTextFormat::FontPixelSize)) {
2392 html += " font-size:"_L1;
2393 html += QString::number(defaultCharFormat.intProperty(QTextFormat::FontPixelSize));
2394 html += "px;"_L1;
2395 }
2396
2397 html += " font-weight:"_L1;
2398 html += QString::number(defaultCharFormat.fontWeight());
2399 html += u';';
2400
2401 html += " font-style:"_L1;
2402 html += (defaultCharFormat.fontItalic() ? "italic"_L1 : "normal"_L1);
2403 html += u';';
2404
2405 const bool percentSpacing = (defaultCharFormat.fontLetterSpacingType() == QFont::PercentageSpacing);
2406 if (defaultCharFormat.hasProperty(QTextFormat::FontLetterSpacing) &&
2407 (!percentSpacing || defaultCharFormat.fontLetterSpacing() != 0.0)) {
2408 html += " letter-spacing:"_L1;
2409 qreal value = defaultCharFormat.fontLetterSpacing();
2410 if (percentSpacing) // Map to em (100% == 0em)
2411 value = (value / 100) - 1;
2412 html += QString::number(value);
2413 html += percentSpacing ? "em;"_L1 : "px;"_L1;
2414 }
2415
2416 if (defaultCharFormat.hasProperty(QTextFormat::FontWordSpacing) &&
2417 defaultCharFormat.fontWordSpacing() != 0.0) {
2418 html += " word-spacing:"_L1;
2419 html += QString::number(defaultCharFormat.fontWordSpacing());
2420 html += "px;"_L1;
2421 }
2422
2423 QString decorationTag(" text-decoration:"_L1);
2424 bool atLeastOneDecorationSet = false;
2425 if (defaultCharFormat.hasProperty(QTextFormat::FontUnderline) || defaultCharFormat.hasProperty(QTextFormat::TextUnderlineStyle)) {
2426 if (defaultCharFormat.fontUnderline()) {
2427 decorationTag += " underline"_L1;
2428 atLeastOneDecorationSet = true;
2429 }
2430 }
2431 if (defaultCharFormat.hasProperty(QTextFormat::FontOverline)) {
2432 if (defaultCharFormat.fontOverline()) {
2433 decorationTag += " overline"_L1;
2434 atLeastOneDecorationSet = true;
2435 }
2436 }
2437 if (defaultCharFormat.hasProperty(QTextFormat::FontStrikeOut)) {
2438 if (defaultCharFormat.fontStrikeOut()) {
2439 decorationTag += " line-through"_L1;
2440 atLeastOneDecorationSet = true;
2441 }
2442 }
2443 if (atLeastOneDecorationSet)
2444 html += decorationTag + u';';
2445
2446 html += u'\"';
2447
2448 const QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
2449 emitBackgroundAttribute(fmt);
2450
2451 } else {
2452 defaultCharFormat = QTextCharFormat();
2453 }
2454 html += u'>';
2455
2456 QTextFrameFormat rootFmt = doc->rootFrame()->frameFormat();
2458
2459 QTextFrameFormat defaultFmt;
2460 defaultFmt.setMargin(doc->documentMargin());
2461
2462 if (rootFmt == defaultFmt)
2463 emitFrame(doc->rootFrame()->begin());
2464 else
2465 emitTextFrame(doc->rootFrame());
2466
2467 html += "</body></html>"_L1;
2468 return html;
2469}
2470
2471void QTextHtmlExporter::emitAttribute(const char *attribute, const QString &value)
2472{
2473 html += u' ';
2475 html += "=\""_L1;
2476 html += value.toHtmlEscaped();
2477 html += u'"';
2478}
2479
2480bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
2481{
2482 bool attributesEmitted = false;
2483
2484 {
2485 const QStringList families = resolvedFontFamilies(format);
2486 if (!families.isEmpty() && families != resolvedFontFamilies(defaultCharFormat)) {
2487 emitFontFamily(families);
2488 attributesEmitted = true;
2489 }
2490 }
2491
2492 if (format.hasProperty(QTextFormat::FontPointSize)
2493 && format.fontPointSize() != defaultCharFormat.fontPointSize()) {
2494 html += " font-size:"_L1;
2495 html += QString::number(format.fontPointSize());
2496 html += "pt;"_L1;
2497 attributesEmitted = true;
2498 } else if (format.hasProperty(QTextFormat::FontSizeAdjustment)) {
2499 static const char sizeNameData[] =
2500 "small" "\0"
2501 "medium" "\0"
2502 "xx-large" ;
2503 static const quint8 sizeNameOffsets[] = {
2504 0, // "small"
2505 sizeof("small"), // "medium"
2506 sizeof("small") + sizeof("medium") + 3, // "large" )
2507 sizeof("small") + sizeof("medium") + 1, // "x-large" )> compressed into "xx-large"
2508 sizeof("small") + sizeof("medium"), // "xx-large" )
2509 };
2510 const char *name = nullptr;
2511 const int idx = format.intProperty(QTextFormat::FontSizeAdjustment) + 1;
2512 if (idx >= 0 && idx <= 4) {
2513 name = sizeNameData + sizeNameOffsets[idx];
2514 }
2515 if (name) {
2516 html += " font-size:"_L1;
2517 html += QLatin1StringView(name);
2518 html += u';';
2519 attributesEmitted = true;
2520 }
2521 } else if (format.hasProperty(QTextFormat::FontPixelSize)) {
2522 html += " font-size:"_L1;
2524 html += "px;"_L1;
2525 attributesEmitted = true;
2526 }
2527
2528 if (format.hasProperty(QTextFormat::FontWeight)
2529 && format.fontWeight() != defaultCharFormat.fontWeight()) {
2530 html += " font-weight:"_L1;
2531 html += QString::number(format.fontWeight());
2532 html += u';';
2533 attributesEmitted = true;
2534 }
2535
2536 if (format.hasProperty(QTextFormat::FontItalic)
2537 && format.fontItalic() != defaultCharFormat.fontItalic()) {
2538 html += " font-style:"_L1;
2539 html += (format.fontItalic() ? "italic"_L1 : "normal"_L1);
2540 html += u';';
2541 attributesEmitted = true;
2542 }
2543
2544 const auto decorationTag = " text-decoration:"_L1;
2545 html += decorationTag;
2546 bool hasDecoration = false;
2547 bool atLeastOneDecorationSet = false;
2548
2550 && format.fontUnderline() != defaultCharFormat.fontUnderline()) {
2551 hasDecoration = true;
2552 if (format.fontUnderline()) {
2553 html += " underline"_L1;
2554 atLeastOneDecorationSet = true;
2555 }
2556 }
2557
2558 if (format.hasProperty(QTextFormat::FontOverline)
2559 && format.fontOverline() != defaultCharFormat.fontOverline()) {
2560 hasDecoration = true;
2561 if (format.fontOverline()) {
2562 html += " overline"_L1;
2563 atLeastOneDecorationSet = true;
2564 }
2565 }
2566
2567 if (format.hasProperty(QTextFormat::FontStrikeOut)
2568 && format.fontStrikeOut() != defaultCharFormat.fontStrikeOut()) {
2569 hasDecoration = true;
2570 if (format.fontStrikeOut()) {
2571 html += " line-through"_L1;
2572 atLeastOneDecorationSet = true;
2573 }
2574 }
2575
2576 if (hasDecoration) {
2577 if (!atLeastOneDecorationSet)
2578 html += "none"_L1;
2579 html += u';';
2580 if (format.hasProperty(QTextFormat::TextUnderlineColor)) {
2581 html += " text-decoration-color:"_L1;
2582 html += colorValue(format.underlineColor());
2583 html += u';';
2584 }
2585 attributesEmitted = true;
2586 } else {
2587 html.chop(decorationTag.size());
2588 }
2589
2590 if (format.foreground() != defaultCharFormat.foreground()
2591 && format.foreground().style() != Qt::NoBrush) {
2592 QBrush brush = format.foreground();
2593 if (brush.style() == Qt::TexturePattern) {
2594 const bool isPixmap = qHasPixmapTexture(brush);
2595 const qint64 cacheKey = isPixmap ? brush.texture().cacheKey() : brush.textureImage().cacheKey();
2596
2597 html += " -qt-fg-texture-cachekey:"_L1;
2598 html += QString::number(cacheKey);
2599 html += ";"_L1;
2600 } else {
2601 html += " color:"_L1;
2602 html += colorValue(brush.color());
2603 html += u';';
2604 }
2605 attributesEmitted = true;
2606 }
2607
2608 if (format.background() != defaultCharFormat.background()
2609 && format.background().style() == Qt::SolidPattern) {
2610 html += " background-color:"_L1;
2611 html += colorValue(format.background().color());
2612 html += u';';
2613 attributesEmitted = true;
2614 }
2615
2616 if (format.verticalAlignment() != defaultCharFormat.verticalAlignment()
2617 && format.verticalAlignment() != QTextCharFormat::AlignNormal)
2618 {
2619 html += " vertical-align:"_L1;
2620
2621 QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
2622 if (valign == QTextCharFormat::AlignSubScript)
2623 html += "sub"_L1;
2624 else if (valign == QTextCharFormat::AlignSuperScript)
2625 html += "super"_L1;
2626 else if (valign == QTextCharFormat::AlignMiddle)
2627 html += "middle"_L1;
2628 else if (valign == QTextCharFormat::AlignTop)
2629 html += "top"_L1;
2630 else if (valign == QTextCharFormat::AlignBottom)
2631 html += "bottom"_L1;
2632
2633 html += u';';
2634 attributesEmitted = true;
2635 }
2636
2637 if (format.fontCapitalization() != QFont::MixedCase) {
2638 const QFont::Capitalization caps = format.fontCapitalization();
2639 if (caps == QFont::AllUppercase)
2640 html += " text-transform:uppercase;"_L1;
2641 else if (caps == QFont::AllLowercase)
2642 html += " text-transform:lowercase;"_L1;
2643 else if (caps == QFont::SmallCaps)
2644 html += " font-variant:small-caps;"_L1;
2645 attributesEmitted = true;
2646 }
2647
2648 if (format.fontWordSpacing() != 0.0) {
2649 html += " word-spacing:"_L1;
2650 html += QString::number(format.fontWordSpacing());
2651 html += "px;"_L1;
2652 attributesEmitted = true;
2653 }
2654
2655 return attributesEmitted;
2656}
2657
2658void QTextHtmlExporter::emitTextLength(const char *attribute, const QTextLength &length)
2659{
2660 if (length.type() == QTextLength::VariableLength) // default
2661 return;
2662
2663 html += u' ';
2665 html += "=\""_L1;
2666 html += QString::number(length.rawValue());
2667
2669 html += "%\""_L1;
2670 else
2671 html += u'\"';
2672}
2673
2674void QTextHtmlExporter::emitAlignment(Qt::Alignment align)
2675{
2676 if (align & Qt::AlignLeft)
2677 return;
2678 else if (align & Qt::AlignRight)
2679 html += " align=\"right\""_L1;
2680 else if (align & Qt::AlignHCenter)
2681 html += " align=\"center\""_L1;
2682 else if (align & Qt::AlignJustify)
2683 html += " align=\"justify\""_L1;
2684}
2685
2686void QTextHtmlExporter::emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode)
2687{
2689 return;
2690
2691 if (mode == EmitStyleTag)
2692 html += " style=\"float:"_L1;
2693 else
2694 html += " float:"_L1;
2695
2697 html += " left;"_L1;
2699 html += " right;"_L1;
2700 else
2701 Q_ASSERT_X(0, "QTextHtmlExporter::emitFloatStyle()", "pos should be a valid enum type");
2702
2703 if (mode == EmitStyleTag)
2704 html += u'\"';
2705}
2706
2708{
2709 switch (style) {
2711 return "none"_L1;
2713 return "dotted"_L1;
2715 return "dashed"_L1;
2717 return "solid"_L1;
2719 return "double"_L1;
2721 return "dot-dash"_L1;
2723 return "dot-dot-dash"_L1;
2725 return "groove"_L1;
2727 return "ridge"_L1;
2729 return "inset"_L1;
2731 return "outset"_L1;
2732 default:
2733 Q_UNREACHABLE();
2734 };
2735 return ""_L1;
2736}
2737
2738void QTextHtmlExporter::emitBorderStyle(QTextFrameFormat::BorderStyle style)
2739{
2741
2742 html += " border-style:"_L1;
2744 html += u';';
2745}
2746
2747void QTextHtmlExporter::emitPageBreakPolicy(QTextFormat::PageBreakFlags policy)
2748{
2750 html += " page-break-before:always;"_L1;
2751
2753 html += " page-break-after:always;"_L1;
2754}
2755
2756void QTextHtmlExporter::emitFontFamily(const QStringList &families)
2757{
2758 html += " font-family:"_L1;
2759
2760 bool first = true;
2761 for (const QString &family : families) {
2762 auto quote = "\'"_L1;
2763 if (family.contains(u'\''))
2764 quote = "&quot;"_L1;
2765
2766 if (!first)
2767 html += ","_L1;
2768 else
2769 first = false;
2770 html += quote;
2771 html += family.toHtmlEscaped();
2772 html += quote;
2773 }
2774 html += u';';
2775}
2776
2777void QTextHtmlExporter::emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right)
2778{
2779 html += " margin-top:"_L1;
2780 html += top;
2781 html += "px;"_L1;
2782
2783 html += " margin-bottom:"_L1;
2784 html += bottom;
2785 html += "px;"_L1;
2786
2787 html += " margin-left:"_L1;
2788 html += left;
2789 html += "px;"_L1;
2790
2791 html += " margin-right:"_L1;
2792 html += right;
2793 html += "px;"_L1;
2794}
2795
2796void QTextHtmlExporter::emitFragment(const QTextFragment &fragment)
2797{
2798 const QTextCharFormat format = fragment.charFormat();
2799
2800 bool closeAnchor = false;
2801
2802 if (format.isAnchor()) {
2803 const auto names = format.anchorNames();
2804 if (!names.isEmpty()) {
2805 html += "<a name=\""_L1;
2806 html += names.constFirst().toHtmlEscaped();
2807 html += "\"></a>"_L1;
2808 }
2809 const QString href = format.anchorHref();
2810 if (!href.isEmpty()) {
2811 html += "<a href=\""_L1;
2812 html += href.toHtmlEscaped();
2813 html += "\">"_L1;
2814 closeAnchor = true;
2815 }
2816 }
2817
2818 QString txt = fragment.text();
2819 const bool isObject = txt.contains(QChar::ObjectReplacementCharacter);
2820 const bool isImage = isObject && format.isImageFormat();
2821
2822 const auto styleTag = "<span style=\""_L1;
2823 html += styleTag;
2824
2825 bool attributesEmitted = false;
2826 if (!isImage)
2827 attributesEmitted = emitCharFormatStyle(format);
2828 if (attributesEmitted)
2829 html += "\">"_L1;
2830 else
2831 html.chop(styleTag.size());
2832
2833 if (isObject) {
2834 for (int i = 0; isImage && i < txt.size(); ++i) {
2836
2837 html += "<img"_L1;
2838
2840 emitAttribute("src", imgFmt.name());
2841
2843 emitAttribute("alt", imgFmt.stringProperty(QTextFormat::ImageAltText));
2844
2846 emitAttribute("title", imgFmt.stringProperty(QTextFormat::ImageTitle));
2847
2849 emitAttribute("width", QString::number(imgFmt.width()));
2850
2852 emitAttribute("height", QString::number(imgFmt.height()));
2853
2855 html += " style=\"vertical-align: middle;\""_L1;
2856 else if (imgFmt.verticalAlignment() == QTextCharFormat::AlignTop)
2857 html += " style=\"vertical-align: top;\""_L1;
2858
2859 if (QTextFrame *imageFrame = qobject_cast<QTextFrame *>(doc->objectForFormat(imgFmt)))
2860 emitFloatStyle(imageFrame->frameFormat().position());
2861
2862 html += " />"_L1;
2863 }
2864 } else {
2866
2867 txt = txt.toHtmlEscaped();
2868
2869 // split for [\n{LineSeparator}]
2870 // space in BR on purpose for compatibility with old-fashioned browsers
2871 txt.replace(u'\n', "<br />"_L1);
2872 txt.replace(QChar::LineSeparator, "<br />"_L1);
2873 html += txt;
2874 }
2875
2876 if (attributesEmitted)
2877 html += "</span>"_L1;
2878
2879 if (closeAnchor)
2880 html += "</a>"_L1;
2881}
2882
2883static bool isOrderedList(int style)
2884{
2889 ;
2890}
2891
2892void QTextHtmlExporter::emitBlockAttributes(const QTextBlock &block)
2893{
2895 emitAlignment(format.alignment());
2896
2897 // assume default to not bloat the html too much
2898 // html += " dir='ltr'"_L1;
2899 if (block.textDirection() == Qt::RightToLeft)
2900 html += " dir='rtl'"_L1;
2901
2902 const auto style = " style=\""_L1;
2903 html += style;
2904
2905 const bool emptyBlock = block.begin().atEnd();
2906 if (emptyBlock) {
2907 html += "-qt-paragraph-type:empty;"_L1;
2908 }
2909
2910 emitMargins(QString::number(format.topMargin()),
2911 QString::number(format.bottomMargin()),
2912 QString::number(format.leftMargin()),
2913 QString::number(format.rightMargin()));
2914
2915 html += " -qt-block-indent:"_L1;
2916 html += QString::number(format.indent());
2917 html += u';';
2918
2919 html += " text-indent:"_L1;
2920 html += QString::number(format.textIndent());
2921 html += "px;"_L1;
2922
2923 if (block.userState() != -1) {
2924 html += " -qt-user-state:"_L1;
2925 html += QString::number(block.userState());
2926 html += u';';
2927 }
2928
2929 if (format.lineHeightType() != QTextBlockFormat::SingleHeight) {
2930 html += " line-height:"_L1
2931 + QString::number(format.lineHeight());
2932 switch (format.lineHeightType()) {
2934 html += "%;"_L1;
2935 break;
2937 html += "; -qt-line-height-type: fixed;"_L1;
2938 break;
2940 html += "px;"_L1;
2941 break;
2943 html += "; -qt-line-height-type: line-distance;"_L1;
2944 break;
2945 default:
2946 html += ";"_L1;
2947 break; // Should never reach here
2948 }
2949 }
2950
2951 emitPageBreakPolicy(format.pageBreakPolicy());
2952
2953 QTextCharFormat diff;
2954 if (emptyBlock) { // only print character properties when we don't expect them to be repeated by actual text in the parag
2955 const QTextCharFormat blockCharFmt = block.charFormat();
2956 diff = formatDifference(defaultCharFormat, blockCharFmt).toCharFormat();
2957 }
2958
2960 if (format.hasProperty(QTextFormat::BackgroundBrush)) {
2961 QBrush bg = format.background();
2962 if (bg.style() != Qt::NoBrush)
2964 }
2965
2966 if (!diff.properties().isEmpty())
2967 emitCharFormatStyle(diff);
2968
2969 html += u'"';
2970
2971}
2972
2973void QTextHtmlExporter::emitBlock(const QTextBlock &block)
2974{
2975 if (block.begin().atEnd()) {
2976 // ### HACK, remove once QTextFrame::Iterator is fixed
2977 int p = block.position();
2978 if (p > 0)
2979 --p;
2980
2982 QChar ch = QTextDocumentPrivate::get(doc)->buffer().at(frag->stringPosition);
2984 || ch == QTextEndOfFrame)
2985 return;
2986 }
2987
2988 html += u'\n';
2989
2990 // save and later restore, in case we 'change' the default format by
2991 // emitting block char format information
2992 QTextCharFormat oldDefaultCharFormat = defaultCharFormat;
2993
2994 QTextList *list = block.textList();
2995 if (list) {
2996 if (list->itemNumber(block) == 0) { // first item? emit <ul> or appropriate
2997 const QTextListFormat format = list->format();
2998 const int style = format.style();
2999 bool ordered = false;
3000 switch (style) {
3001 case QTextListFormat::ListDisc: html += "<ul"_L1; break;
3002 case QTextListFormat::ListCircle: html += "<ul type=\"circle\""_L1; break;
3003 case QTextListFormat::ListSquare: html += "<ul type=\"square\""_L1; break;
3004 case QTextListFormat::ListDecimal: html += "<ol"_L1; ordered = true; break;
3005 case QTextListFormat::ListLowerAlpha: html += "<ol type=\"a\""_L1; ordered = true; break;
3006 case QTextListFormat::ListUpperAlpha: html += "<ol type=\"A\""_L1; ordered = true; break;
3007 case QTextListFormat::ListLowerRoman: html += "<ol type=\"i\""_L1; ordered = true; break;
3008 case QTextListFormat::ListUpperRoman: html += "<ol type=\"I\""_L1; ordered = true; break;
3009 default: html += "<ul"_L1; // ### should not happen
3010 }
3011
3012 if (ordered && format.start() != 1) {
3013 html += " start=\""_L1;
3014 html += QString::number(format.start());
3015 html += u'"';
3016 }
3017
3018 QString styleString = QString::fromLatin1("margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px;");
3019
3020 if (format.hasProperty(QTextFormat::ListIndent)) {
3021 styleString += " -qt-list-indent: "_L1;
3022 styleString += QString::number(format.indent());
3023 styleString += u';';
3024 }
3025
3026 if (format.hasProperty(QTextFormat::ListNumberPrefix)) {
3027 QString numberPrefix = format.numberPrefix();
3028 numberPrefix.replace(u'"', "\\22"_L1);
3029 numberPrefix.replace(u'\'', "\\27"_L1); // FIXME: There's a problem in the CSS parser the prevents this from being correctly restored
3030 styleString += " -qt-list-number-prefix: "_L1;
3031 styleString += u'\'';
3032 styleString += numberPrefix;
3033 styleString += u'\'';
3034 styleString += u';';
3035 }
3036
3037 if (format.hasProperty(QTextFormat::ListNumberSuffix)) {
3038 if (format.numberSuffix() != "."_L1) { // this is our default
3039 QString numberSuffix = format.numberSuffix();
3040 numberSuffix.replace(u'"', "\\22"_L1);
3041 numberSuffix.replace(u'\'', "\\27"_L1); // see above
3042 styleString += " -qt-list-number-suffix: "_L1;
3043 styleString += u'\'';
3044 styleString += numberSuffix;
3045 styleString += u'\'';
3046 styleString += u';';
3047 }
3048 }
3049
3050 html += " style=\""_L1;
3051 html += styleString;
3052 html += "\">\n"_L1;
3053 }
3054
3055 html += "<li"_L1;
3056
3057 const QTextCharFormat blockFmt = formatDifference(defaultCharFormat, block.charFormat()).toCharFormat();
3058 if (!blockFmt.properties().isEmpty()) {
3059 html += " style=\""_L1;
3060 emitCharFormatStyle(blockFmt);
3061 html += u'\"';
3062
3063 defaultCharFormat.merge(block.charFormat());
3064 }
3066 switch (block.blockFormat().marker()) {
3068 html += " class=\"checked\""_L1;
3069 break;
3071 html += " class=\"unchecked\""_L1;
3072 break;
3074 break;
3075 }
3076 }
3077 }
3078
3079 const QTextBlockFormat blockFormat = block.blockFormat();
3081 html += "<hr"_L1;
3082
3084 if (width.type() != QTextLength::VariableLength)
3085 emitTextLength("width", width);
3086 html += u' ';
3087
3088 if (blockFormat.hasProperty(QTextFormat::BackgroundBrush)) {
3089 html += "style=\""_L1;
3090 html += "background-color:"_L1;
3091 html += colorValue(qvariant_cast<QBrush>(blockFormat.property(QTextFormat::BackgroundBrush)).color());
3092 html += u';';
3093 html += u'\"';
3094 }
3095
3096 html += "/>"_L1;
3097 return;
3098 }
3099
3100 const bool pre = blockFormat.nonBreakableLines();
3101 if (pre) {
3102 if (list)
3103 html += u'>';
3104 html += "<pre"_L1;
3105 } else if (!list) {
3106 int headingLevel = blockFormat.headingLevel();
3107 if (headingLevel > 0 && headingLevel <= 6)
3108 html += "<h"_L1 + QString::number(headingLevel);
3109 else
3110 html += "<p"_L1;
3111 }
3112
3113 emitBlockAttributes(block);
3114
3115 html += u'>';
3116 if (block.begin().atEnd())
3117 html += "<br />"_L1;
3118
3119 QTextBlock::Iterator it = block.begin();
3120 if (fragmentMarkers && !it.atEnd() && block == doc->begin())
3121 html += "<!--StartFragment-->"_L1;
3122
3123 for (; !it.atEnd(); ++it)
3124 emitFragment(it.fragment());
3125
3126 if (fragmentMarkers && block.position() + block.length() == QTextDocumentPrivate::get(doc)->length())
3127 html += "<!--EndFragment-->"_L1;
3128
3129 QString closeTags;
3130
3131 if (pre)
3132 html += "</pre>"_L1;
3133 else if (list)
3134 closeTags += "</li>"_L1;
3135 else {
3136 int headingLevel = blockFormat.headingLevel();
3137 if (headingLevel > 0 && headingLevel <= 6)
3138 html += QString::asprintf("</h%d>", headingLevel);
3139 else
3140 html += "</p>"_L1;
3141 }
3142
3143 if (list) {
3144 if (list->itemNumber(block) == list->count() - 1) { // last item? close list
3145 if (isOrderedList(list->format().style()))
3146 closeTags += "</ol>"_L1;
3147 else
3148 closeTags += "</ul>"_L1;
3149 }
3150 const QTextBlock nextBlock = block.next();
3151 // If the next block is the beginning of a new deeper nested list, then we don't
3152 // want to close the current list item just yet. This should be closed when this
3153 // item is fully finished
3154 if (nextBlock.isValid() && nextBlock.textList() &&
3155 nextBlock.textList()->itemNumber(nextBlock) == 0 &&
3156 nextBlock.textList()->format().indent() > list->format().indent()) {
3157 QString lastTag;
3158 if (!closingTags.isEmpty() && list->itemNumber(block) == list->count() - 1)
3159 lastTag = closingTags.takeLast();
3160 lastTag.prepend(closeTags);
3161 closingTags << lastTag;
3162 } else if (list->itemNumber(block) == list->count() - 1) {
3163 // If we are at the end of the list now then we can add in the closing tags for that
3164 // current block
3165 html += closeTags;
3166 if (!closingTags.isEmpty())
3167 html += closingTags.takeLast();
3168 } else {
3169 html += closeTags;
3170 }
3171 }
3172
3173 defaultCharFormat = oldDefaultCharFormat;
3174}
3175
3176extern bool qHasPixmapTexture(const QBrush& brush);
3177
3178QString QTextHtmlExporter::findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap)
3179{
3180 QString url;
3181 if (!doc)
3182 return url;
3183
3184 if (QTextDocument *parent = qobject_cast<QTextDocument *>(doc->parent()))
3185 return findUrlForImage(parent, cacheKey, isPixmap);
3186
3188 Q_ASSERT(priv != nullptr);
3189
3190 QMap<QUrl, QVariant>::const_iterator it = priv->cachedResources.constBegin();
3191 for (; it != priv->cachedResources.constEnd(); ++it) {
3192
3193 const QVariant &v = it.value();
3194 if (v.userType() == QMetaType::QImage && !isPixmap) {
3195 if (qvariant_cast<QImage>(v).cacheKey() == cacheKey)
3196 break;
3197 }
3198
3199 if (v.userType() == QMetaType::QPixmap && isPixmap) {
3200 if (qvariant_cast<QPixmap>(v).cacheKey() == cacheKey)
3201 break;
3202 }
3203 }
3204
3205 if (it != priv->cachedResources.constEnd())
3206 url = it.key().toString();
3207
3208 return url;
3209}
3210
3212{
3213 if (!priv)
3214 return;
3215
3216 cachedResources.insert(priv->cachedResources);
3217}
3218
3219void QTextHtmlExporter::emitBackgroundAttribute(const QTextFormat &format)
3220{
3221 if (format.hasProperty(QTextFormat::BackgroundImageUrl)) {
3223 emitAttribute("background", url);
3224 } else {
3225 const QBrush &brush = format.background();
3226 if (brush.style() == Qt::SolidPattern) {
3227 emitAttribute("bgcolor", colorValue(brush.color()));
3228 } else if (brush.style() == Qt::TexturePattern) {
3229 const bool isPixmap = qHasPixmapTexture(brush);
3230 const qint64 cacheKey = isPixmap ? brush.texture().cacheKey() : brush.textureImage().cacheKey();
3231
3232 const QString url = findUrlForImage(doc, cacheKey, isPixmap);
3233
3234 if (!url.isEmpty())
3235 emitAttribute("background", url);
3236 }
3237 }
3238}
3239
3240void QTextHtmlExporter::emitTable(const QTextTable *table)
3241{
3242 QTextTableFormat format = table->format();
3243
3244 html += "\n<table"_L1;
3245
3246 if (format.hasProperty(QTextFormat::FrameBorder))
3247 emitAttribute("border", QString::number(format.border()));
3248
3249 emitFrameStyle(format, TableFrame);
3250
3251 emitAlignment(format.alignment());
3252 emitTextLength("width", format.width());
3253
3254 if (format.hasProperty(QTextFormat::TableCellSpacing))
3255 emitAttribute("cellspacing", QString::number(format.cellSpacing()));
3256 if (format.hasProperty(QTextFormat::TableCellPadding))
3257 emitAttribute("cellpadding", QString::number(format.cellPadding()));
3258
3259 emitBackgroundAttribute(format);
3260
3261 html += u'>';
3262
3263 const int rows = table->rows();
3264 const int columns = table->columns();
3265
3266 QList<QTextLength> columnWidths = format.columnWidthConstraints();
3267 if (columnWidths.isEmpty()) {
3268 columnWidths.resize(columns);
3269 columnWidths.fill(QTextLength());
3270 }
3271 Q_ASSERT(columnWidths.size() == columns);
3272
3273 QVarLengthArray<bool> widthEmittedForColumn(columns);
3274 for (int i = 0; i < columns; ++i)
3275 widthEmittedForColumn[i] = false;
3276
3277 const int headerRowCount = qMin(format.headerRowCount(), rows);
3278 if (headerRowCount > 0)
3279 html += "<thead>"_L1;
3280
3281 for (int row = 0; row < rows; ++row) {
3282 html += "\n<tr>"_L1;
3283
3284 for (int col = 0; col < columns; ++col) {
3285 const QTextTableCell cell = table->cellAt(row, col);
3286
3287 // for col/rowspans
3288 if (cell.row() != row)
3289 continue;
3290
3291 if (cell.column() != col)
3292 continue;
3293
3294 html += "\n<td"_L1;
3295
3296 if (!widthEmittedForColumn[col] && cell.columnSpan() == 1) {
3297 emitTextLength("width", columnWidths.at(col));
3298 widthEmittedForColumn[col] = true;
3299 }
3300
3301 if (cell.columnSpan() > 1)
3302 emitAttribute("colspan", QString::number(cell.columnSpan()));
3303
3304 if (cell.rowSpan() > 1)
3305 emitAttribute("rowspan", QString::number(cell.rowSpan()));
3306
3307 const QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
3308 emitBackgroundAttribute(cellFormat);
3309
3310 QTextCharFormat oldDefaultCharFormat = defaultCharFormat;
3311
3313
3314 QString styleString;
3316 styleString += " vertical-align:"_L1;
3317 switch (valign) {
3319 styleString += "middle"_L1;
3320 break;
3322 styleString += "top"_L1;
3323 break;
3325 styleString += "bottom"_L1;
3326 break;
3327 default:
3328 break;
3329 }
3330 styleString += u';';
3331
3332 QTextCharFormat temp;
3333 temp.setVerticalAlignment(valign);
3334 defaultCharFormat.merge(temp);
3335 }
3336
3338 styleString += " padding-left:"_L1 + QString::number(cellFormat.leftPadding()) + u';';
3340 styleString += " padding-right:"_L1 + QString::number(cellFormat.rightPadding()) + u';';
3342 styleString += " padding-top:"_L1 + QString::number(cellFormat.topPadding()) + u';';
3344 styleString += " padding-bottom:"_L1 + QString::number(cellFormat.bottomPadding()) + u';';
3345
3347 styleString += " border-top:"_L1 + QString::number(cellFormat.topBorder()) + "px;"_L1;
3349 styleString += " border-right:"_L1 + QString::number(cellFormat.rightBorder()) + "px;"_L1;
3351 styleString += " border-bottom:"_L1 + QString::number(cellFormat.bottomBorder()) + "px;"_L1;
3353 styleString += " border-left:"_L1 + QString::number(cellFormat.leftBorder()) + "px;"_L1;
3354
3356 styleString += " border-top-color:"_L1 + cellFormat.topBorderBrush().color().name() + u';';
3358 styleString += " border-right-color:"_L1 + cellFormat.rightBorderBrush().color().name() + u';';
3360 styleString += " border-bottom-color:"_L1 + cellFormat.bottomBorderBrush().color().name() + u';';
3362 styleString += " border-left-color:"_L1 + cellFormat.leftBorderBrush().color().name() + u';';
3363
3365 styleString += " border-top-style:"_L1 + richtextBorderStyleToHtmlBorderStyle(cellFormat.topBorderStyle()) + u';';
3367 styleString += " border-right-style:"_L1 + richtextBorderStyleToHtmlBorderStyle(cellFormat.rightBorderStyle()) + u';';
3369 styleString += " border-bottom-style:"_L1 + richtextBorderStyleToHtmlBorderStyle(cellFormat.bottomBorderStyle()) + u';';
3371 styleString += " border-left-style:"_L1 + richtextBorderStyleToHtmlBorderStyle(cellFormat.leftBorderStyle()) + u';';
3372
3373 if (!styleString.isEmpty())
3374 html += " style=\""_L1 + styleString + u'\"';
3375
3376 html += u'>';
3377
3378 emitFrame(cell.begin());
3379
3380 html += "</td>"_L1;
3381
3382 defaultCharFormat = oldDefaultCharFormat;
3383 }
3384
3385 html += "</tr>"_L1;
3386 if (headerRowCount > 0 && row == headerRowCount - 1)
3387 html += "</thead>"_L1;
3388 }
3389
3390 html += "</table>"_L1;
3391}
3392
3393void QTextHtmlExporter::emitFrame(const QTextFrame::Iterator &frameIt)
3394{
3395 if (!frameIt.atEnd()) {
3396 QTextFrame::Iterator next = frameIt;
3397 ++next;
3398 if (next.atEnd()
3399 && frameIt.currentFrame() == nullptr
3400 && frameIt.parentFrame() != doc->rootFrame()
3401 && frameIt.currentBlock().begin().atEnd())
3402 return;
3403 }
3404
3405 for (QTextFrame::Iterator it = frameIt;
3406 !it.atEnd(); ++it) {
3407 if (QTextFrame *f = it.currentFrame()) {
3408 if (QTextTable *table = qobject_cast<QTextTable *>(f)) {
3409 emitTable(table);
3410 } else {
3411 emitTextFrame(f);
3412 }
3413 } else if (it.currentBlock().isValid()) {
3414 emitBlock(it.currentBlock());
3415 }
3416 }
3417}
3418
3419void QTextHtmlExporter::emitTextFrame(const QTextFrame *f)
3420{
3421 FrameType frameType = f->parentFrame() ? TextFrame : RootFrame;
3422
3423 html += "\n<table"_L1;
3424 QTextFrameFormat format = f->frameFormat();
3425
3426 if (format.hasProperty(QTextFormat::FrameBorder))
3427 emitAttribute("border", QString::number(format.border()));
3428
3429 emitFrameStyle(format, frameType);
3430
3431 emitTextLength("width", format.width());
3432 emitTextLength("height", format.height());
3433
3434 // root frame's bcolor goes in the <body> tag
3435 if (frameType != RootFrame)
3436 emitBackgroundAttribute(format);
3437
3438 html += u'>';
3439 html += "\n<tr>\n<td style=\"border: none;\">"_L1;
3440 emitFrame(f->begin());
3441 html += "</td></tr></table>"_L1;
3442}
3443
3444void QTextHtmlExporter::emitFrameStyle(const QTextFrameFormat &format, FrameType frameType)
3445{
3446 const auto styleAttribute = " style=\""_L1;
3447 html += styleAttribute;
3448 const int originalHtmlLength = html.size();
3449
3450 if (frameType == TextFrame)
3451 html += "-qt-table-type: frame;"_L1;
3452 else if (frameType == RootFrame)
3453 html += "-qt-table-type: root;"_L1;
3454
3455 const QTextFrameFormat defaultFormat;
3456
3457 emitFloatStyle(format.position(), OmitStyleTag);
3458 emitPageBreakPolicy(format.pageBreakPolicy());
3459
3460 if (format.borderBrush() != defaultFormat.borderBrush()) {
3461 html += " border-color:"_L1;
3462 html += colorValue(format.borderBrush().color());
3463 html += u';';
3464 }
3465
3466 if (format.borderStyle() != defaultFormat.borderStyle())
3467 emitBorderStyle(format.borderStyle());
3468
3469 if (format.hasProperty(QTextFormat::FrameMargin)
3470 || format.hasProperty(QTextFormat::FrameLeftMargin)
3472 || format.hasProperty(QTextFormat::FrameTopMargin)
3473 || format.hasProperty(QTextFormat::FrameBottomMargin))
3474 emitMargins(QString::number(format.topMargin()),
3475 QString::number(format.bottomMargin()),
3476 QString::number(format.leftMargin()),
3477 QString::number(format.rightMargin()));
3478
3479 if (format.property(QTextFormat::TableBorderCollapse).toBool())
3480 html += " border-collapse:collapse;"_L1;
3481
3482 if (html.size() == originalHtmlLength) // nothing emitted?
3483 html.chop(styleAttribute.size());
3484 else
3485 html += u'\"';
3486}
3487
3498#ifndef QT_NO_TEXTHTMLPARSER
3500{
3501 return QTextHtmlExporter(this).toHtml();
3502}
3503#endif // QT_NO_TEXTHTMLPARSER
3504
3512#if QT_CONFIG(textmarkdownwriter)
3513QString QTextDocument::toMarkdown(QTextDocument::MarkdownFeatures features) const
3514{
3515 QString ret;
3516 QTextStream s(&ret);
3517 QTextMarkdownWriter w(s, features);
3518 if (w.writeAll(this))
3519 return ret;
3520 return QString();
3521}
3522#endif
3523
3554#if QT_CONFIG(textmarkdownreader)
3555void QTextDocument::setMarkdown(const QString &markdown, QTextDocument::MarkdownFeatures features)
3556{
3557 QTextMarkdownImporter(features).import(this, markdown);
3558}
3559#endif
3560
3565{
3566 Q_D(const QTextDocument);
3567 return d->formatCollection()->formats;
3568}
3569
3578
3579#include "moc_qtextdocument.cpp"
virtual int pageCount() const =0
Returns the number of pages contained in the layout.
virtual void draw(QPainter *painter, const PaintContext &context)=0
Draws the layout with the given painter using the given context.
QPaintDevice * paintDevice() const
Returns the paint device used to render the document's layout.
virtual QSizeF documentSize() const =0
Returns the total size of the document's layout.
\inmodule QtGui
Definition qbrush.h:30
const QColor & color() const
Returns the brush color.
Definition qbrush.h:121
Qt::BrushStyle style() const
Returns the brush style.
Definition qbrush.h:120
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qchar.h:48
constexpr bool isLetterOrNumber() const noexcept
Returns true if the character is a letter or number (Letter_* or Number_* categories); otherwise retu...
Definition qchar.h:472
@ ObjectReplacementCharacter
Definition qchar.h:60
@ Nbsp
Definition qchar.h:57
@ ParagraphSeparator
Definition qchar.h:63
@ LineSeparator
Definition qchar.h:64
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
Definition qchar.h:458
constexpr bool isSpace() const noexcept
Returns true if the character is a separator character (Separator_* categories or certain code points...
Definition qchar.h:466
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
QString name(NameFormat format=HexRgb) const
Definition qcolor.cpp:834
bool parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity=Qt::CaseSensitive)
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
Definition qdir.h:206
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QString absolutePath() const
Returns a file's path absolute path.
bool isAbsolute() const
Returns true if the file path is absolute, otherwise returns false (i.e.
Definition qfileinfo.h:116
bool exists() const
Returns true if the file exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
\reentrant \inmodule QtGui
int horizontalAdvance(const QString &, int len=-1) const
Returns the horizontal advance in pixels of the first len characters of text.
int ascent() const
Returns the ascent of the font.
\reentrant
Definition qfont.h:20
Capitalization
Definition qfont.h:94
@ AllLowercase
Definition qfont.h:97
@ AllUppercase
Definition qfont.h:96
@ MixedCase
Definition qfont.h:95
@ SmallCaps
Definition qfont.h:98
@ PercentageSpacing
Definition qfont.h:104
\inmodule QtGui
Definition qimage.h:37
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
QList< T > & fill(parameter_type t, qsizetype size=-1)
Definition qlist.h:896
bool isEmpty() const noexcept
Definition qlist.h:390
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
qsizetype count() const noexcept
Definition qlist.h:387
void resize(qsizetype size)
Definition qlist.h:392
Definition qmap.h:186
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
\inmodule QtCore
Definition qmargins.h:274
constexpr void setLeft(qreal aleft) noexcept
Sets the left margin to aleft (which must be finite).
Definition qmargins.h:377
\inmodule QtCore
Definition qmetaobject.h:18
\inmodule QtCore
Definition qobject.h:90
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
QMarginsF margins() const
Returns the margins of the page layout using the currently set units.
The QPageRanges class represents a collection of page ranges.
Definition qpageranges.h:21
bool isEmpty() const
Returns true if the ranges are empty; otherwise returns false.
int lastPage() const
Returns the index of the last page covered by the page ranges, or 0 if the page ranges are empty.
int firstPage() const
Returns the index of the first page covered by the page ranges, or 0 if the page ranges are empty.
bool contains(int pageNumber) const
Returns true if the ranges include the page pageNumber; otherwise returns false.
\inmodule QtGui
virtual bool newPage()=0
Starts a new page.
virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units=QPageLayout::Millimeter)
QPageRanges pageRanges() const
QPageLayout pageLayout() const
int logicalDpiX() const
int logicalDpiY() const
int width() const
int height() const
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
void setClipping(bool enable)
Enables clipping if enable is true, or disables clipping if enable is false.
void setClipRect(const QRectF &, Qt::ClipOperation op=Qt::ReplaceClip)
Enables clipping, and sets the clip region to the given rectangle using the given clip operation.
void restore()
Restores the current painter state (pops a saved state off the stack).
QFontMetrics fontMetrics() const
Returns the font metrics for the painter if the painter is active.
void save()
Saves the current painter state (pushes the state onto a stack).
void setFont(const QFont &f)
Sets the painter's font to the given font.
void drawText(const QPointF &p, const QString &s)
Draws the given text with the currently defined text direction, beginning at the given position.
void translate(const QPointF &offset)
Translates the coordinate system by the given offset; i.e.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition qpixmap.cpp:460
bool loadFromData(const uchar *buf, uint len, const char *format=nullptr, Qt::ImageConversionFlags flags=Qt::AutoColor)
Loads a pixmap from the len first bytes of the given binary data.
Definition qpixmap.cpp:765
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
bool isNull() const noexcept
Returns true if both the x and y coordinates are set to 0.0 (ignoring the sign); otherwise returns fa...
Definition qpoint.h:328
\inmodule QtCore\reentrant
Definition qrect.h:483
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:496
constexpr QSizeF size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:721
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:497
\inmodule QtCore \reentrant
\inmodule QtCore \reentrant
bool isValid() const
Returns true if the regular expression is a valid regular expression (that is, it contains no syntax ...
PatternOptions patternOptions() const
Returns the pattern options for the regular expression.
\inmodule QtCore
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
iterator begin()
Definition qset.h:136
\inmodule QtCore
Definition qsize.h:207
constexpr qreal & rwidth() noexcept
Returns a reference to the width.
Definition qsize.h:345
constexpr void setHeight(qreal h) noexcept
Sets the height to the given finite height.
Definition qsize.h:330
constexpr qreal & rheight() noexcept
Returns a reference to the height.
Definition qsize.h:348
constexpr void setWidth(qreal w) noexcept
Sets the width to the given finite width.
Definition qsize.h:327
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:321
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:324
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:279
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3794
void reserve(qsizetype size)
Ensures the string has space for at least size characters.
Definition qstring.h:1173
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6180
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
Definition qstring.cpp:8606
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString & prepend(QChar c)
Definition qstring.h:411
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7005
QString toHtmlEscaped() const
Definition qstring.cpp:9926
int headingLevel() const
MarkerType marker() const
bool nonBreakableLines() const
Returns true if the lines in the paragraph are non-breakable; otherwise returns false.
bool atEnd() const
Returns true if the current item is the last item in the text block.
\reentrant
iterator begin() const
Returns a text block iterator pointing to the beginning of the text block.
int length() const
Returns the length of the block in characters.
QTextBlockFormat blockFormat() const
Returns the QTextBlockFormat that describes block-specific properties.
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
QTextBlock next() const
Returns the text block in the document after this block, or an empty text block if this is the last o...
int userState() const
int position() const
Returns the index of the block's first character within the document.
QString text() const
Returns the block's contents as plain text.
Qt::LayoutDirection textDirection() const
QTextCharFormat charFormat() const
Returns the QTextCharFormat that describes the block's character format.
QTextList * textList() const
If the block represents a list item, returns the list that the item belongs to; otherwise returns \nu...
QTextBlock previous() const
Returns the text block in the document before this block, or an empty text block if this is the first...
qreal fontLetterSpacing() const
VerticalAlignment
This enum describes the ways that adjacent characters can be vertically aligned.
QStringList anchorNames() const
int fontWeight() const
Returns the text format's font weight.
qreal fontPointSize() const
Returns the font size used to display text in this format.
bool fontStrikeOut() const
Returns true if the text format's font is struck out (has a horizontal line drawn through it); otherw...
void setVerticalAlignment(VerticalAlignment alignment)
Sets the vertical alignment used for the characters with this format to the alignment specified.
qreal fontWordSpacing() const
bool fontOverline() const
Returns true if the text format's font is overlined; otherwise returns false.
VerticalAlignment verticalAlignment() const
Returns the vertical alignment used for characters with this format.
QFont::SpacingType fontLetterSpacingType() const
bool fontItalic() const
Returns true if the text format's font is italic; otherwise returns false.
bool fontUnderline() const
Returns true if the text format's font is underlined; otherwise returns false.
void setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior=FontPropertiesAll)
static QTextCursor fromPosition(QTextDocumentPrivate *d, int pos)
\reentrant \inmodule QtGui
Definition qtextcursor.h:30
void setBlockCharFormat(const QTextCharFormat &format)
Sets the block char format of the current block (or all blocks that are contained in the selection) t...
QTextBlockFormat blockFormat() const
Returns the block format of the block the cursor is in.
QTextCharFormat blockCharFormat() const
Returns the block character format of the block the cursor is in.
void insertFragment(const QTextDocumentFragment &fragment)
Inserts the text fragment at the current position().
void setBlockFormat(const QTextBlockFormat &format)
Sets the block format of the current block (or all blocks that are contained in the selection) to for...
void insertText(const QString &text)
Inserts text at the current position, using the current character format.
QString buffer() const
static const QTextDocumentPrivate * get(const QTextDocument *document)
FragmentMap::ConstIterator FragmentIterator
FragmentIterator find(int pos) const
void mergeCachedResources(const QTextDocumentPrivate *priv)
\reentrant \inmodule QtGui
void setModified(bool m=true)
QString defaultStyleSheet
QTextDocument * clone(QObject *parent=nullptr) const
Creates a new QTextDocument that is a copy of this text document.
void setDefaultCursorMoveStyle(Qt::CursorMoveStyle style)
void setSuperScriptBaseline(qreal baseline)
void setBaselineOffset(qreal baseline)
void setIndentWidth(qreal width)
QTextBlock findBlockByLineNumber(int blockNumber) const
int maximumBlockCount
Specifies the limit for blocks in the document.
void setHtml(const QString &html)
Replaces the entire contents of the document with the given HTML-formatted text in the html string.
bool isEmpty() const
Returns true if the document is empty; otherwise returns false.
QTextFrame * frameAt(int pos) const
MetaInformation
This enum describes the different types of meta information that can be added to a document.
qreal baselineOffset() const
qreal idealWidth() const
int lineCount() const
void setDefaultTextOption(const QTextOption &option)
int availableRedoSteps() const
Stacks
\value UndoStack The undo stack.
void setResourceProvider(const ResourceProvider &provider)
bool isLayoutEnabled() const
QList< QTextFormat > allFormats() const
Returns a list of text formats for all the formats used in the document.
bool isRedoAvailable() const
Returns true if redo is available; otherwise returns false.
QFont defaultFont
the default font used to display the document's text
QString toHtml() const
Returns a string containing an HTML representation of the document.
QTextBlock findBlockByNumber(int blockNumber) const
int availableUndoSteps() const
int blockCount
the number of text blocks in the document.
QAbstractTextDocumentLayout * documentLayout() const
Returns the document layout for this document.
QString toRawText() const
Returns the raw text contained in the document without any formatting information.
bool useDesignMetrics
whether the document uses design metrics of fonts to improve the accuracy of text layout
QSizeF size
the actual size of the document. This is equivalent to documentLayout()->documentSize();
QSizeF pageSize
the page size that should be used for laying out the document
void appendUndoItem(QAbstractUndoItem *)
bool isModified() const
QTextObject * objectForFormat(const QTextFormat &) const
Returns the text object associated with the format f.
virtual void clear()
Clears the document.
bool isUndoRedoEnabled() const
int revision() const
void baseUrlChanged(const QUrl &url)
int pageCount() const
returns the number of pages in this document.
QTextBlock begin() const
Returns the document's first text block.
bool isUndoAvailable() const
Returns true if undo is available; otherwise returns false.
void setLayoutEnabled(bool b)
QTextOption defaultTextOption() const
the default text option will be set on all \l{QTextLayout}s in the document.
void print(QPagedPaintDevice *printer) const
Prints the document to the given printer.
QVariant resource(int type, const QUrl &name) const
Returns data of the specified type from the resource with the given name.
void setDefaultFont(const QFont &font)
Sets the default font to use in the document layout.
QChar characterAt(int pos) const
void setPageSize(const QSizeF &size)
QTextDocument(QObject *parent=nullptr)
Constructs an empty QTextDocument with the given parent.
QTextDocument::ResourceProvider resourceProvider() const
void setDefaultStyleSheet(const QString &sheet)
void setUndoRedoEnabled(bool enable)
QUrl baseUrl
the base URL used to resolve relative resource URLs within the document.
QString toPlainText() const
Returns the plain text contained in the document.
virtual Q_INVOKABLE QVariant loadResource(int type, const QUrl &name)
Loads data of the specified type from the resource with the given name.
QTextObject * object(int objectIndex) const
Returns the text object associated with the given objectIndex.
void clearUndoRedoStacks(Stacks historyToClear=UndoAndRedoStacks)
QTextCursor find(const QString &subString, int from=0, FindFlags options=FindFlags()) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setDocumentMargin(qreal margin)
QTextBlock findBlock(int pos) const
Returns the text block that contains the {pos}-th character.
qreal subScriptBaseline() const
QTextBlock end() const
This function returns a block to test for the end of the document while iterating over it.
QString metaInformation(MetaInformation info) const
Returns meta information about the document of the type specified by info.
Qt::CursorMoveStyle defaultCursorMoveStyle() const
QTextBlock firstBlock() const
static void setDefaultResourceProvider(const ResourceProvider &provider)
void setPlainText(const QString &text)
Replaces the entire contents of the document with the given plain text.
void setMaximumBlockCount(int maximum)
QTextFrame * rootFrame() const
Returns the document's root frame.
void setDocumentLayout(QAbstractTextDocumentLayout *layout)
Sets the document to use the given layout.
void setMetaInformation(MetaInformation info, const QString &)
Sets the document's meta information of the type specified by info to the given string.
qreal superScriptBaseline() const
static QTextDocument::ResourceProvider defaultResourceProvider()
void setBaseUrl(const QUrl &url)
QTextBlock lastBlock() const
void addResource(int type, const QUrl &name, const QVariant &resource)
Adds the resource resource to the resource cache, using type and name as identifiers.
void setSubScriptBaseline(qreal baseline)
~QTextDocument()
Destroys the document.
void undo()
This is an overloaded member function, provided for convenience. It differs from the above function o...
virtual QTextObject * createObject(const QTextFormat &f)
Creates and returns a new document object (a QTextObject), based on the given format.
std::function< QVariant(const QUrl &)> ResourceProvider
void markContentsDirty(int from, int length)
Marks the contents specified by the given position and length as "dirty", informing the document that...
void setUseDesignMetrics(bool b)
void setTextWidth(qreal width)
void drawContents(QPainter *painter, const QRectF &rect=QRectF())
int characterCount() const
void redo()
This is an overloaded member function, provided for convenience. It differs from the above function o...
\reentrant
Definition qtextformat.h:90
QTextCharFormat toCharFormat() const
Returns this format as a character format.
QBrush background() const
Returns the brush used to paint the document's background.
QString stringProperty(int propertyId) const
Returns the value of the property given by propertyId; if the property isn't of QMetaType::QString ty...
@ TableCellBottomBorderStyle
@ TableCellTopBorderStyle
@ TableCellBottomBorderBrush
@ TableCellRightBorderStyle
@ BlockTrailingHorizontalRulerWidth
@ TableCellTopBorderBrush
@ TableCellRightBorderBrush
@ TableCellBottomPadding
@ TableCellRightPadding
@ TableCellBottomBorder
@ TableCellLeftBorderStyle
@ TableCellLeftBorderBrush
QTextLength lengthProperty(int propertyId) const
Returns the value of the property given by propertyId.
int intProperty(int propertyId) const
Returns the value of the property specified by propertyId.
void setProperty(int propertyId, const QVariant &value)
Sets the property specified by the propertyId to the given value.
QTextImageFormat toImageFormat() const
Returns this format as an image format.
QMap< int, QVariant > properties() const
Returns a map with all properties of this text format.
QTextTableCellFormat toTableCellFormat() const
bool hasProperty(int propertyId) const
Returns true if the text format has a property with the given propertyId; otherwise returns false.
void clearProperty(int propertyId)
Clears the value of the property given by propertyId.
void merge(const QTextFormat &other)
Merges the other format with this format; where there are conflicts the other format takes precedence...
@ PageBreak_AlwaysBefore
@ PageBreak_AlwaysAfter
QVariant property(int propertyId) const
Returns the property specified by the given propertyId.
QBrush foreground() const
Returns the brush used to render foreground details, such as text, frame outlines,...
\reentrant
QString text() const
Returns the text fragment's as plain text.
QTextCharFormat charFormat() const
Returns the text fragment's character format.
QBrush borderBrush() const
BorderStyle borderStyle() const
Position
This enum describes how a frame is located relative to the surrounding text.
void setMargin(qreal margin)
Sets the frame's margin in pixels.
QTextFrame * parentFrame() const
Returns the parent frame of the current frame.
QTextFrame * currentFrame() const
Returns the current frame pointed to by the iterator, or \nullptr if the iterator currently points to...
bool atEnd() const
Returns true if the current item is the last item in the text frame.
Q_GUI_EXPORT QTextBlock currentBlock() const
Returns the current block the iterator points to.
\reentrant
Definition qtextobject.h:81
void setFrameFormat(const QTextFrameFormat &format)
Sets the frame's format.
QTextFrameFormat frameFormat() const
Returns the frame's format.
Definition qtextobject.h:89
iterator begin() const
Returns an iterator pointing to the first document element inside the frame.
QString toHtml(ExportMode mode=ExportEntireDocument)
Returns the document in HTML format.
QTextHtmlExporter(const QTextDocument *_doc)
static int lookupElement(const QString &element)
qreal width() const
Returns the width of the rectangle occupied by the image.
qreal height() const
Returns the height of the rectangle occupied by the image.
QString name() const
Returns the name of the image.
\reentrant
Definition qtextformat.h:45
int indent() const
Returns the list format's indentation.
\reentrant
Definition qtextlist.h:18
int itemNumber(const QTextBlock &) const
Returns the index of the list item that corresponds to the given block.
QTextListFormat format() const
Returns the list's format.
Definition qtextlist.h:37
void import(QTextDocument *doc, const QString &markdown)
\reentrant
Definition qtextobject.h:25
\reentrant
Definition qtextoption.h:18
\inmodule QtCore
QBrush leftBorderBrush() const
QTextFrameFormat::BorderStyle bottomBorderStyle() const
QTextFrameFormat::BorderStyle rightBorderStyle() const
QBrush rightBorderBrush() const
qreal rightBorder() const
qreal leftBorder() const
qreal topPadding() const
QBrush topBorderBrush() const
qreal bottomBorder() const
qreal leftPadding() const
qreal rightPadding() const
QBrush bottomBorderBrush() const
QTextFrameFormat::BorderStyle leftBorderStyle() const
qreal bottomPadding() const
QTextFrameFormat::BorderStyle topBorderStyle() const
qreal topBorder() const
\reentrant
Definition qtexttable.h:19
QTextCharFormat format() const
Returns the cell's character format.
int columnSpan() const
Returns the number of columns this cell spans.
int row() const
Returns the number of the row in the table that contains this cell.
int rowSpan() const
Returns the number of rows this cell spans.
int column() const
Returns the number of the column in the table that contains this cell.
QTextFrame::iterator begin() const
Returns a frame iterator pointing to the beginning of the table's cell.
\reentrant
Definition qtexttable.h:63
static QThread * currentThread()
Definition qthread.cpp:966
\inmodule QtCore
Definition qurl.h:94
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3354
QUrl resolved(const QUrl &relative) const
Returns the result of the merge of this URL with relative.
Definition qurl.cpp:2722
bool isRelative() const
Returns true if the URL is relative; otherwise returns false.
Definition qurl.cpp:2797
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1888
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1983
void setScheme(const QString &scheme)
Sets the scheme of the URL to scheme.
Definition qurl.cpp:1959
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2828
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
Definition qurl.cpp:3411
\inmodule QtCore
Definition qvariant.h:64
EGLContext ctx
QString text
QCursor cursor
double e
QSet< QString >::iterator it
rect
[4]
short next
Definition keywords.cpp:445
@ StyleSheetOrigin_UserAgent
Combined button and popup list for selecting options.
@ AlignRight
Definition qnamespace.h:145
@ AlignJustify
Definition qnamespace.h:148
@ AlignHCenter
Definition qnamespace.h:147
@ AlignLeft
Definition qnamespace.h:143
Q_GUI_EXPORT QString convertFromPlainText(const QString &plain, WhiteSpaceMode mode=WhiteSpacePre)
Converts the plain text string plain to an HTML-formatted paragraph while preserving most of its look...
@ RightToLeft
@ black
Definition qnamespace.h:29
WhiteSpaceMode
Definition qnamespace.h:195
@ WhiteSpacePre
Definition qnamespace.h:197
CaseSensitivity
@ CaseInsensitive
@ CaseSensitive
@ SolidPattern
@ TexturePattern
@ NoBrush
CursorMoveStyle
Q_GUI_EXPORT bool mightBeRichText(const QString &)
Returns true if the string text is likely to be rich text; otherwise returns false.
@ DirectConnection
Definition brush.cpp:5
Definition image.cpp:4
bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush &brush)
Definition qbrush.cpp:202
#define Q_DECL_CONST_FUNCTION
#define qApp
AudioChannelLayoutTag tag
Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray &payload)
Definition qdataurl.cpp:18
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputLayerEXT EGLint attribute
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:281
Q_GUI_EXPORT int qt_defaultDpiX()
Definition qfont.cpp:107
Q_GUI_EXPORT int qt_defaultDpiY()
Definition qfont.cpp:122
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n)
\inmodule QtCore \title Global Qt Declarations
Definition qglobal.cpp:113
return ret
static const QMetaObjectPrivate * priv(const uint *data)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
#define Q_RETURN_ARG(Type, data)
Definition qobjectdefs.h:63
#define Q_ARG(Type, data)
Definition qobjectdefs.h:62
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLenum mode
const GLfloat * m
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble right
GLfloat GLfloat f
GLint GLsizei width
GLint left
GLenum type
GLint GLint bottom
GLboolean enable
GLenum GLuint GLsizei const GLenum * props
GLuint start
GLenum GLuint GLintptr offset
GLuint name
GLint first
GLfloat n
GLint GLsizei GLsizei GLenum format
GLhandleARB obj
[2]
const GLubyte * c
GLuint GLuint * names
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLuint GLenum option
GLenum GLenum GLsizei void * table
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
static QT_BEGIN_NAMESPACE bool isDigit(ushort ch)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
static QString colorValue(QColor color)
static bool isOrderedList(int style)
static QLatin1StringView richtextBorderStyleToHtmlBorderStyle(QTextFrameFormat::BorderStyle style)
static QStringList resolvedFontFamilies(const QTextCharFormat &format)
static void printPage(int index, QPainter *painter, const QTextDocument *doc, const QRectF &body, const QPointF &pageNumberPos)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n)
\inmodule QtCore \title Global Qt Declarations
Definition qglobal.cpp:113
static bool findInBlock(const QTextBlock &block, const QString &expression, int offset, QTextDocument::FindFlags options, QTextCursor *cursor)
static QTextFormat formatDifference(const QTextFormat &from, const QTextFormat &to)
bool qHasPixmapTexture(const QBrush &brush)
Definition qbrush.cpp:202
#define QTextBeginningOfFrame
#define QTextEndOfFrame
#define emit
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
static int compare(quint64 a, quint64 b)
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
double qreal
Definition qtypes.h:92
unsigned char quint8
Definition qtypes.h:41
static QString quote(const QString &str)
QVideoFrameFormat::PixelFormat fmt
QList< int > list
[14]
file open(QIODevice::ReadOnly)
QFileInfo info(fileName)
[8]
QFileInfo fi("c:/temp/foo")
[newstuff]
QUrl url("example.com")
[constructor-url-reference]
QVBoxLayout * layout
QString title
[35]
QByteArray page
[45]
Text files * txt
QGraphicsItem * item
QPainter painter(this)
[7]
QSizePolicy policy
QQuickView * view
[0]
\inmodule QtCore
int indexOfMethod(const char *method) const
Finds method and returns its index; otherwise returns -1.
QMetaMethod method(int index) const
Returns the meta-data for the method with the given index.
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent