5#include <qtextformat.h>
14#include <qloggingcategory.h>
15#if QT_CONFIG(regularexpression)
16#include <qregularexpression.h>
18#include <qvarlengtharray.h>
20#include <qcoreapplication.h>
21#include <qmetaobject.h>
29#include "private/qdataurl_p.h"
32#include <private/qabstracttextdocumentlayout_p.h>
34#include "private/qpagedpaintdevice_p.h"
35#if QT_CONFIG(textmarkdownreader)
36#include <private/qtextmarkdownimporter_p.h>
38#if QT_CONFIG(textmarkdownwriter)
39#include <private/qtextmarkdownwriter_p.h>
46using namespace Qt::StringLiterals;
48Q_CORE_EXPORT Q_DECL_CONST_FUNCTION
unsigned int qt_int_sqrt(
unsigned int n);
51 QTextDocument::ResourceProvider qt_defaultResourceProvider;
54QAbstractUndoItem::~QAbstractUndoItem()
58
59
60
61
62
63
64
65
66
67
68
69
70
71
79 while (start < text.size() && QChar(text.at(start)).isSpace())
83 if (text.mid(start, 5).compare(
"<?xml"_L1) == 0) {
84 while (start < text.size()) {
85 if (text.at(start) == u'?'
86 && start + 2 < text.size()
87 && text.at(start + 1) == u'>') {
94 while (start < text.size() && QChar(text.at(start)).isSpace())
98 if (text.mid(start, 5).compare(
"<!doc"_L1, Qt::CaseInsensitive) == 0)
100 qsizetype open = start;
101 while (open < text.size() && text.at(open) != u'<'
102 && text.at(open) != u'\n') {
103 if (text.at(open) == u'&' && text.mid(open + 1, 3) ==
"lt;"_L1)
107 if (open < text.size() && text.at(open) == u'<') {
108 const qsizetype close = text.indexOf(u'>', open);
110 QVarLengthArray<
char16_t> tag;
111 for (qsizetype i = open + 1; i < close; ++i) {
112 const auto current = QChar(text[i]);
113 if (current.isDigit() || current.isLetter())
114 tag.append(current.toLower().unicode());
115 else if (!tag.isEmpty() && current.isSpace())
117 else if (!tag.isEmpty() && current == u'/' && i + 1 == close)
119 else if (!current.isSpace() && (!tag.isEmpty() || current != u'!'))
122#ifndef QT_NO_TEXTHTMLPARSER
123 return QTextHtmlParser::lookupElement(tag) != -1;
134 return mightBeRichTextImpl(QLatin1StringView(QByteArrayView(text)));
139 return text.visit([](
auto text) {
return mightBeRichTextImpl(text); });
143
144
145
146
147
148
149
150
151
152QString
Qt::convertFromPlainText(
const QString &plain, Qt::WhiteSpaceMode mode)
157 for (qsizetype i = 0; i < plain.size(); ++i) {
158 if (plain[i] == u'\n'){
160 while (i+1 < plain.size() && plain[i+1] == u'\n') {
174 if (mode == Qt::WhiteSpacePre && plain[i] == u'\t'){
182 else if (mode == Qt::WhiteSpacePre && plain[i].isSpace())
184 else if (plain[i] == u'<')
186 else if (plain[i] == u'>')
188 else if (plain[i] == u'&')
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
262
263
264
267
268
269
270
271
272
273
276
277
278QTextDocument::QTextDocument(QObject *parent)
279 : QObject(*
new QTextDocumentPrivate, parent)
286
287
288
289QTextDocument::QTextDocument(
const QString &text, QObject *parent)
290 : QObject(*
new QTextDocumentPrivate, parent)
294 QTextCursor(
this).insertText(text);
298
299
300QTextDocument::QTextDocument(QTextDocumentPrivate &dd, QObject *parent)
301 : QObject(dd, parent)
308
309
310QTextDocument::~QTextDocument()
316
317
318
319QTextDocument *QTextDocument::clone(QObject *parent)
const
321 Q_D(
const QTextDocument);
322 QTextDocument *doc =
new QTextDocument(parent);
324 const QTextCursor thisCursor(
const_cast<QTextDocument *>(
this));
326 const auto blockFormat = thisCursor.blockFormat();
327 if (blockFormat.isValid() && !blockFormat.isEmpty())
328 QTextCursor(doc).setBlockFormat(blockFormat);
330 const auto blockCharFormat = thisCursor.blockCharFormat();
331 if (blockCharFormat.isValid() && !blockCharFormat.isEmpty())
332 QTextCursor(doc).setBlockCharFormat(blockCharFormat);
334 QTextCursor(doc).insertFragment(QTextDocumentFragment(
this));
336 doc->rootFrame()->setFrameFormat(rootFrame()->frameFormat());
337 QTextDocumentPrivate *priv = doc->d_func();
338 priv->title = d->title;
340 priv->cssMedia = d->cssMedia;
341 priv->pageSize = d->pageSize;
342 priv->indentWidth = d->indentWidth;
343 priv->defaultTextOption = d->defaultTextOption;
344 priv->setDefaultFont(d->defaultFont());
345 priv->resources = d->resources;
346 priv->cachedResources.clear();
347 priv->resourceProvider = d->resourceProvider;
348#ifndef QT_NO_CSSPARSER
349 priv->defaultStyleSheet = d->defaultStyleSheet;
350 priv->parsedDefaultStyleSheet = d->parsedDefaultStyleSheet;
356
357
358bool QTextDocument::isEmpty()
const
360 Q_D(
const QTextDocument);
362
363 return d->length() <= 1;
367
368
369void QTextDocument::clear()
373 d->resources.clear();
377
378
379
380
381
382
383
384
385
386
387
388void QTextDocument::undo(QTextCursor *cursor)
391 const int pos = d->undoRedo(
true);
392 if (cursor && pos >= 0) {
393 *cursor = QTextCursor(
this);
394 cursor->setPosition(pos);
399
400
401
402
403
404
405void QTextDocument::redo(QTextCursor *cursor)
408 const int pos = d->undoRedo(
false);
409 if (cursor && pos >= 0) {
410 *cursor = QTextCursor(
this);
411 cursor->setPosition(pos);
416
417
418
419
420
423
424
425
426
427
428
429
430
431
432
433void QTextDocument::clearUndoRedoStacks(Stacks stacksToClear)
436 d->clearUndoRedoStacks(stacksToClear,
true);
440
441
442
443void QTextDocument::undo()
450
451
452
453void QTextDocument::redo()
460
461
462
463
464void QTextDocument::appendUndoItem(QAbstractUndoItem *item)
467 d->appendUndoItem(item);
471
472
473
474
475
476
477void QTextDocument::setUndoRedoEnabled(
bool enable)
480 d->enableUndoRedo(enable);
483bool QTextDocument::isUndoRedoEnabled()
const
485 Q_D(
const QTextDocument);
486 return d->isUndoRedoEnabled();
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510int QTextDocument::maximumBlockCount()
const
512 Q_D(
const QTextDocument);
513 return d->maximumBlockCount;
516void QTextDocument::setMaximumBlockCount(
int maximum)
519 d->maximumBlockCount = maximum;
520 d->ensureMaximumBlockCount();
521 setUndoRedoEnabled(
false);
525
526
527
528
529
530
531QTextOption QTextDocument::defaultTextOption()
const
533 Q_D(
const QTextDocument);
534 return d->defaultTextOption;
538
539
540
541
542void QTextDocument::setDefaultTextOption(
const QTextOption &option)
545 d->defaultTextOption = option;
547 d->lout->documentChanged(0, 0, d->length());
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566QUrl QTextDocument::baseUrl()
const
568 Q_D(
const QTextDocument);
572void QTextDocument::setBaseUrl(
const QUrl &url)
575 if (d->baseUrl != url) {
578 d->lout->documentChanged(0, 0, d->length());
579 emit baseUrlChanged(url);
584
585
586
587
588
589Qt::CursorMoveStyle QTextDocument::defaultCursorMoveStyle()
const
591 Q_D(
const QTextDocument);
592 return d->defaultCursorMoveStyle;
596
597
598
599
600void QTextDocument::setDefaultCursorMoveStyle(Qt::CursorMoveStyle style)
603 d->defaultCursorMoveStyle = style;
607
608
609
610
611
612
613void QTextDocument::markContentsDirty(
int from,
int length)
616 d->documentChange(from, length);
617 if (!d->inContentsChange) {
619 d->lout->documentChanged(d->docChangeFrom, d->docChangeOldLength, d->docChangeLength);
620 d->docChangeFrom = -1;
626
627
628
629
630
631
632
633
634
635
636
637
638
639
641void QTextDocument::setUseDesignMetrics(
bool b)
644 if (b == d->defaultTextOption.useDesignMetrics())
646 d->defaultTextOption.setUseDesignMetrics(b);
648 d->lout->documentChanged(0, 0, d->length());
651bool QTextDocument::useDesignMetrics()
const
653 Q_D(
const QTextDocument);
654 return d->defaultTextOption.useDesignMetrics();
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
675void QTextDocument::setLayoutEnabled(
bool b)
678 if (d->layoutEnabled == b)
680 d->layoutEnabled = b;
682 d->lout->documentChanged(0, 0, d->length());
685bool QTextDocument::isLayoutEnabled()
const
687 Q_D(
const QTextDocument);
688 return d->layoutEnabled;
692
693
694
695
696
697void QTextDocument::drawContents(QPainter *p,
const QRectF &rect)
700 QAbstractTextDocumentLayout::PaintContext ctx;
701 if (rect.isValid()) {
702 p->setClipRect(rect);
705 documentLayout()->draw(p, ctx);
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730void QTextDocument::setTextWidth(qreal width)
733 QSizeF sz = d->pageSize;
735 qCDebug(lcLayout) <<
"page size" << sz <<
"-> width" << width;
741qreal QTextDocument::textWidth()
const
743 Q_D(
const QTextDocument);
744 return d->pageSize.width();
748
749
750
751
752
753
754
755qreal QTextDocument::idealWidth()
const
757 if (QTextDocumentLayout *lout = qobject_cast<QTextDocumentLayout *>(documentLayout()))
758 return lout->idealWidth();
763
764
765
766
767
768qreal QTextDocument::documentMargin()
const
770 Q_D(
const QTextDocument);
771 return d->documentMargin;
774void QTextDocument::setDocumentMargin(qreal margin)
777 if (d->documentMargin != margin) {
778 d->documentMargin = margin;
780 QTextFrame* root = rootFrame();
781 QTextFrameFormat format = root->frameFormat();
782 format.setMargin(margin);
783 root->setFrameFormat(format);
786 d->lout->documentChanged(0, 0, d->length());
792
793
794
795
796
797
798
799
800qreal QTextDocument::indentWidth()
const
802 Q_D(
const QTextDocument);
803 return d->indentWidth;
808
809
810
811
812
813
814
815
816
817void QTextDocument::setIndentWidth(qreal width)
820 if (d->indentWidth != width) {
821 d->indentWidth = width;
823 d->lout->documentChanged(0, 0, d->length());
831
832
833
834
835
836
837void QTextDocument::adjustSize()
840 QFont f = defaultFont();
842 int mw = fm.horizontalAdvance(u'x') * 80;
845 QSizeF size = documentLayout()->documentSize();
846 if (size.width() != 0) {
847 w = qt_int_sqrt((uint)(5 * size.height() * size.width() / 3));
848 setTextWidth(qMin(w, mw));
850 size = documentLayout()->documentSize();
851 if (w*3 < 5*size.height()) {
852 w = qt_int_sqrt((uint)(2 * size.height() * size.width()));
853 setTextWidth(qMin(w, mw));
856 setTextWidth(idealWidth());
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876QSizeF QTextDocument::size()
const
878 return documentLayout()->documentSize();
882
883
884
885
886
887
888
889
890
891
892int QTextDocument::blockCount()
const
894 Q_D(
const QTextDocument);
895 return d->blockMap().numNodes();
900
901
902
903
904
905
906
907int QTextDocument::lineCount()
const
909 Q_D(
const QTextDocument);
910 return d->blockMap().length(2);
914
915
916
917
918
919
920
921
922
923int QTextDocument::characterCount()
const
925 Q_D(
const QTextDocument);
930
931
932
933
934
935
936
937QChar QTextDocument::characterAt(
int pos)
const
939 Q_D(
const QTextDocument);
940 if (pos < 0 || pos >= d->length())
942 QTextDocumentPrivate::FragmentIterator fragIt = d->find(pos);
943 const QTextFragmentData *
const frag = fragIt.value();
944 const int offsetInFragment = qMax(0, pos - fragIt.position());
945 return d->text.at(frag->stringPosition + offsetInFragment);
950
951
952
953
954
955
956
957
958
959
960
961
962
964#ifndef QT_NO_CSSPARSER
965void QTextDocument::setDefaultStyleSheet(
const QString &sheet)
968 d->defaultStyleSheet = sheet;
969 QCss::Parser parser(sheet);
970 d->parsedDefaultStyleSheet = QCss::StyleSheet();
971 d->parsedDefaultStyleSheet.origin = QCss::StyleSheetOrigin_UserAgent;
972 parser.parse(&d->parsedDefaultStyleSheet);
975QString QTextDocument::defaultStyleSheet()
const
977 Q_D(
const QTextDocument);
978 return d->defaultStyleSheet;
983
984
985
986
987
988
989
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1022
1023
1024
1025
1026
1029
1030
1031
1032
1033
1034
1035
1036
1039
1040
1041
1042
1043
1044
1045
1048
1049
1050
1051
1052
1053
1054
1055
1059
1060
1061
1062
1063bool QTextDocument::isUndoAvailable()
const
1065 Q_D(
const QTextDocument);
1066 return d->isUndoAvailable();
1070
1071
1072
1073
1074bool QTextDocument::isRedoAvailable()
const
1076 Q_D(
const QTextDocument);
1077 return d->isRedoAvailable();
1081
1082
1083
1084
1085
1086int QTextDocument::availableUndoSteps()
const
1088 Q_D(
const QTextDocument);
1089 return d->availableUndoSteps();
1093
1094
1095
1096
1097
1098int QTextDocument::availableRedoSteps()
const
1100 Q_D(
const QTextDocument);
1101 return d->availableRedoSteps();
1105
1106
1107
1108
1109
1110
1111
1112
1113int QTextDocument::revision()
const
1115 Q_D(
const QTextDocument);
1122
1123
1124
1125
1126
1127void QTextDocument::setDocumentLayout(QAbstractTextDocumentLayout *layout)
1130 d->setLayout(layout);
1134
1135
1136QAbstractTextDocumentLayout *QTextDocument::documentLayout()
const
1138 Q_D(
const QTextDocument);
1140 QTextDocument *that =
const_cast<QTextDocument *>(
this);
1141 that->d_func()->setLayout(
new QTextDocumentLayout(that));
1148
1149
1150
1151
1152
1153QString QTextDocument::metaInformation(MetaInformation info)
const
1155 Q_D(
const QTextDocument);
1164 return d->frontMatter;
1170
1171
1172
1173
1174
1175void QTextDocument::setMetaInformation(MetaInformation info,
const QString &string)
1186 d->cssMedia = string;
1189 d->frontMatter = string;
1195
1196
1197
1198
1199
1200
1201
1202QString QTextDocument::toRawText()
const
1204 Q_D(
const QTextDocument);
1205 return d->plainText();
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225QString QTextDocument::toPlainText()
const
1227 Q_D(
const QTextDocument);
1228 QString txt = d->plainText();
1230 constexpr char16_t delims[] = { 0xfdd0, 0xfdd1,
1231 QChar::ParagraphSeparator, QChar::LineSeparator, QChar::Nbsp };
1233 const size_t pos = std::u16string_view(txt).find_first_of(
1234 std::u16string_view(delims, std::size(delims)));
1235 if (pos == std::u16string_view::npos)
1238 QChar *uc = txt.data();
1239 QChar *
const e = uc + txt.size();
1241 for (uc += pos; uc != e; ++uc) {
1242 switch (uc->unicode()) {
1245 case QChar::ParagraphSeparator:
1246 case QChar::LineSeparator:
1260
1261
1262
1263
1264
1265void QTextDocument::setPlainText(
const QString &text)
1268 bool previousState = d->isUndoRedoEnabled();
1269 d->enableUndoRedo(
false);
1270 d->beginEditBlock();
1272 QTextCursor(
this).insertText(text);
1274 d->enableUndoRedo(previousState);
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1296#ifndef QT_NO_TEXTHTMLPARSER
1298void QTextDocument::setHtml(
const QString &html)
1301 bool previousState = d->isUndoRedoEnabled();
1302 d->enableUndoRedo(
false);
1303 d->beginEditBlock();
1307 QTextHtmlImporter(
this, html, QTextHtmlImporter::ImportToDocument).import();
1309 d->enableUndoRedo(previousState);
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1346static bool findInBlock(
const QTextBlock &block,
const QString &expression,
int offset,
1347 QTextDocument::FindFlags options, QTextCursor *cursor)
1350 text.replace(QChar::Nbsp, u' ');
1351 Qt::CaseSensitivity sensitivity = options & QTextDocument::FindCaseSensitively ? Qt::CaseSensitive : Qt::CaseInsensitive;
1354 while (offset >= 0 && offset <= text.size()) {
1355 idx = (options & QTextDocument::FindBackward) ?
1356 text.lastIndexOf(expression, offset, sensitivity) : text.indexOf(expression, offset, sensitivity);
1360 if (options & QTextDocument::FindWholeWords) {
1361 const int start = idx;
1362 const int end = start + expression.size();
1363 if ((start != 0 && text.at(start - 1).isLetterOrNumber())
1364 || (end != text.size() && text.at(end).isLetterOrNumber())) {
1366 offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;
1372 *cursor = QTextCursorPrivate::fromPosition(
const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(block)),
1373 block.position() + idx);
1374 cursor->setPosition(cursor->position() + expression.size(), QTextCursor::KeepAnchor);
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396QTextCursor QTextDocument::find(
const QString &subString,
int from, FindFlags options)
const
1398 Q_D(
const QTextDocument);
1400 if (subString.isEmpty())
1401 return QTextCursor();
1406 if (options & FindBackward) {
1409 return QTextCursor();
1413 QTextBlock block = d->blocksFind(pos);
1414 int blockOffset = pos - block.position();
1416 if (!(options & FindBackward)) {
1417 while (block.isValid()) {
1418 if (findInBlock(block, subString, blockOffset, options, &cursor))
1420 block = block.next();
1424 if (blockOffset == block.length() - 1)
1426 while (block.isValid()) {
1427 if (findInBlock(block, subString, blockOffset, options, &cursor))
1429 block = block.previous();
1430 blockOffset = block.length() - 2;
1434 return QTextCursor();
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452QTextCursor QTextDocument::find(
const QString &subString,
const QTextCursor &cursor, FindFlags options)
const
1455 if (!cursor.isNull()) {
1456 if (options & QTextDocument::FindBackward)
1457 pos = cursor.selectionStart();
1459 pos = cursor.selectionEnd();
1462 return find(subString, pos, options);
1465#if QT_CONFIG(regularexpression)
1466static bool findInBlock(
const QTextBlock &block,
const QRegularExpression &expr,
int offset,
1467 QTextDocument::FindFlags options, QTextCursor *cursor)
1469 QString text = block.text();
1470 text.replace(QChar::Nbsp, u' ');
1471 QRegularExpressionMatch match;
1474 while (offset >= 0 && offset <= text.size()) {
1475 idx = (options & QTextDocument::FindBackward) ?
1476 text.lastIndexOf(expr, offset, &match) : text.indexOf(expr, offset, &match);
1480 if (options & QTextDocument::FindWholeWords) {
1481 const int start = idx;
1482 const int end = start + match.capturedLength();
1483 if ((start != 0 && text.at(start - 1).isLetterOrNumber())
1484 || (end != text.size() && text.at(end).isLetterOrNumber())) {
1486 offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;
1492 *cursor = QTextCursorPrivate::fromPosition(
const_cast<QTextDocumentPrivate *>(QTextDocumentPrivate::get(block)),
1493 block.position() + idx);
1494 cursor->setPosition(cursor->position() + match.capturedLength(), QTextCursor::KeepAnchor);
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520QTextCursor QTextDocument::find(
const QRegularExpression &expr,
int from, FindFlags options)
const
1522 Q_D(
const QTextDocument);
1524 if (!expr.isValid())
1525 return QTextCursor();
1530 if (options & FindBackward) {
1533 return QTextCursor();
1537 QTextBlock block = d->blocksFind(pos);
1538 int blockOffset = pos - block.position();
1540 QRegularExpression expression(expr);
1541 if (!(options & QTextDocument::FindCaseSensitively))
1542 expression.setPatternOptions(expr.patternOptions() | QRegularExpression::CaseInsensitiveOption);
1544 expression.setPatternOptions(expr.patternOptions() & ~QRegularExpression::CaseInsensitiveOption);
1546 if (!(options & FindBackward)) {
1547 while (block.isValid()) {
1548 if (findInBlock(block, expression, blockOffset, options, &cursor))
1550 block = block.next();
1554 while (block.isValid()) {
1555 if (findInBlock(block, expression, blockOffset, options, &cursor))
1557 block = block.previous();
1558 blockOffset = block.length() - 1;
1562 return QTextCursor();
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584QTextCursor QTextDocument::find(
const QRegularExpression &expr,
const QTextCursor &cursor, FindFlags options)
const
1587 if (!cursor.isNull()) {
1588 if (options & QTextDocument::FindBackward)
1589 pos = cursor.selectionStart();
1591 pos = cursor.selectionEnd();
1593 return find(expr, pos, options);
1598
1599
1600
1601
1602
1603
1604
1605
1606QTextObject *QTextDocument::createObject(
const QTextFormat &f)
1608 QTextObject *obj =
nullptr;
1609 if (f.isListFormat())
1610 obj =
new QTextList(
this);
1611 else if (f.isTableFormat())
1612 obj =
new QTextTable(
this);
1613 else if (f.isFrameFormat())
1614 obj =
new QTextFrame(
this);
1620
1621
1622
1623
1624QTextFrame *QTextDocument::frameAt(
int pos)
const
1626 Q_D(
const QTextDocument);
1627 return d->frameAt(pos);
1631
1632
1633QTextFrame *QTextDocument::rootFrame()
const
1635 Q_D(
const QTextDocument);
1636 return d->rootFrame();
1640
1641
1642QTextObject *QTextDocument::object(
int objectIndex)
const
1644 Q_D(
const QTextDocument);
1645 return d->objectForIndex(objectIndex);
1649
1650
1651QTextObject *QTextDocument::objectForFormat(
const QTextFormat &f)
const
1653 Q_D(
const QTextDocument);
1654 return d->objectForFormat(f);
1659
1660
1661QTextBlock QTextDocument::findBlock(
int pos)
const
1663 Q_D(
const QTextDocument);
1664 return QTextBlock(
const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(pos));
1668
1669
1670
1671
1672
1673QTextBlock QTextDocument::findBlockByNumber(
int blockNumber)
const
1675 Q_D(
const QTextDocument);
1676 return QTextBlock(
const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(blockNumber, 1));
1680
1681
1682
1683
1684
1685QTextBlock QTextDocument::findBlockByLineNumber(
int lineNumber)
const
1687 Q_D(
const QTextDocument);
1688 return QTextBlock(
const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(lineNumber, 2));
1692
1693
1694
1695
1696QTextBlock QTextDocument::begin()
const
1698 Q_D(
const QTextDocument);
1699 return QTextBlock(
const_cast<QTextDocumentPrivate *>(d), d->blockMap().begin().n);
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714QTextBlock QTextDocument::end()
const
1716 Q_D(
const QTextDocument);
1717 return QTextBlock(
const_cast<QTextDocumentPrivate *>(d), 0);
1721
1722
1723
1724QTextBlock QTextDocument::firstBlock()
const
1726 Q_D(
const QTextDocument);
1727 return QTextBlock(
const_cast<QTextDocumentPrivate *>(d), d->blockMap().begin().n);
1731
1732
1733
1734QTextBlock QTextDocument::lastBlock()
const
1736 Q_D(
const QTextDocument);
1737 return QTextBlock(
const_cast<QTextDocumentPrivate *>(d), d->blockMap().last().n);
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1754void QTextDocument::setPageSize(
const QSizeF &size)
1759 d->lout->documentChanged(0, 0, d->length());
1762QSizeF QTextDocument::pageSize()
const
1764 Q_D(
const QTextDocument);
1769
1770
1771int QTextDocument::pageCount()
const
1773 return documentLayout()->pageCount();
1777
1778
1779void QTextDocument::setDefaultFont(
const QFont &font)
1782 d->setDefaultFont(font);
1784 d->lout->documentChanged(0, 0, d->length());
1788
1789
1790QFont QTextDocument::defaultFont()
const
1792 Q_D(
const QTextDocument);
1793 return d->defaultFont();
1797
1798
1799
1800
1801
1802
1803
1804
1805void QTextDocument::setSuperScriptBaseline(qreal baseline)
1808 d->formats.setSuperScriptBaseline(baseline);
1812
1813
1814
1815
1816
1817
1818
1819qreal QTextDocument::superScriptBaseline()
const
1821 Q_D(
const QTextDocument);
1822 return d->formats.defaultTextFormat().superScriptBaseline();
1826
1827
1828
1829
1830
1831
1832
1833
1834void QTextDocument::setSubScriptBaseline(qreal baseline)
1837 d->formats.setSubScriptBaseline(baseline);
1841
1842
1843
1844
1845
1846
1847
1848qreal QTextDocument::subScriptBaseline()
const
1850 Q_D(
const QTextDocument);
1851 return d->formats.defaultTextFormat().subScriptBaseline();
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864void QTextDocument::setBaselineOffset(qreal baseline)
1867 d->formats.setBaselineOffset(baseline);
1871
1872
1873
1874
1875
1876
1877
1878
1879qreal QTextDocument::baselineOffset()
const
1881 Q_D(
const QTextDocument);
1882 return d->formats.defaultTextFormat().baselineOffset();
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1900
1901
1902
1903
1904
1905
1906
1908bool QTextDocument::isModified()
const
1910 Q_D(
const QTextDocument);
1911 return d->isModified();
1914void QTextDocument::setModified(
bool m)
1920#ifndef QT_NO_PRINTER
1921static void printPage(
int index,
QPainter *painter,
const QTextDocument *doc,
const QRectF &body,
const QPointF &pageNumberPos)
1924 painter->translate(body.left(), body.top() - (index - 1) * body.height());
1925 QRectF view(0, (index - 1) * body.height(), body.width(), body.height());
1927 QAbstractTextDocumentLayout *layout = doc->documentLayout();
1928 QAbstractTextDocumentLayout::PaintContext ctx;
1930 painter->setClipRect(view);
1936 ctx.palette.setColor(QPalette::Text, Qt::black);
1938 layout->draw(painter, ctx);
1940 if (!pageNumberPos.isNull()) {
1941 painter->setClipping(
false);
1942 painter->setFont(QFont(doc->defaultFont()));
1943 const QString pageString = QString::number(index);
1945 painter->drawText(qRound(pageNumberPos.x() - painter->fontMetrics().horizontalAdvance(pageString)),
1946 qRound(pageNumberPos.y() + view.top()),
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1971void QTextDocument::print(QPagedPaintDevice *printer)
const
1973 Q_D(
const QTextDocument);
1978 bool documentPaginated = d->pageSize.isValid() && !d->pageSize.isNull()
1979 && d->pageSize.height() != INT_MAX;
1982 QMarginsF m = printer->pageLayout().margins(QPageLayout::Millimeter);
1983 if (!documentPaginated && m.left() == 0. && m.right() == 0. && m.top() == 0. && m.bottom() == 0.) {
1988 printer->setPageMargins(m, QPageLayout::Millimeter);
1992 QPainter p(printer);
1998 const QTextDocument *doc =
this;
1999 QScopedPointer<QTextDocument> clonedDoc;
2000 (
void)doc->documentLayout();
2002 QRectF body = QRectF(QPointF(0, 0), d->pageSize);
2003 QPointF pageNumberPos;
2005 qreal sourceDpiX = qt_defaultDpiX();
2006 qreal sourceDpiY = qt_defaultDpiY();
2007 const qreal dpiScaleX = qreal(printer->logicalDpiX()) / sourceDpiX;
2008 const qreal dpiScaleY = qreal(printer->logicalDpiY()) / sourceDpiY;
2010 if (documentPaginated) {
2012 QPaintDevice *dev = doc->documentLayout()->paintDevice();
2014 sourceDpiX = dev->logicalDpiX();
2015 sourceDpiY = dev->logicalDpiY();
2019 p.scale(dpiScaleX, dpiScaleY);
2021 QSizeF scaledPageSize = d->pageSize;
2022 scaledPageSize.rwidth() *= dpiScaleX;
2023 scaledPageSize.rheight() *= dpiScaleY;
2025 const QSizeF printerPageSize(printer->width(), printer->height());
2028 p.scale(printerPageSize.width() / scaledPageSize.width(),
2029 printerPageSize.height() / scaledPageSize.height());
2031 doc = clone(
const_cast<QTextDocument *>(
this));
2032 clonedDoc.reset(
const_cast<QTextDocument *>(doc));
2034 for (QTextBlock srcBlock = firstBlock(), dstBlock = clonedDoc->firstBlock();
2035 srcBlock.isValid() && dstBlock.isValid();
2036 srcBlock = srcBlock.next(), dstBlock = dstBlock.next()) {
2037 dstBlock.layout()->setFormats(srcBlock.layout()->formats());
2040 QAbstractTextDocumentLayout *layout = doc->documentLayout();
2041 layout->setPaintDevice(p.device());
2044 layout->d_func()->handlers = documentLayout()->d_func()->handlers;
2047 const int horizontalMargin =
int((2/2.54)*sourceDpiX);
2048 const int verticalMargin =
int((2/2.54)*sourceDpiY);
2049 QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
2050 fmt.setLeftMargin(horizontalMargin);
2051 fmt.setRightMargin(horizontalMargin);
2052 fmt.setTopMargin(verticalMargin);
2053 fmt.setBottomMargin(verticalMargin);
2054 doc->rootFrame()->setFrameFormat(fmt);
2057 const int dpiy = p.device()->logicalDpiY();
2058 body = QRectF(0, 0, printer->width(), printer->height());
2059 pageNumberPos = QPointF(body.width() - horizontalMargin * dpiScaleX,
2060 body.height() - verticalMargin * dpiScaleY
2061 + QFontMetrics(doc->defaultFont(), p.device()).ascent()
2063 clonedDoc->setPageSize(body.size());
2066 const QPageRanges pageRanges = printer->pageRanges();
2067 int fromPage = pageRanges.firstPage();
2068 int toPage = pageRanges.lastPage();
2070 if (fromPage == 0 && toPage == 0) {
2072 toPage = doc->pageCount();
2075 fromPage = qMax(1, fromPage);
2076 toPage = qMin(doc->pageCount(), toPage);
2078 if (toPage < fromPage) {
2092 int page = fromPage;
2094 if (pageRanges.isEmpty() || pageRanges.contains(page))
2095 printPage(page, &p, doc, body, pageNumberPos);
2100 if (!printer->newPage())
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149QVariant QTextDocument::resource(
int type,
const QUrl &name)
const
2151 Q_D(
const QTextDocument);
2152 const QUrl url = d->baseUrl.resolved(name);
2153 QVariant r = d->resources.value(url);
2155 r = d->cachedResources.value(url);
2157 r =
const_cast<QTextDocument *>(
this)->loadResource(type, url);
2159 if (d->resourceProvider)
2160 r = d->resourceProvider(url);
2161 else if (
auto defaultProvider = defaultResourceProvider())
2162 r = defaultProvider(url);
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187void QTextDocument::addResource(
int type,
const QUrl &name,
const QVariant &resource)
2191 d->resources.insert(name, resource);
2195
2196
2197
2198
2199
2200
2201QTextDocument::ResourceProvider QTextDocument::resourceProvider()
const
2203 Q_D(
const QTextDocument);
2204 return d->resourceProvider;
2208
2209
2210
2211
2212
2215
2216
2217
2218
2219
2220
2221void QTextDocument::setResourceProvider(
const ResourceProvider &provider)
2224 d->resourceProvider = provider;
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237void QTextDocument::setDefaultResourceProvider(
const ResourceProvider &provider)
2239 qt_defaultResourceProvider = provider;
2243
2244
2245
2246
2247
2248
2249QTextDocument::ResourceProvider QTextDocument::defaultResourceProvider()
2251 return qt_defaultResourceProvider;
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273QVariant QTextDocument::loadResource(
int type,
const QUrl &name)
2278 QObject *p = parent();
2280 const QMetaObject *me = p->metaObject();
2281 int index = me->indexOfMethod(
"loadResource(int,QUrl)");
2283 QMetaMethod loader = me->method(index);
2285 loader.invoke(p, Qt::DirectConnection, Q_RETURN_ARG(QVariant, r), Q_ARG(
int, type), Q_ARG(QUrl, name));
2290 if (r.isNull() && name.scheme().compare(
"data"_L1, Qt::CaseInsensitive) == 0) {
2293 if (qDecodeDataUrl(name, mimetype, payload))
2298 if (!qobject_cast<QTextDocument *>(p) && r.isNull()) {
2299 QUrl resourceUrl = name;
2301 if (name.isRelative()) {
2302 QUrl currentURL = d->url;
2305 if (!(currentURL.isRelative()
2306 || (currentURL.scheme() ==
"file"_L1
2307 && !QFileInfo(currentURL.toLocalFile()).isAbsolute()))
2308 || (name.hasFragment() && name.path().isEmpty())) {
2309 resourceUrl = currentURL.resolved(name);
2314 QFileInfo fi(currentURL.toLocalFile());
2317 QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(name);
2318 }
else if (currentURL.isEmpty()) {
2319 resourceUrl.setScheme(
"file"_L1);
2324 QString s = resourceUrl.toLocalFile();
2326 if (!s.isEmpty() && f.open(QFile::ReadOnly)) {
2333 if (type == ImageResource && r.userType() == QMetaType::QByteArray) {
2334 if (!QThread::isMainThread()) {
2337 image.loadFromData(r.toByteArray());
2338 if (!image.isNull())
2342 pm.loadFromData(r.toByteArray());
2347 d->cachedResources.insert(name, r);
2354 QTextFormat diff = to;
2356 const QMap<
int, QVariant> props = to.properties();
2357 for (QMap<
int, QVariant>::ConstIterator it = props.begin(), end = props.end();
2359 if (it.value() == from.property(it.key()))
2360 diff.clearProperty(it.key());
2369 if (color.alpha() == 255) {
2370 result = color.name();
2371 }
else if (color.alpha()) {
2372 QString alphaValue = QString::number(color.alphaF(),
'f', 6);
2373 while (alphaValue.size() > 1 && alphaValue.at(alphaValue.size() - 1) == u'0')
2375 if (alphaValue.at(alphaValue.size() - 1) == u'.')
2377 result = QString::fromLatin1(
"rgba(%1,%2,%3,%4)").arg(color.red())
2382 result =
"transparent"_L1;
2389 : doc(_doc), fragmentMarkers(
false)
2391 const QFont defaultFont = doc->defaultFont();
2392 defaultCharFormat.setFont(defaultFont);
2397 return format.fontFamilies().toStringList();
2401
2402
2403
2404
2407 html =
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
2408 "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
2409 "<html><head><meta name=\"qrichtext\" content=\"1\" />"_L1;
2410 html.reserve(QTextDocumentPrivate::get(doc)->length());
2414 html +=
"<meta charset=\"utf-8\" />"_L1;
2416 QString title = doc->metaInformation(QTextDocument::DocumentTitle);
2417 if (!title.isEmpty()) {
2418 html +=
"<title>"_L1;
2420 html +=
"</title>"_L1;
2422 html +=
"<style type=\"text/css\">\n"_L1;
2423 html +=
"p, li { white-space: pre-wrap; }\n"_L1;
2424 html +=
"hr { height: 1px; border-width: 0; }\n"_L1;
2425 html +=
"li.unchecked::marker { content: \"\\2610\"; }\n"_L1;
2426 html +=
"li.checked::marker { content: \"\\2612\"; }\n"_L1;
2427 html +=
"</style>"_L1;
2428 html +=
"</head><body"_L1;
2431 html +=
" style=\""_L1;
2433 emitFontFamily(resolvedFontFamilies(defaultCharFormat));
2435 if (defaultCharFormat.hasProperty(QTextFormat::FontPointSize)) {
2436 html +=
" font-size:"_L1;
2437 html += QString::number(defaultCharFormat.fontPointSize());
2439 }
else if (defaultCharFormat.hasProperty(QTextFormat::FontPixelSize)) {
2440 html +=
" font-size:"_L1;
2441 html += QString::number(defaultCharFormat.intProperty(QTextFormat::FontPixelSize));
2445 html +=
" font-weight:"_L1;
2446 html += QString::number(defaultCharFormat.fontWeight());
2449 html +=
" font-style:"_L1;
2450 html += (defaultCharFormat.fontItalic() ?
"italic"_L1 :
"normal"_L1);
2453 const bool percentSpacing = (defaultCharFormat.fontLetterSpacingType() == QFont::PercentageSpacing);
2454 if (defaultCharFormat.hasProperty(QTextFormat::FontLetterSpacing) &&
2455 (!percentSpacing || defaultCharFormat.fontLetterSpacing() != 0.0)) {
2456 html +=
" letter-spacing:"_L1;
2457 qreal value = defaultCharFormat.fontLetterSpacing();
2459 value = (value / 100) - 1;
2460 html += QString::number(value);
2461 html += percentSpacing ?
"em;"_L1 :
"px;"_L1;
2464 if (defaultCharFormat.hasProperty(QTextFormat::FontWordSpacing) &&
2465 defaultCharFormat.fontWordSpacing() != 0.0) {
2466 html +=
" word-spacing:"_L1;
2467 html += QString::number(defaultCharFormat.fontWordSpacing());
2471 QString decorationTag(
" text-decoration:"_L1);
2472 bool atLeastOneDecorationSet =
false;
2473 if (defaultCharFormat.hasProperty(QTextFormat::FontUnderline) || defaultCharFormat.hasProperty(QTextFormat::TextUnderlineStyle)) {
2474 if (defaultCharFormat.fontUnderline()) {
2475 decorationTag +=
" underline"_L1;
2476 atLeastOneDecorationSet =
true;
2479 if (defaultCharFormat.hasProperty(QTextFormat::FontOverline)) {
2480 if (defaultCharFormat.fontOverline()) {
2481 decorationTag +=
" overline"_L1;
2482 atLeastOneDecorationSet =
true;
2485 if (defaultCharFormat.hasProperty(QTextFormat::FontStrikeOut)) {
2486 if (defaultCharFormat.fontStrikeOut()) {
2487 decorationTag +=
" line-through"_L1;
2488 atLeastOneDecorationSet =
true;
2491 if (atLeastOneDecorationSet)
2492 html += decorationTag + u';';
2496 const QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
2497 emitBackgroundAttribute(fmt);
2500 defaultCharFormat = QTextCharFormat();
2504 QTextFrameFormat rootFmt = doc->rootFrame()->frameFormat();
2505 rootFmt.clearProperty(QTextFormat::BackgroundBrush);
2507 QTextFrameFormat defaultFmt;
2508 defaultFmt.setMargin(doc->documentMargin());
2510 if (rootFmt == defaultFmt)
2511 emitFrame(doc->rootFrame()->begin());
2513 emitTextFrame(doc->rootFrame());
2515 html +=
"</body></html>"_L1;
2519void QTextHtmlExporter::emitAttribute(
const char *attribute,
const QString &value)
2522 html += QLatin1StringView(attribute);
2524 html += value.toHtmlEscaped();
2530 bool attributesEmitted =
false;
2533 const QStringList families = resolvedFontFamilies(format);
2534 if (!families.isEmpty() && families != resolvedFontFamilies(defaultCharFormat)) {
2535 emitFontFamily(families);
2536 attributesEmitted =
true;
2540 if (format.hasProperty(QTextFormat::FontPointSize)
2541 && format.fontPointSize() != defaultCharFormat.fontPointSize()) {
2542 html +=
" font-size:"_L1;
2543 html += QString::number(format.fontPointSize());
2545 attributesEmitted =
true;
2546 }
else if (format.hasProperty(QTextFormat::FontSizeAdjustment)) {
2547 static const char sizeNameData[] =
2551 static const quint8 sizeNameOffsets[] = {
2554 sizeof(
"small") +
sizeof(
"medium") + 3,
2555 sizeof(
"small") +
sizeof(
"medium") + 1,
2556 sizeof(
"small") +
sizeof(
"medium"),
2558 const char *name =
nullptr;
2559 const int idx = format.intProperty(QTextFormat::FontSizeAdjustment) + 1;
2560 if (idx >= 0 && idx <= 4) {
2561 name = sizeNameData + sizeNameOffsets[idx];
2564 html +=
" font-size:"_L1;
2565 html += QLatin1StringView(name);
2567 attributesEmitted =
true;
2569 }
else if (format.hasProperty(QTextFormat::FontPixelSize)
2570 && format.property(QTextFormat::FontPixelSize)
2571 != defaultCharFormat.property(QTextFormat::FontPixelSize)) {
2572 html +=
" font-size:"_L1;
2573 html += QString::number(format.intProperty(QTextFormat::FontPixelSize));
2575 attributesEmitted =
true;
2578 if (format.hasProperty(QTextFormat::FontWeight)
2579 && format.fontWeight() != defaultCharFormat.fontWeight()) {
2580 html +=
" font-weight:"_L1;
2581 html += QString::number(format.fontWeight());
2583 attributesEmitted =
true;
2586 if (format.hasProperty(QTextFormat::FontItalic)
2587 && format.fontItalic() != defaultCharFormat.fontItalic()) {
2588 html +=
" font-style:"_L1;
2589 html += (format.fontItalic() ?
"italic"_L1 :
"normal"_L1);
2591 attributesEmitted =
true;
2594 const auto decorationTag =
" text-decoration:"_L1;
2595 html += decorationTag;
2596 bool hasDecoration =
false;
2597 bool atLeastOneDecorationSet =
false;
2599 if ((format.hasProperty(QTextFormat::FontUnderline) || format.hasProperty(QTextFormat::TextUnderlineStyle))
2600 && format.fontUnderline() != defaultCharFormat.fontUnderline()) {
2601 hasDecoration =
true;
2602 if (format.fontUnderline()) {
2603 html +=
" underline"_L1;
2604 atLeastOneDecorationSet =
true;
2608 if (format.hasProperty(QTextFormat::FontOverline)
2609 && format.fontOverline() != defaultCharFormat.fontOverline()) {
2610 hasDecoration =
true;
2611 if (format.fontOverline()) {
2612 html +=
" overline"_L1;
2613 atLeastOneDecorationSet =
true;
2617 if (format.hasProperty(QTextFormat::FontStrikeOut)
2618 && format.fontStrikeOut() != defaultCharFormat.fontStrikeOut()) {
2619 hasDecoration =
true;
2620 if (format.fontStrikeOut()) {
2621 html +=
" line-through"_L1;
2622 atLeastOneDecorationSet =
true;
2626 if (hasDecoration) {
2627 if (!atLeastOneDecorationSet)
2630 if (format.hasProperty(QTextFormat::TextUnderlineColor)) {
2631 html +=
" text-decoration-color:"_L1;
2632 html += colorValue(format.underlineColor());
2635 attributesEmitted =
true;
2637 html.chop(decorationTag.size());
2640 if (format.foreground() != defaultCharFormat.foreground()
2641 && format.foreground().style() != Qt::NoBrush) {
2642 QBrush brush = format.foreground();
2643 if (brush.style() == Qt::TexturePattern) {
2644 const bool isPixmap = qHasPixmapTexture(brush);
2645 const qint64 cacheKey = isPixmap ? brush.texture().cacheKey() : brush.textureImage().cacheKey();
2647 html +=
" -qt-fg-texture-cachekey:"_L1;
2648 html += QString::number(cacheKey);
2650 }
else if (brush.style() == Qt::LinearGradientPattern
2651 || brush.style() == Qt::RadialGradientPattern
2652 || brush.style() == Qt::ConicalGradientPattern) {
2653 const QGradient *gradient = brush.gradient();
2654 if (gradient->type() == QGradient::LinearGradient) {
2655 const QLinearGradient *linearGradient =
static_cast<
const QLinearGradient *>(brush.gradient());
2657 html +=
" -qt-foreground: qlineargradient("_L1;
2658 html +=
"x1:"_L1 + QString::number(linearGradient->start().x()) + u',';
2659 html +=
"y1:"_L1 + QString::number(linearGradient->start().y()) + u',';
2660 html +=
"x2:"_L1 + QString::number(linearGradient->finalStop().x()) + u',';
2661 html +=
"y2:"_L1 + QString::number(linearGradient->finalStop().y()) + u',';
2662 }
else if (gradient->type() == QGradient::RadialGradient) {
2663 const QRadialGradient *radialGradient =
static_cast<
const QRadialGradient *>(brush.gradient());
2665 html +=
" -qt-foreground: qradialgradient("_L1;
2666 html +=
"cx:"_L1 + QString::number(radialGradient->center().x()) + u',';
2667 html +=
"cy:"_L1 + QString::number(radialGradient->center().y()) + u',';
2668 html +=
"fx:"_L1 + QString::number(radialGradient->focalPoint().x()) + u',';
2669 html +=
"fy:"_L1 + QString::number(radialGradient->focalPoint().y()) + u',';
2670 html +=
"radius:"_L1 + QString::number(radialGradient->radius()) + u',';
2672 const QConicalGradient *conicalGradient =
static_cast<
const QConicalGradient *>(brush.gradient());
2674 html +=
" -qt-foreground: qconicalgradient("_L1;
2675 html +=
"cx:"_L1 + QString::number(conicalGradient->center().x()) + u',';
2676 html +=
"cy:"_L1 + QString::number(conicalGradient->center().y()) + u',';
2677 html +=
"angle:"_L1 + QString::number(conicalGradient->angle()) + u',';
2680 const QStringList coordinateModes = {
"logical"_L1,
"stretchtodevice"_L1,
"objectbounding"_L1,
"object"_L1 };
2681 html +=
"coordinatemode:"_L1;
2682 html += coordinateModes.at(
int(gradient->coordinateMode()));
2685 const QStringList spreads = {
"pad"_L1,
"reflect"_L1,
"repeat"_L1 };
2686 html +=
"spread:"_L1;
2687 html += spreads.at(
int(gradient->spread()));
2689 for (
const QGradientStop &stop : gradient->stops()) {
2690 html +=
",stop:"_L1;
2691 html += QString::number(stop.first);
2693 html += colorValue(stop.second);
2698 html +=
" color:"_L1;
2699 html += colorValue(brush.color());
2702 attributesEmitted =
true;
2705 if (format.background() != defaultCharFormat.background()
2706 && format.background().style() == Qt::SolidPattern) {
2707 html +=
" background-color:"_L1;
2708 html += colorValue(format.background().color());
2710 attributesEmitted =
true;
2713 if (format.verticalAlignment() != defaultCharFormat.verticalAlignment()
2714 && format.verticalAlignment() != QTextCharFormat::AlignNormal)
2716 html +=
" vertical-align:"_L1;
2718 QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
2719 if (valign == QTextCharFormat::AlignSubScript)
2721 else if (valign == QTextCharFormat::AlignSuperScript)
2723 else if (valign == QTextCharFormat::AlignMiddle)
2724 html +=
"middle"_L1;
2725 else if (valign == QTextCharFormat::AlignTop)
2727 else if (valign == QTextCharFormat::AlignBottom)
2728 html +=
"bottom"_L1;
2731 attributesEmitted =
true;
2734 if (format.fontCapitalization() != QFont::MixedCase) {
2735 const QFont::Capitalization caps = format.fontCapitalization();
2736 if (caps == QFont::AllUppercase)
2737 html +=
" text-transform:uppercase;"_L1;
2738 else if (caps == QFont::AllLowercase)
2739 html +=
" text-transform:lowercase;"_L1;
2740 else if (caps == QFont::SmallCaps)
2741 html +=
" font-variant:small-caps;"_L1;
2742 attributesEmitted =
true;
2745 if (format.fontWordSpacing() != 0.0) {
2746 html +=
" word-spacing:"_L1;
2747 html += QString::number(format.fontWordSpacing());
2749 attributesEmitted =
true;
2752 if (format.hasProperty(QTextFormat::TextOutline)) {
2753 QPen outlinePen = format.textOutline();
2754 html +=
" -qt-stroke-color:"_L1;
2755 html += colorValue(outlinePen.color());
2758 html +=
" -qt-stroke-width:"_L1;
2759 html += QString::number(outlinePen.widthF());
2762 html +=
" -qt-stroke-linecap:"_L1;
2763 if (outlinePen.capStyle() == Qt::SquareCap)
2764 html +=
"squarecap;"_L1;
2765 else if (outlinePen.capStyle() == Qt::FlatCap)
2766 html +=
"flatcap;"_L1;
2767 else if (outlinePen.capStyle() == Qt::RoundCap)
2768 html +=
"roundcap;"_L1;
2770 html +=
" -qt-stroke-linejoin:"_L1;
2771 if (outlinePen.joinStyle() == Qt::MiterJoin)
2772 html +=
"miterjoin;"_L1;
2773 else if (outlinePen.joinStyle() == Qt::SvgMiterJoin)
2774 html +=
"svgmiterjoin;"_L1;
2775 else if (outlinePen.joinStyle() == Qt::BevelJoin)
2776 html +=
"beveljoin;"_L1;
2777 else if (outlinePen.joinStyle() == Qt::RoundJoin)
2778 html +=
"roundjoin;"_L1;
2780 if (outlinePen.joinStyle() == Qt::MiterJoin ||
2781 outlinePen.joinStyle() == Qt::SvgMiterJoin) {
2782 html +=
" -qt-stroke-miterlimit:"_L1;
2783 html += QString::number(outlinePen.miterLimit());
2787 if (outlinePen.style() == Qt::CustomDashLine && !outlinePen.dashPattern().empty()) {
2788 html +=
" -qt-stroke-dasharray:"_L1;
2790 QList<qreal> dashes = outlinePen.dashPattern();
2792 for (
int i = 0; i < dashes.length() - 1; i++) {
2793 qreal dash = dashes[i];
2794 dashArrayString += QString::number(dash) + u',';
2797 dashArrayString += QString::number(dashes.last());
2798 html += dashArrayString;
2801 html +=
" -qt-stroke-dashoffset:"_L1;
2802 html += QString::number(outlinePen.dashOffset());
2806 attributesEmitted =
true;
2809 return attributesEmitted;
2812void QTextHtmlExporter::emitTextLength(
const char *attribute,
const QTextLength &length)
2814 if (length.type() == QTextLength::VariableLength)
2818 html += QLatin1StringView(attribute);
2820 html += QString::number(length.rawValue());
2822 if (length.type() == QTextLength::PercentageLength)
2830 if (align & Qt::AlignLeft)
2832 else if (align & Qt::AlignRight)
2833 html +=
" align=\"right\""_L1;
2834 else if (align & Qt::AlignHCenter)
2835 html +=
" align=\"center\""_L1;
2836 else if (align & Qt::AlignJustify)
2837 html +=
" align=\"justify\""_L1;
2840void QTextHtmlExporter::emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode)
2842 if (pos == QTextFrameFormat::InFlow)
2845 if (mode == EmitStyleTag)
2846 html +=
" style=\"float:"_L1;
2848 html +=
" float:"_L1;
2850 if (pos == QTextFrameFormat::FloatLeft)
2851 html +=
" left;"_L1;
2852 else if (pos == QTextFrameFormat::FloatRight)
2853 html +=
" right;"_L1;
2855 Q_ASSERT_X(0,
"QTextHtmlExporter::emitFloatStyle()",
"pos should be a valid enum type");
2857 if (mode == EmitStyleTag)
2864 case QTextFrameFormat::BorderStyle_None:
2866 case QTextFrameFormat::BorderStyle_Dotted:
2868 case QTextFrameFormat::BorderStyle_Dashed:
2870 case QTextFrameFormat::BorderStyle_Solid:
2872 case QTextFrameFormat::BorderStyle_Double:
2874 case QTextFrameFormat::BorderStyle_DotDash:
2875 return "dot-dash"_L1;
2876 case QTextFrameFormat::BorderStyle_DotDotDash:
2877 return "dot-dot-dash"_L1;
2878 case QTextFrameFormat::BorderStyle_Groove:
2880 case QTextFrameFormat::BorderStyle_Ridge:
2882 case QTextFrameFormat::BorderStyle_Inset:
2884 case QTextFrameFormat::BorderStyle_Outset:
2894 Q_ASSERT(style <= QTextFrameFormat::BorderStyle_Outset);
2896 html +=
" border-style:"_L1;
2897 html += richtextBorderStyleToHtmlBorderStyle(style);
2903 if (policy & QTextFormat::PageBreak_AlwaysBefore)
2904 html +=
" page-break-before:always;"_L1;
2906 if (policy & QTextFormat::PageBreak_AlwaysAfter)
2907 html +=
" page-break-after:always;"_L1;
2912 html +=
" font-family:"_L1;
2915 for (
const QString &family : families) {
2916 auto quote =
"\'"_L1;
2917 if (family.contains(u'\''))
2918 quote =
"""_L1;
2925 html += family.toHtmlEscaped();
2931void QTextHtmlExporter::emitMargins(
const QString &top,
const QString &bottom,
const QString &left,
const QString &right)
2933 html +=
" margin-top:"_L1;
2937 html +=
" margin-bottom:"_L1;
2941 html +=
" margin-left:"_L1;
2945 html +=
" margin-right:"_L1;
2952 const QTextCharFormat format = fragment.charFormat();
2954 bool closeAnchor =
false;
2956 if (format.isAnchor()) {
2957 const auto names = format.anchorNames();
2958 if (!names.isEmpty()) {
2959 html +=
"<a name=\""_L1;
2960 html += names.constFirst().toHtmlEscaped();
2961 html +=
"\"></a>"_L1;
2963 const QString href = format.anchorHref();
2964 if (!href.isEmpty()) {
2965 html +=
"<a href=\""_L1;
2966 html += href.toHtmlEscaped();
2972 QString txt = fragment.text();
2973 const bool isObject = txt.contains(QChar::ObjectReplacementCharacter);
2974 const bool isImage = isObject && format.isImageFormat();
2976 const auto styleTag =
"<span style=\""_L1;
2979 bool attributesEmitted =
false;
2981 attributesEmitted = emitCharFormatStyle(format);
2982 if (attributesEmitted)
2985 html.chop(styleTag.size());
2988 for (
int i = 0; isImage && i < txt.size(); ++i) {
2989 QTextImageFormat imgFmt = format.toImageFormat();
2995 if (imgFmt.hasProperty(QTextFormat::ImageMaxWidth)) {
2996 auto length = imgFmt.lengthProperty(QTextFormat::ImageMaxWidth);
2997 maxWidthCss +=
"max-width:"_L1;
2998 if (length.type() == QTextLength::PercentageLength)
2999 maxWidthCss += QString::number(length.rawValue()) +
"%;"_L1;
3000 else if (length.type() == QTextLength::FixedLength)
3001 maxWidthCss += QString::number(length.rawValue()) +
"px;"_L1;
3004 if (imgFmt.hasProperty(QTextFormat::ImageName))
3005 emitAttribute(
"src", imgFmt.name());
3007 if (imgFmt.hasProperty(QTextFormat::ImageAltText))
3008 emitAttribute(
"alt", imgFmt.stringProperty(QTextFormat::ImageAltText));
3010 if (imgFmt.hasProperty(QTextFormat::ImageTitle))
3011 emitAttribute(
"title", imgFmt.stringProperty(QTextFormat::ImageTitle));
3013 if (imgFmt.hasProperty(QTextFormat::ImageWidth))
3014 emitAttribute(
"width", QString::number(imgFmt.width()));
3016 if (imgFmt.hasProperty(QTextFormat::ImageHeight))
3017 emitAttribute(
"height", QString::number(imgFmt.height()));
3019 if (imgFmt.verticalAlignment() == QTextCharFormat::AlignMiddle)
3020 html +=
" style=\"vertical-align: middle;"_L1 + maxWidthCss + u'\"';
3021 else if (imgFmt.verticalAlignment() == QTextCharFormat::AlignTop)
3022 html +=
" style=\"vertical-align: top;"_L1 + maxWidthCss + u'\"';
3023 else if (!maxWidthCss.isEmpty())
3024 html +=
" style=\""_L1 + maxWidthCss + u'\"';
3026 if (QTextFrame *imageFrame = qobject_cast<QTextFrame *>(doc->objectForFormat(imgFmt)))
3027 emitFloatStyle(imageFrame->frameFormat().position());
3032 Q_ASSERT(!txt.contains(QChar::ObjectReplacementCharacter));
3034 txt = txt.toHtmlEscaped();
3038 txt.replace(u'\n',
"<br />"_L1);
3039 txt.replace(QChar::LineSeparator,
"<br />"_L1);
3043 if (attributesEmitted)
3044 html +=
"</span>"_L1;
3052 return style == QTextListFormat::ListDecimal || style == QTextListFormat::ListLowerAlpha
3053 || style == QTextListFormat::ListUpperAlpha
3054 || style == QTextListFormat::ListUpperRoman
3055 || style == QTextListFormat::ListLowerRoman
3061 QTextBlockFormat format = block.blockFormat();
3062 emitAlignment(format.alignment());
3066 if (block.textDirection() == Qt::RightToLeft)
3067 html +=
" dir='rtl'"_L1;
3069 const auto style =
" style=\""_L1;
3072 const bool emptyBlock = block.begin().atEnd();
3074 html +=
"-qt-paragraph-type:empty;"_L1;
3077 emitMargins(QString::number(format.topMargin()),
3078 QString::number(format.bottomMargin()),
3079 QString::number(format.leftMargin()),
3080 QString::number(format.rightMargin()));
3082 html +=
" -qt-block-indent:"_L1;
3083 html += QString::number(format.indent());
3086 html +=
" text-indent:"_L1;
3087 html += QString::number(format.textIndent());
3090 if (block.userState() != -1) {
3091 html +=
" -qt-user-state:"_L1;
3092 html += QString::number(block.userState());
3096 if (format.lineHeightType() != QTextBlockFormat::SingleHeight) {
3097 html +=
" line-height:"_L1
3098 + QString::number(format.lineHeight());
3099 switch (format.lineHeightType()) {
3100 case QTextBlockFormat::ProportionalHeight:
3103 case QTextBlockFormat::FixedHeight:
3104 html +=
"; -qt-line-height-type: fixed;"_L1;
3106 case QTextBlockFormat::MinimumHeight:
3109 case QTextBlockFormat::LineDistanceHeight:
3110 html +=
"; -qt-line-height-type: line-distance;"_L1;
3118 emitPageBreakPolicy(format.pageBreakPolicy());
3120 QTextCharFormat diff;
3122 const QTextCharFormat blockCharFmt = block.charFormat();
3123 diff = formatDifference(defaultCharFormat, blockCharFmt).toCharFormat();
3126 diff.clearProperty(QTextFormat::BackgroundBrush);
3127 if (format.hasProperty(QTextFormat::BackgroundBrush)) {
3128 QBrush bg = format.background();
3129 if (bg.style() != Qt::NoBrush)
3130 diff.setProperty(QTextFormat::BackgroundBrush, format.property(QTextFormat::BackgroundBrush));
3133 if (!diff.properties().isEmpty())
3134 emitCharFormatStyle(diff);
3142 if (block.begin().atEnd()) {
3144 int p = block.position();
3148 QTextDocumentPrivate::FragmentIterator frag = QTextDocumentPrivate::get(doc)->find(p);
3149 QChar ch = QTextDocumentPrivate::get(doc)->buffer().at(frag->stringPosition);
3159 QTextCharFormat oldDefaultCharFormat = defaultCharFormat;
3161 QTextList *list = block.textList();
3163 if (list->itemNumber(block) == 0) {
3164 const QTextListFormat format = list->format();
3165 const int style = format.style();
3166 bool ordered =
false;
3168 case QTextListFormat::ListDisc: html +=
"<ul"_L1;
break;
3169 case QTextListFormat::ListCircle: html +=
"<ul type=\"circle\""_L1;
break;
3170 case QTextListFormat::ListSquare: html +=
"<ul type=\"square\""_L1;
break;
3171 case QTextListFormat::ListDecimal: html +=
"<ol"_L1; ordered =
true;
break;
3172 case QTextListFormat::ListLowerAlpha: html +=
"<ol type=\"a\""_L1; ordered =
true;
break;
3173 case QTextListFormat::ListUpperAlpha: html +=
"<ol type=\"A\""_L1; ordered =
true;
break;
3174 case QTextListFormat::ListLowerRoman: html +=
"<ol type=\"i\""_L1; ordered =
true;
break;
3175 case QTextListFormat::ListUpperRoman: html +=
"<ol type=\"I\""_L1; ordered =
true;
break;
3176 default: html +=
"<ul"_L1;
3179 if (ordered && format.start() != 1) {
3180 html +=
" start=\""_L1;
3181 html += QString::number(format.start());
3186 styleString +=
"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px;"_L1;
3188 if (format.hasProperty(QTextFormat::ListIndent)) {
3189 styleString +=
" -qt-list-indent: "_L1;
3190 styleString += QString::number(format.indent());
3191 styleString += u';';
3194 if (format.hasProperty(QTextFormat::ListNumberPrefix)) {
3195 QString numberPrefix = format.numberPrefix();
3196 numberPrefix.replace(u'"',
"\\22"_L1);
3197 numberPrefix.replace(u'\'',
"\\27"_L1);
3198 styleString +=
" -qt-list-number-prefix: "_L1;
3199 styleString += u'\'';
3200 styleString += numberPrefix;
3201 styleString += u'\'';
3202 styleString += u';';
3205 if (format.hasProperty(QTextFormat::ListNumberSuffix)) {
3206 if (format.numberSuffix() !=
"."_L1) {
3207 QString numberSuffix = format.numberSuffix();
3208 numberSuffix.replace(u'"',
"\\22"_L1);
3209 numberSuffix.replace(u'\'',
"\\27"_L1);
3210 styleString +=
" -qt-list-number-suffix: "_L1;
3211 styleString += u'\'';
3212 styleString += numberSuffix;
3213 styleString += u'\'';
3214 styleString += u';';
3218 html +=
" style=\""_L1;
3219 html += styleString;
3225 const QTextCharFormat blockFmt = formatDifference(defaultCharFormat, block.charFormat()).toCharFormat();
3226 if (!blockFmt.properties().isEmpty()) {
3227 html +=
" style=\""_L1;
3228 emitCharFormatStyle(blockFmt);
3231 defaultCharFormat.merge(block.charFormat());
3233 if (block.blockFormat().hasProperty(QTextFormat::BlockMarker)) {
3234 switch (block.blockFormat().marker()) {
3235 case QTextBlockFormat::MarkerType::Checked:
3236 html +=
" class=\"checked\""_L1;
3238 case QTextBlockFormat::MarkerType::Unchecked:
3239 html +=
" class=\"unchecked\""_L1;
3241 case QTextBlockFormat::MarkerType::NoMarker:
3247 const QTextBlockFormat blockFormat = block.blockFormat();
3248 if (blockFormat.hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)) {
3251 QTextLength width = blockFormat.lengthProperty(QTextFormat::BlockTrailingHorizontalRulerWidth);
3252 if (width.type() != QTextLength::VariableLength)
3253 emitTextLength(
"width", width);
3256 if (blockFormat.hasProperty(QTextFormat::BackgroundBrush)) {
3257 html +=
"style=\""_L1;
3258 html +=
"background-color:"_L1;
3259 html += colorValue(qvariant_cast<QBrush>(blockFormat.property(QTextFormat::BackgroundBrush)).color());
3268 const bool pre = blockFormat.nonBreakableLines();
3274 int headingLevel = blockFormat.headingLevel();
3275 if (headingLevel > 0 && headingLevel <= 6)
3276 html +=
"<h"_L1 + QString::number(headingLevel);
3281 emitBlockAttributes(block);
3284 if (block.begin().atEnd())
3285 html +=
"<br />"_L1;
3287 QTextBlock::Iterator it = block.begin();
3288 if (fragmentMarkers && !it.atEnd() && block == doc->begin())
3289 html +=
"<!--StartFragment-->"_L1;
3291 for (; !it.atEnd(); ++it)
3292 emitFragment(it.fragment());
3294 if (fragmentMarkers && block.position() + block.length() == QTextDocumentPrivate::get(doc)->length())
3295 html +=
"<!--EndFragment-->"_L1;
3300 html +=
"</pre>"_L1;
3302 closeTags +=
"</li>"_L1;
3304 int headingLevel = blockFormat.headingLevel();
3305 if (headingLevel > 0 && headingLevel <= 6)
3306 html += QString::asprintf(
"</h%d>", headingLevel);
3312 if (list->itemNumber(block) == list->count() - 1) {
3313 if (isOrderedList(list->format().style()))
3314 closeTags +=
"</ol>"_L1;
3316 closeTags +=
"</ul>"_L1;
3318 const QTextBlock nextBlock = block.next();
3322 if (nextBlock.isValid() && nextBlock.textList() &&
3323 nextBlock.textList()->itemNumber(nextBlock) == 0 &&
3324 nextBlock.textList()->format().indent() > list->format().indent()) {
3326 if (!closingTags.isEmpty() && list->itemNumber(block) == list->count() - 1)
3327 lastTag = closingTags.takeLast();
3328 lastTag.prepend(closeTags);
3329 closingTags << lastTag;
3330 }
else if (list->itemNumber(block) == list->count() - 1) {
3334 if (!closingTags.isEmpty())
3335 html += closingTags.takeLast();
3341 defaultCharFormat = oldDefaultCharFormat;
3346QString
QTextHtmlExporter::findUrlForImage(
const QTextDocument *doc, qint64 cacheKey,
bool isPixmap)
3352 if (QTextDocument *parent = qobject_cast<QTextDocument *>(doc->parent()))
3353 return findUrlForImage(parent, cacheKey, isPixmap);
3355 const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(doc);
3356 Q_ASSERT(priv !=
nullptr);
3358 QMap<QUrl, QVariant>::const_iterator it = priv->cachedResources.constBegin();
3359 for (; it != priv->cachedResources.constEnd(); ++it) {
3361 const QVariant &v = it.value();
3362 if (v.userType() == QMetaType::QImage && !isPixmap) {
3363 if (qvariant_cast<QImage>(v).cacheKey() == cacheKey)
3367 if (v.userType() == QMetaType::QPixmap && isPixmap) {
3368 if (qvariant_cast<QPixmap>(v).cacheKey() == cacheKey)
3373 if (it != priv->cachedResources.constEnd())
3374 url = it.key().toString();
3379void QTextDocumentPrivate::mergeCachedResources(
const QTextDocumentPrivate *priv)
3384 cachedResources.insert(priv->cachedResources);
3389 if (format.hasProperty(QTextFormat::BackgroundImageUrl)) {
3390 QString url = format.property(QTextFormat::BackgroundImageUrl).toString();
3391 emitAttribute(
"background", url);
3393 const QBrush &brush = format.background();
3394 if (brush.style() == Qt::SolidPattern) {
3395 emitAttribute(
"bgcolor", colorValue(brush.color()));
3396 }
else if (brush.style() == Qt::TexturePattern) {
3398 const qint64 cacheKey = isPixmap ? brush.texture().cacheKey() : brush.textureImage().cacheKey();
3400 const QString url = findUrlForImage(doc, cacheKey, isPixmap);
3403 emitAttribute(
"background", url);
3410 QTextTableFormat format = table->format();
3412 html +=
"\n<table"_L1;
3414 if (format.hasProperty(QTextFormat::FrameBorder))
3415 emitAttribute(
"border", QString::number(format.border()));
3417 emitFrameStyle(format, TableFrame);
3419 emitAlignment(format.alignment());
3420 emitTextLength(
"width", format.width());
3422 if (format.hasProperty(QTextFormat::TableCellSpacing))
3423 emitAttribute(
"cellspacing", QString::number(format.cellSpacing()));
3424 if (format.hasProperty(QTextFormat::TableCellPadding))
3425 emitAttribute(
"cellpadding", QString::number(format.cellPadding()));
3427 emitBackgroundAttribute(format);
3431 const int rows = table->rows();
3432 const int columns = table->columns();
3434 QList<QTextLength> columnWidths = format.columnWidthConstraints();
3435 if (columnWidths.isEmpty()) {
3436 columnWidths.resize(columns);
3437 columnWidths.fill(QTextLength());
3439 Q_ASSERT(columnWidths.size() == columns);
3441 QVarLengthArray<
bool> widthEmittedForColumn(columns);
3442 for (
int i = 0; i < columns; ++i)
3443 widthEmittedForColumn[i] =
false;
3445 const int headerRowCount = qMin(format.headerRowCount(), rows);
3446 if (headerRowCount > 0)
3447 html +=
"<thead>"_L1;
3449 for (
int row = 0; row < rows; ++row) {
3450 html +=
"\n<tr>"_L1;
3452 for (
int col = 0; col < columns; ++col) {
3453 const QTextTableCell cell = table->cellAt(row, col);
3456 if (cell.row() != row)
3459 if (cell.column() != col)
3464 if (!widthEmittedForColumn[col] && cell.columnSpan() == 1) {
3465 emitTextLength(
"width", columnWidths.at(col));
3466 widthEmittedForColumn[col] =
true;
3469 if (cell.columnSpan() > 1)
3470 emitAttribute(
"colspan", QString::number(cell.columnSpan()));
3472 if (cell.rowSpan() > 1)
3473 emitAttribute(
"rowspan", QString::number(cell.rowSpan()));
3475 const QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
3476 emitBackgroundAttribute(cellFormat);
3478 QTextCharFormat oldDefaultCharFormat = defaultCharFormat;
3480 QTextCharFormat::VerticalAlignment valign = cellFormat.verticalAlignment();
3483 if (valign >= QTextCharFormat::AlignMiddle && valign <= QTextCharFormat::AlignBottom) {
3484 styleString +=
" vertical-align:"_L1;
3486 case QTextCharFormat::AlignMiddle:
3487 styleString +=
"middle"_L1;
3489 case QTextCharFormat::AlignTop:
3490 styleString +=
"top"_L1;
3492 case QTextCharFormat::AlignBottom:
3493 styleString +=
"bottom"_L1;
3498 styleString += u';';
3500 QTextCharFormat temp;
3501 temp.setVerticalAlignment(valign);
3502 defaultCharFormat.merge(temp);
3505 if (cellFormat.hasProperty(QTextFormat::TableCellLeftPadding))
3506 styleString +=
" padding-left:"_L1 + QString::number(cellFormat.leftPadding()) + u';';
3507 if (cellFormat.hasProperty(QTextFormat::TableCellRightPadding))
3508 styleString +=
" padding-right:"_L1 + QString::number(cellFormat.rightPadding()) + u';';
3509 if (cellFormat.hasProperty(QTextFormat::TableCellTopPadding))
3510 styleString +=
" padding-top:"_L1 + QString::number(cellFormat.topPadding()) + u';';
3511 if (cellFormat.hasProperty(QTextFormat::TableCellBottomPadding))
3512 styleString +=
" padding-bottom:"_L1 + QString::number(cellFormat.bottomPadding()) + u';';
3514 if (cellFormat.hasProperty(QTextFormat::TableCellTopBorder))
3515 styleString +=
" border-top:"_L1 + QString::number(cellFormat.topBorder()) +
"px;"_L1;
3516 if (cellFormat.hasProperty(QTextFormat::TableCellRightBorder))
3517 styleString +=
" border-right:"_L1 + QString::number(cellFormat.rightBorder()) +
"px;"_L1;
3518 if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorder))
3519 styleString +=
" border-bottom:"_L1 + QString::number(cellFormat.bottomBorder()) +
"px;"_L1;
3520 if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorder))
3521 styleString +=
" border-left:"_L1 + QString::number(cellFormat.leftBorder()) +
"px;"_L1;
3523 if (cellFormat.hasProperty(QTextFormat::TableCellTopBorderBrush))
3524 styleString +=
" border-top-color:"_L1 + cellFormat.topBorderBrush().color().name() + u';';
3525 if (cellFormat.hasProperty(QTextFormat::TableCellRightBorderBrush))
3526 styleString +=
" border-right-color:"_L1 + cellFormat.rightBorderBrush().color().name() + u';';
3527 if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorderBrush))
3528 styleString +=
" border-bottom-color:"_L1 + cellFormat.bottomBorderBrush().color().name() + u';';
3529 if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorderBrush))
3530 styleString +=
" border-left-color:"_L1 + cellFormat.leftBorderBrush().color().name() + u';';
3532 if (cellFormat.hasProperty(QTextFormat::TableCellTopBorderStyle))
3533 styleString +=
" border-top-style:"_L1 + richtextBorderStyleToHtmlBorderStyle(cellFormat.topBorderStyle()) + u';';
3534 if (cellFormat.hasProperty(QTextFormat::TableCellRightBorderStyle))
3535 styleString +=
" border-right-style:"_L1 + richtextBorderStyleToHtmlBorderStyle(cellFormat.rightBorderStyle()) + u';';
3536 if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorderStyle))
3537 styleString +=
" border-bottom-style:"_L1 + richtextBorderStyleToHtmlBorderStyle(cellFormat.bottomBorderStyle()) + u';';
3538 if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorderStyle))
3539 styleString +=
" border-left-style:"_L1 + richtextBorderStyleToHtmlBorderStyle(cellFormat.leftBorderStyle()) + u';';
3541 if (!styleString.isEmpty())
3542 html +=
" style=\""_L1 + styleString + u'\"';
3546 emitFrame(cell.begin());
3550 defaultCharFormat = oldDefaultCharFormat;
3554 if (headerRowCount > 0 && row == headerRowCount - 1)
3555 html +=
"</thead>"_L1;
3558 html +=
"</table>"_L1;
3563 if (!frameIt.atEnd()) {
3564 QTextFrame::Iterator next = frameIt;
3567 && frameIt.currentFrame() ==
nullptr
3568 && frameIt.parentFrame() != doc->rootFrame()
3569 && frameIt.currentBlock().begin().atEnd())
3573 for (QTextFrame::Iterator it = frameIt;
3574 !it.atEnd(); ++it) {
3575 if (QTextFrame *f = it.currentFrame()) {
3576 if (QTextTable *table = qobject_cast<QTextTable *>(f)) {
3581 }
else if (it.currentBlock().isValid()) {
3582 emitBlock(it.currentBlock());
3589 FrameType frameType = f->parentFrame() ? TextFrame : RootFrame;
3591 html +=
"\n<table"_L1;
3592 QTextFrameFormat format = f->frameFormat();
3594 if (format.hasProperty(QTextFormat::FrameBorder))
3595 emitAttribute(
"border", QString::number(format.border()));
3597 emitFrameStyle(format, frameType);
3599 emitTextLength(
"width", format.width());
3600 emitTextLength(
"height", format.height());
3603 if (frameType != RootFrame)
3604 emitBackgroundAttribute(format);
3607 html +=
"\n<tr>\n<td style=\"border: none;\">"_L1;
3608 emitFrame(f->begin());
3609 html +=
"</td></tr></table>"_L1;
3612void QTextHtmlExporter::emitFrameStyle(
const QTextFrameFormat &format, FrameType frameType)
3614 const auto styleAttribute =
" style=\""_L1;
3615 html += styleAttribute;
3616 const qsizetype originalHtmlLength = html.size();
3618 if (frameType == TextFrame)
3619 html +=
"-qt-table-type: frame;"_L1;
3620 else if (frameType == RootFrame)
3621 html +=
"-qt-table-type: root;"_L1;
3623 const QTextFrameFormat defaultFormat;
3625 emitFloatStyle(format.position(), OmitStyleTag);
3626 emitPageBreakPolicy(format.pageBreakPolicy());
3628 if (format.borderBrush() != defaultFormat.borderBrush()) {
3629 html +=
" border-color:"_L1;
3630 html += colorValue(format.borderBrush().color());
3634 if (format.borderStyle() != defaultFormat.borderStyle())
3635 emitBorderStyle(format.borderStyle());
3637 if (format.hasProperty(QTextFormat::FrameMargin)
3638 || format.hasProperty(QTextFormat::FrameLeftMargin)
3639 || format.hasProperty(QTextFormat::FrameRightMargin)
3640 || format.hasProperty(QTextFormat::FrameTopMargin)
3641 || format.hasProperty(QTextFormat::FrameBottomMargin))
3642 emitMargins(QString::number(format.topMargin()),
3643 QString::number(format.bottomMargin()),
3644 QString::number(format.leftMargin()),
3645 QString::number(format.rightMargin()));
3647 if (format.property(QTextFormat::TableBorderCollapse).toBool())
3648 html +=
" border-collapse:collapse;"_L1;
3650 if (html.size() == originalHtmlLength)
3651 html.chop(styleAttribute.size());
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666#ifndef QT_NO_TEXTHTMLPARSER
3667QString QTextDocument::toHtml()
const
3669 return QTextHtmlExporter(
this).toHtml();
3674
3675
3676
3677
3678
3679
3680#if QT_CONFIG(textmarkdownwriter)
3681QString QTextDocument::toMarkdown(QTextDocument::MarkdownFeatures features)
const
3684 QTextStream s(&ret);
3685 QTextMarkdownWriter w(s, features);
3686 if (w.writeAll(
this))
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752#if QT_CONFIG(textmarkdownreader)
3753void QTextDocument::setMarkdown(
const QString &markdown, QTextDocument::MarkdownFeatures features)
3755 QTextMarkdownImporter(
this, features).import(markdown);
3760
3761
3762QList<QTextFormat> QTextDocument::allFormats()
const
3764 Q_D(
const QTextDocument);
3765 return d->formatCollection()->formats;
3769
3770
3771
3772
3773
3777#include "moc_qtextdocument.cpp"
QString toHtml(ExportMode mode=ExportEntireDocument)
Returns the document in HTML format.
QTextHtmlExporter(const QTextDocument *_doc)
Combined button and popup list for selecting options.
Q_GUI_EXPORT bool mightBeRichText(QAnyStringView)
Returns true if the string text is likely to be rich text; otherwise returns false.
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n)
\inmodule QtCore \title Global Qt Declarations
#define qCDebug(category,...)
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)
static bool mightBeRichTextImpl(T text)
static bool mightBeRichTextImpl(QUtf8StringView text)
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)
#define QTextBeginningOfFrame