8#if QT_CONFIG(textmarkdownreader)
9#include "qtextmarkdownimporter_p.h"
11#if QT_CONFIG(textmarkdownwriter)
12#include "qtextmarkdownwriter_p.h"
16#include <qbytearray.h>
17#include <qdatastream.h>
22using namespace Qt::StringLiterals;
24QTextCopyHelper::QTextCopyHelper(
const QTextCursor &_source,
const QTextCursor &_destination,
bool forceCharFormat,
const QTextCharFormat &fmt)
26 : formatCollection(*_destination.d->priv->formatCollection()), originalText((
const QString)_source.d->priv->buffer())
28 : formatCollection(*_destination.d->priv->formatCollection()), originalText(_source.d->priv->buffer())
31 src = _source.d->priv;
32 dst = _destination.d->priv;
33 insertPos = _destination.position();
34 this->forceCharFormat = forceCharFormat;
35 primaryCharFormatIndex = convertFormatIndex(fmt);
39int QTextCopyHelper::convertFormatIndex(
const QTextFormat &oldFormat,
int objectIndexToSet)
41 QTextFormat fmt = oldFormat;
42 if (objectIndexToSet != -1) {
43 fmt.setObjectIndex(objectIndexToSet);
44 }
else if (fmt.objectIndex() != -1) {
45 int newObjectIndex = objectIndexMap.value(fmt.objectIndex(), -1);
46 if (newObjectIndex == -1) {
47 QTextFormat objFormat = src->formatCollection()->objectFormat(fmt.objectIndex());
48 Q_ASSERT(objFormat.objectIndex() == -1);
49 newObjectIndex = formatCollection.createObjectIndex(objFormat);
50 objectIndexMap.insert(fmt.objectIndex(), newObjectIndex);
52 fmt.setObjectIndex(newObjectIndex);
54 int idx = formatCollection.indexForFormat(fmt);
55 Q_ASSERT(formatCollection.format(idx).type() == oldFormat.type());
59int QTextCopyHelper::appendFragment(
int pos,
int endPos,
int objectIndex)
61 QTextDocumentPrivate::FragmentIterator fragIt = src->find(pos);
64 Q_ASSERT(objectIndex == -1
65 || (frag->size_array[0] == 1 && src->formatCollection()->format(frag->format).objectIndex() != -1));
69 charFormatIndex = primaryCharFormatIndex;
71 charFormatIndex = convertFormatIndex(frag
->format, objectIndex);
73 const int inFragmentOffset = qMax(0, pos - fragIt.position());
74 int charsToCopy = qMin(
int(frag->size_array[0] - inFragmentOffset), endPos - pos);
76 QTextBlock nextBlock = src->blocksFind(pos + 1);
79 if (nextBlock.position() == pos + 1) {
80 blockIdx = convertFormatIndex(nextBlock.blockFormat());
81 }
else if (pos == 0 && insertPos == 0) {
82 dst->setBlockFormat(dst->blocksBegin(), dst->blocksBegin(), convertFormat(src->blocksBegin().blockFormat()).toBlockFormat());
83 dst->setCharFormat(-1, 1, convertFormat(src->blocksBegin().charFormat()).toCharFormat());
86 QString txtToInsert(originalText.constData() + frag->stringPosition + inFragmentOffset, charsToCopy);
87 if (txtToInsert.size() == 1
88 && (txtToInsert.at(0) == QChar::ParagraphSeparator
93 dst->insertBlock(txtToInsert.at(0), insertPos, blockIdx, charFormatIndex);
96 if (nextBlock.textList()) {
97 QTextBlock dstBlock = dst->blocksFind(insertPos);
98 if (!dstBlock.textList()) {
102 int listBlockFormatIndex = convertFormatIndex(nextBlock.blockFormat());
103 int listCharFormatIndex = convertFormatIndex(nextBlock.charFormat());
104 dst->insertBlock(insertPos, listBlockFormatIndex, listCharFormatIndex);
108 dst->insert(insertPos, txtToInsert, charFormatIndex);
109 const int userState = nextBlock.userState();
111 dst->blocksFind(insertPos).setUserState(userState);
112 insertPos += txtToInsert.size();
120 Q_ASSERT(pos < endPos);
123 pos += appendFragment(pos, endPos);
128 if (cursor.hasComplexSelection()) {
129 QTextTable *table = cursor.currentTable();
130 int row_start, col_start, num_rows, num_cols;
131 cursor.selectedTableCells(&row_start, &num_rows, &col_start, &num_cols);
133 QTextTableFormat tableFormat = table->format();
134 tableFormat.setColumns(num_cols);
135 tableFormat.clearColumnWidthConstraints();
136 const int objectIndex = dst->formatCollection()->createObjectIndex(tableFormat);
138 Q_ASSERT(row_start != -1);
139 for (
int r = row_start; r < row_start + num_rows; ++r) {
140 for (
int c = col_start; c < col_start + num_cols; ++c) {
141 QTextTableCell cell = table->cellAt(r, c);
142 const int rspan = cell.rowSpan();
143 const int cspan = cell.columnSpan();
150 int cc = cell.column();
156 QTextCharFormat cellFormat = cell.format();
157 if (r + rspan >= row_start + num_rows) {
158 cellFormat.setTableCellRowSpan(row_start + num_rows - r);
160 if (c + cspan >= col_start + num_cols) {
161 cellFormat.setTableCellColumnSpan(col_start + num_cols - c);
163 const int charFormatIndex = convertFormatIndex(cellFormat, objectIndex);
166 const int cellPos = cell.firstPosition();
167 QTextBlock block = src->blocksFind(cellPos);
168 if (block.position() == cellPos) {
169 blockIdx = convertFormatIndex(block.blockFormat());
176 if (cell.lastPosition() > cellPos) {
178 appendFragments(cellPos, cell.lastPosition());
184 int end = table->lastPosition();
185 appendFragment(end, end+1, objectIndex);
187 appendFragments(cursor.selectionStart(), cursor.selectionEnd());
194 doc->setUndoRedoEnabled(
false);
196 if (!_cursor.hasSelection())
199 QTextDocumentPrivate *p = QTextDocumentPrivate::get(doc);
201 QTextCursor destCursor(doc);
206 p->mergeCachedResources(_cursor.d->priv);
211 if (_cursor.isNull())
214 QTextDocumentPrivate *destPieceTable = _cursor.d->priv;
215 destPieceTable->beginEditBlock();
217 QTextCursor sourceCursor(doc);
218 sourceCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
219 QTextCopyHelper(sourceCursor, _cursor, importedFromPlainText, _cursor.charFormat()).copy();
221 destPieceTable->endEditBlock();
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
247
248
249
250
251QTextDocumentFragment::QTextDocumentFragment()
257
258
259
260
261QTextDocumentFragment::QTextDocumentFragment(
const QTextDocument *document)
267 QTextCursor cursor(
const_cast<QTextDocument *>(document));
268 cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
269 d =
new QTextDocumentFragmentPrivate(cursor);
273
274
275
276
277
278QTextDocumentFragment::QTextDocumentFragment(
const QTextCursor &cursor)
281 if (!cursor.hasSelection())
284 d =
new QTextDocumentFragmentPrivate(cursor);
288
289
290
291
292QTextDocumentFragment::QTextDocumentFragment(
const QTextDocumentFragment &rhs)
300
301
302
303
304QTextDocumentFragment &QTextDocumentFragment::operator=(
const QTextDocumentFragment &rhs)
308 if (d && !d->ref.deref())
315
316
317QTextDocumentFragment::~QTextDocumentFragment()
319 if (d && !d->ref.deref())
324
325
326bool QTextDocumentFragment::isEmpty()
const
328 return d ==
nullptr || d->doc ==
nullptr || QTextDocumentPrivate::get(d->doc)->length() <= 1;
332
333
334
335
336
337
338
339
340
341
342QString QTextDocumentFragment::toPlainText()
const
347 return d->doc->toPlainText();
351
352
353
354
355
356
357QString QTextDocumentFragment::toRawText()
const
362 return d->doc->toRawText();
365#ifndef QT_NO_TEXTHTMLPARSER
368
369
370
371
372
373
374QString QTextDocumentFragment::toHtml()
const
379 return QTextHtmlExporter(d->doc).toHtml(QTextHtmlExporter::ExportFragment);
384#if QT_CONFIG(textmarkdownwriter)
387
388
389
390
391
392
393
394QString QTextDocumentFragment::toMarkdown(QTextDocument::MarkdownFeatures features)
const
399 return d->doc->toMarkdown(features);
405
406
407
408
409
410QTextDocumentFragment QTextDocumentFragment::fromPlainText(
const QString &plainText)
412 QTextDocumentFragment res;
414 res.d =
new QTextDocumentFragmentPrivate;
415 res.d->importedFromPlainText =
true;
416 QTextCursor cursor(res.d->doc);
417 cursor.insertText(plainText);
421#ifndef QT_NO_TEXTHTMLPARSER
425 if (style == QTextListFormat::ListDisc)
426 return QTextListFormat::ListCircle;
427 else if (style == QTextListFormat::ListCircle)
428 return QTextListFormat::ListSquare;
433 : indent(0), headingLevel(0), compressNextWhitespace(PreserveWhiteSpace), doc(_doc), importMode(mode)
435 cursor = QTextCursor(doc);
436 wsm = QTextHtmlParserNode::WhiteSpaceNormal;
438 QString html = _html;
439 const int startFragmentPos = html.indexOf(
"<!--StartFragment-->"_L1);
440 if (startFragmentPos != -1) {
441 const auto qt3RichTextHeader =
"<meta name=\"qrichtext\" content=\"1\" />"_L1;
444 const bool hasQtRichtextMetaTag = html.contains(qt3RichTextHeader);
446 const int endFragmentPos = html.indexOf(
"<!--EndFragment-->"_L1);
447 if (startFragmentPos < endFragmentPos)
448 html = html.mid(startFragmentPos, endFragmentPos - startFragmentPos);
450 html = html.mid(startFragmentPos);
452 if (hasQtRichtextMetaTag)
453 html.prepend(qt3RichTextHeader);
456 parse(html, resourceProvider ? resourceProvider : doc);
462 cursor.beginEditBlock();
464 forceBlockMerging =
false;
465 compressNextWhitespace = RemoveWhiteSpace;
466 blockTagClosed =
false;
467 for (currentNodeIdx = 0; currentNodeIdx < count(); ++currentNodeIdx) {
468 currentNode = &at(currentNodeIdx);
469 wsm = textEditMode ? QTextHtmlParserNode::WhiteSpacePreWrap : currentNode->wsm;
472
473
474
475
476
477
478
479
480
481
482
485
486
487
488
489
490 if (currentNodeIdx > 0 && (currentNode->parent != currentNodeIdx - 1)) {
491 const bool lastBlockTagClosed = closeTag();
492 blockTagClosed = blockTagClosed || lastBlockTagClosed;
497 && !currentNode->isBlock()
498 && currentNode->id != Html_unknown)
501 }
else if (blockTagClosed && hasBlock) {
503 QTextBlockFormat blockFormat = currentNode->blockFormat;
504 blockFormat.setIndent(indent);
506 QTextBlockFormat oldFormat = cursor.blockFormat();
507 if (oldFormat.hasProperty(QTextFormat::PageBreakPolicy)) {
508 QTextFormat::PageBreakFlags pageBreak = oldFormat.pageBreakPolicy();
509 if (pageBreak == QTextFormat::PageBreak_AlwaysAfter)
511
512
513
514 pageBreak = QTextFormat::PageBreak_AlwaysBefore;
515 blockFormat.setPageBreakPolicy(pageBreak);
518 cursor.setBlockFormat(blockFormat);
522 if (currentNode->displayMode == QTextHtmlElement::DisplayNone) {
523 if (currentNode->id == Html_title)
524 doc->setMetaInformation(QTextDocument::DocumentTitle, currentNode->text);
529 if (processSpecialNodes() == ContinueWithNextNode)
535 && !currentNode->isBlock()
536 && !currentNode->text.isEmpty() && !currentNode->hasOnlyWhitespace()
537 && currentNode->displayMode == QTextHtmlElement::DisplayInline) {
539 QTextBlockFormat block = currentNode->blockFormat;
540 block.setIndent(indent);
542 appendBlock(block, currentNode->charFormat);
544 blockTagClosed =
false;
548 if (currentNode->isBlock()) {
550 if (result == ContinueWithNextNode) {
552 }
else if (result == ContinueWithNextSibling) {
553 currentNodeIdx += currentNode->children.size();
558 if (currentNode->charFormat.isAnchor()) {
559 const auto names = currentNode->charFormat.anchorNames();
560 if (!names.isEmpty())
561 namedAnchors.append(names.constFirst());
564 if (appendNodeText())
569 cursor.endEditBlock();
574 const int initialCursorPosition = cursor.position();
575 QTextCharFormat format = currentNode->charFormat;
577 if (wsm == QTextHtmlParserNode::WhiteSpacePre || wsm == QTextHtmlParserNode::WhiteSpacePreWrap)
578 compressNextWhitespace = PreserveWhiteSpace;
580 const QString text = currentNode->text;
582 QString textToInsert;
583 textToInsert.reserve(text.size());
585 for (QChar ch : text) {
588 && ch != QChar::ParagraphSeparator) {
590 if (wsm == QTextHtmlParserNode::WhiteSpacePreLine && (ch == u'\n' || ch == u'\r'))
591 compressNextWhitespace = PreserveWhiteSpace;
593 if (compressNextWhitespace == CollapseWhiteSpace)
594 compressNextWhitespace = RemoveWhiteSpace;
595 else if (compressNextWhitespace == RemoveWhiteSpace)
598 if (wsm == QTextHtmlParserNode::WhiteSpacePre
604 }
else if (ch == u'\r') {
607 }
else if (wsm != QTextHtmlParserNode::WhiteSpacePreWrap) {
608 compressNextWhitespace = RemoveWhiteSpace;
609 if (wsm == QTextHtmlParserNode::WhiteSpacePreLine && (ch == u'\n' || ch == u'\r'))
611 else if (wsm == QTextHtmlParserNode::WhiteSpaceNoWrap)
617 compressNextWhitespace = PreserveWhiteSpace;
621 || ch == QChar::ParagraphSeparator) {
623 if (!textToInsert.isEmpty()) {
624 if (wsm == QTextHtmlParserNode::WhiteSpacePreLine && textToInsert.at(textToInsert.size() - 1) == u' ')
625 textToInsert = textToInsert.chopped(1);
626 cursor.insertText(textToInsert, format);
627 textToInsert.clear();
630 QTextBlockFormat fmt = cursor.blockFormat();
632 if (fmt.hasProperty(QTextFormat::BlockBottomMargin)) {
633 QTextBlockFormat tmp = fmt;
634 tmp.clearProperty(QTextFormat::BlockBottomMargin);
635 cursor.setBlockFormat(tmp);
638 fmt.clearProperty(QTextFormat::BlockTopMargin);
639 appendBlock(fmt, cursor.charFormat());
641 if (!namedAnchors.isEmpty()) {
642 if (!textToInsert.isEmpty()) {
643 cursor.insertText(textToInsert, format);
644 textToInsert.clear();
647 format.setAnchor(
true);
648 format.setAnchorNames(namedAnchors);
649 cursor.insertText(ch, format);
650 namedAnchors.clear();
651 format.clearProperty(QTextFormat::IsAnchor);
652 format.clearProperty(QTextFormat::AnchorName);
659 if (!textToInsert.isEmpty()) {
660 cursor.insertText(textToInsert, format);
663 return cursor.position() != initialCursorPosition;
668 switch (currentNode->id) {
670 if (currentNode->charFormat.background().style() != Qt::NoBrush) {
671 QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
672 fmt.setBackground(currentNode->charFormat.background());
673 doc->rootFrame()->setFrameFormat(fmt);
674 const_cast<QTextHtmlParserNode *>(currentNode)->charFormat.clearProperty(QTextFormat::BackgroundBrush);
676 compressNextWhitespace = RemoveWhiteSpace;
681 QTextListFormat::Style style = currentNode->listStyle;
683 if (currentNode->id == Html_ul && !currentNode->hasOwnListStyle && currentNode->parent) {
684 const QTextHtmlParserNode *n = &at(currentNode->parent);
686 if (n->id == Html_ul) {
687 style = nextListStyle(currentNode->listStyle);
696 QTextListFormat listFmt;
697 listFmt.setStyle(style);
698 if (!currentNode->textListNumberPrefix.isNull())
699 listFmt.setNumberPrefix(currentNode->textListNumberPrefix);
700 if (!currentNode->textListNumberSuffix.isNull())
701 listFmt.setNumberSuffix(currentNode->textListNumberSuffix);
702 if (currentNode->listStart != 1)
703 listFmt.setStart(currentNode->listStart);
706 if (currentNode->hasCssListIndent)
707 listFmt.setIndent(currentNode->cssListIndent);
709 listFmt.setIndent(indent);
713 l.listNode = currentNodeIdx;
715 compressNextWhitespace = RemoveWhiteSpace;
718 const QString simpl = currentNode->text.simplified();
719 if (simpl.isEmpty() || simpl.at(0).isSpace())
720 return ContinueWithNextNode;
725 Table t = scanTable(currentNodeIdx);
728 compressNextWhitespace = RemoveWhiteSpace;
729 return ContinueWithNextNode;
733 return ContinueWithNextNode;
736 QTextImageFormat fmt;
737 fmt.setName(currentNode->imageName);
738 if (!currentNode->text.isEmpty())
739 fmt.setProperty(QTextFormat::ImageTitle, currentNode->text);
740 if (!currentNode->imageAlt.isEmpty())
741 fmt.setProperty(QTextFormat::ImageAltText, currentNode->imageAlt);
743 fmt.merge(currentNode->charFormat);
745 if (currentNode->imageWidth != -1)
746 fmt.setWidth(currentNode->imageWidth);
747 if (currentNode->imageHeight != -1)
748 fmt.setHeight(currentNode->imageHeight);
750 cursor.insertImage(fmt, QTextFrameFormat::Position(currentNode->cssFloat));
752 cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
753 cursor.mergeCharFormat(currentNode->charFormat);
754 cursor.movePosition(QTextCursor::NextCharacter);
755 compressNextWhitespace = CollapseWhiteSpace;
758 return ContinueWithNextNode;
762 QTextBlockFormat blockFormat = currentNode->blockFormat;
763 blockFormat.setTopMargin(topMargin(currentNodeIdx));
764 blockFormat.setBottomMargin(bottomMargin(currentNodeIdx));
765 blockFormat.setProperty(QTextFormat::BlockTrailingHorizontalRulerWidth, currentNode->width);
766 if (hasBlock && importMode == ImportToDocument)
767 cursor.mergeBlockFormat(blockFormat);
769 appendBlock(blockFormat);
771 compressNextWhitespace = RemoveWhiteSpace;
772 return ContinueWithNextNode;
797 return ContinueWithCurrentNode;
803 const QTextHtmlParserNode *closedNode = &at(currentNodeIdx - 1);
804 const int endDepth = depth(currentNodeIdx) - 1;
805 int depth =
this->depth(currentNodeIdx - 1);
806 bool blockTagClosed =
false;
808 while (depth > endDepth) {
810 if (!tables.isEmpty())
813 switch (closedNode->id) {
815 if (t && !t->isTextFrame) {
819 while (!t->currentCell.atEnd() && t->currentCell.row < t->currentRow)
823 blockTagClosed =
true;
829 indent = t->lastIndent;
831 tables.resize(tables.size() - 1);
834 if (tables.isEmpty()) {
835 cursor = doc->rootFrame()->lastCursorPosition();
839 cursor = t->frame->lastCursorPosition();
840 else if (!t->currentCell.atEnd())
841 cursor = t->currentCell.cell().lastCursorPosition();
847 blockTagClosed =
false;
848 compressNextWhitespace = RemoveWhiteSpace;
853 if (t && !t->isTextFrame)
855 blockTagClosed =
true;
856 compressNextWhitespace = RemoveWhiteSpace;
863 lists.resize(lists.size() - 1);
865 blockTagClosed =
true;
869 compressNextWhitespace = RemoveWhiteSpace;
873 if (cursor.position() > 0) {
874 const QChar curChar = cursor.document()->characterAt(cursor.position() - 1);
875 if (!closedNode->children.isEmpty() && curChar != QChar::LineSeparator) {
876 blockTagClosed =
true;
887 blockTagClosed =
true;
890 if (closedNode->isBlock())
891 blockTagClosed =
true;
895 closedNode = &at(closedNode->parent);
899 return blockTagClosed;
907 QList<QTextLength> columnWidths;
909 int tableHeaderRowCount = 0;
911 rowNodes.reserve(at(tableNodeIdx).children.size());
912 for (
int row : at(tableNodeIdx).children) {
913 switch (at(row).id) {
920 for (
int potentialRow : at(row).children) {
921 if (at(potentialRow).id == Html_tr) {
922 rowNodes += potentialRow;
923 if (at(row).id == Html_thead)
924 ++tableHeaderRowCount;
932 QList<RowColSpanInfo> rowColSpans;
933 QList<RowColSpanInfo> rowColSpanForColumn;
935 int effectiveRow = 0;
936 for (
int row : std::as_const(rowNodes)) {
939 for (
int cell : at(row).children) {
940 if (at(cell).isTableCell()) {
942 while (colsInRow < rowColSpanForColumn.size()) {
943 const RowColSpanInfo &spanInfo = rowColSpanForColumn.at(colsInRow);
945 if (spanInfo.row + spanInfo.rowSpan > effectiveRow) {
946 Q_ASSERT(spanInfo.col == colsInRow);
947 colsInRow += spanInfo.colSpan;
952 const QTextHtmlParserNode &c = at(cell);
953 const int currentColumn = colsInRow;
954 colsInRow += c.tableCellColSpan;
956 RowColSpanInfo spanInfo;
957 spanInfo.row = effectiveRow;
958 spanInfo.col = currentColumn;
959 spanInfo.colSpan = c.tableCellColSpan;
960 spanInfo.rowSpan = c.tableCellRowSpan;
961 if (spanInfo.colSpan > 1 || spanInfo.rowSpan > 1)
962 rowColSpans.append(spanInfo);
964 columnWidths.resize(qMax(columnWidths.size(), colsInRow));
965 rowColSpanForColumn.resize(columnWidths.size());
966 for (
int i = currentColumn; i < currentColumn + c.tableCellColSpan; ++i) {
967 if (columnWidths.at(i).type() == QTextLength::VariableLength) {
968 QTextLength w = c.width;
969 if (c.tableCellColSpan > 1 && w.type() != QTextLength::VariableLength)
970 w = QTextLength(w.type(), w.value(100.) / c.tableCellColSpan);
973 rowColSpanForColumn[i] = spanInfo;
978 table.columns = qMax(table.columns, colsInRow);
982 table.rows = effectiveRow;
984 table.lastIndent = indent;
987 if (table.rows == 0 || table.columns == 0)
990 QTextFrameFormat fmt;
991 const QTextHtmlParserNode &node = at(tableNodeIdx);
993 if (!node.isTextFrame) {
994 QTextTableFormat tableFmt;
995 tableFmt.setCellSpacing(node.tableCellSpacing);
996 tableFmt.setCellPadding(node.tableCellPadding);
997 if (node.blockFormat.hasProperty(QTextFormat::BlockAlignment))
998 tableFmt.setAlignment(node.blockFormat.alignment());
999 tableFmt.setColumns(table.columns);
1000 tableFmt.setColumnWidthConstraints(columnWidths);
1001 tableFmt.setHeaderRowCount(tableHeaderRowCount);
1002 tableFmt.setBorderCollapse(node.borderCollapse);
1006 fmt.setTopMargin(topMargin(tableNodeIdx));
1007 fmt.setBottomMargin(bottomMargin(tableNodeIdx));
1008 fmt.setLeftMargin(leftMargin(tableNodeIdx)
1009 + table.lastIndent * 40
1011 fmt.setRightMargin(rightMargin(tableNodeIdx));
1014 if (qFuzzyCompare(fmt.leftMargin(), fmt.rightMargin())
1015 && qFuzzyCompare(fmt.leftMargin(), fmt.topMargin())
1016 && qFuzzyCompare(fmt.leftMargin(), fmt.bottomMargin()))
1017 fmt.setProperty(QTextFormat::FrameMargin, fmt.leftMargin());
1019 fmt.setBorderStyle(node.borderStyle);
1020 fmt.setBorderBrush(node.borderBrush);
1021 fmt.setBorder(node.tableBorder);
1022 fmt.setWidth(node.width);
1023 fmt.setHeight(node.height);
1024 if (node.blockFormat.hasProperty(QTextFormat::PageBreakPolicy))
1025 fmt.setPageBreakPolicy(node.blockFormat.pageBreakPolicy());
1027 if (node.blockFormat.hasProperty(QTextFormat::LayoutDirection))
1028 fmt.setLayoutDirection(node.blockFormat.layoutDirection());
1029 if (node.charFormat.background().style() != Qt::NoBrush)
1030 fmt.setBackground(node.charFormat.background());
1031 fmt.setPosition(QTextFrameFormat::Position(node.cssFloat));
1033 if (node.isTextFrame) {
1034 if (node.isRootFrame) {
1035 table.frame = cursor.currentFrame();
1036 table.frame->setFrameFormat(fmt);
1038 table.frame = cursor.insertFrame(fmt);
1040 table.isTextFrame =
true;
1042 const int oldPos = cursor.position();
1043 QTextTable *textTable = cursor.insertTable(table.rows, table.columns, fmt.toTableFormat());
1044 table.frame = textTable;
1046 for (
int i = 0; i < rowColSpans.size(); ++i) {
1047 const RowColSpanInfo &nfo = rowColSpans.at(i);
1048 textTable->mergeCells(nfo.row, nfo.col, nfo.rowSpan, nfo.colSpan);
1051 table.currentCell = TableCellIterator(textTable);
1052 cursor.setPosition(oldPos);
1059 QTextBlockFormat block;
1060 QTextCharFormat charFmt;
1061 bool modifiedBlockFormat =
true;
1062 bool modifiedCharFormat =
true;
1064 if (currentNode->isTableCell() && !tables.isEmpty()) {
1065 Table &t = tables.last();
1066 if (!t.isTextFrame && !t.currentCell.atEnd()) {
1067 QTextTableCell cell = t.currentCell.cell();
1068 if (cell.isValid()) {
1069 QTextTableCellFormat fmt = cell.format().toTableCellFormat();
1070 if (topPadding(currentNodeIdx) >= 0)
1071 fmt.setTopPadding(topPadding(currentNodeIdx));
1072 if (bottomPadding(currentNodeIdx) >= 0)
1073 fmt.setBottomPadding(bottomPadding(currentNodeIdx));
1074 if (leftPadding(currentNodeIdx) >= 0)
1075 fmt.setLeftPadding(leftPadding(currentNodeIdx));
1076 if (rightPadding(currentNodeIdx) >= 0)
1077 fmt.setRightPadding(rightPadding(currentNodeIdx));
1078#ifndef QT_NO_CSSPARSER
1079 if (tableCellBorder(currentNodeIdx, QCss::TopEdge) > 0)
1080 fmt.setTopBorder(tableCellBorder(currentNodeIdx, QCss::TopEdge));
1081 if (tableCellBorder(currentNodeIdx, QCss::RightEdge) > 0)
1082 fmt.setRightBorder(tableCellBorder(currentNodeIdx, QCss::RightEdge));
1083 if (tableCellBorder(currentNodeIdx, QCss::BottomEdge) > 0)
1084 fmt.setBottomBorder(tableCellBorder(currentNodeIdx, QCss::BottomEdge));
1085 if (tableCellBorder(currentNodeIdx, QCss::LeftEdge) > 0)
1086 fmt.setLeftBorder(tableCellBorder(currentNodeIdx, QCss::LeftEdge));
1087 if (tableCellBorderStyle(currentNodeIdx, QCss::TopEdge) != QTextFrameFormat::BorderStyle_None)
1088 fmt.setTopBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::TopEdge));
1089 if (tableCellBorderStyle(currentNodeIdx, QCss::RightEdge) != QTextFrameFormat::BorderStyle_None)
1090 fmt.setRightBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::RightEdge));
1091 if (tableCellBorderStyle(currentNodeIdx, QCss::BottomEdge) != QTextFrameFormat::BorderStyle_None)
1092 fmt.setBottomBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::BottomEdge));
1093 if (tableCellBorderStyle(currentNodeIdx, QCss::LeftEdge) != QTextFrameFormat::BorderStyle_None)
1094 fmt.setLeftBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::LeftEdge));
1095 if (tableCellBorderBrush(currentNodeIdx, QCss::TopEdge) != Qt::NoBrush)
1096 fmt.setTopBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::TopEdge));
1097 if (tableCellBorderBrush(currentNodeIdx, QCss::RightEdge) != Qt::NoBrush)
1098 fmt.setRightBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::RightEdge));
1099 if (tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge) != Qt::NoBrush)
1100 fmt.setBottomBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge));
1101 if (tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge) != Qt::NoBrush)
1102 fmt.setLeftBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge));
1105 cell.setFormat(fmt);
1107 cursor.setPosition(cell.firstPosition());
1111 compressNextWhitespace = RemoveWhiteSpace;
1113 if (currentNode->charFormat.background().style() != Qt::NoBrush) {
1114 charFmt.setBackground(currentNode->charFormat.background());
1115 cursor.mergeBlockCharFormat(charFmt);
1120 block = cursor.blockFormat();
1121 charFmt = cursor.blockCharFormat();
1122 modifiedBlockFormat =
false;
1123 modifiedCharFormat =
false;
1128 qreal tm = qreal(topMargin(currentNodeIdx));
1129 if (tm > block.topMargin()) {
1130 block.setTopMargin(tm);
1131 modifiedBlockFormat =
true;
1135 int bottomMargin =
this->bottomMargin(currentNodeIdx);
1139 const QTextHtmlParserNode *parentNode = currentNode->parent ? &at(currentNode->parent) :
nullptr;
1140 if ((currentNode->id == Html_li || currentNode->id == Html_dt || currentNode->id == Html_dd)
1142 && (parentNode->isListStart() || parentNode->id == Html_dl)
1143 && (parentNode->children.last() == currentNodeIdx)) {
1144 bottomMargin = qMax(bottomMargin,
this->bottomMargin(currentNode->parent));
1147 if (block.bottomMargin() != bottomMargin) {
1148 block.setBottomMargin(bottomMargin);
1149 modifiedBlockFormat =
true;
1153 const qreal lm = leftMargin(currentNodeIdx);
1154 const qreal rm = rightMargin(currentNodeIdx);
1156 if (block.leftMargin() != lm) {
1157 block.setLeftMargin(lm);
1158 modifiedBlockFormat =
true;
1160 if (block.rightMargin() != rm) {
1161 block.setRightMargin(rm);
1162 modifiedBlockFormat =
true;
1166 if (currentNode->id != Html_li
1170 || !lists.constLast().list
1171 || lists.constLast().list->itemNumber(cursor.block()) == -1
1174 block.setIndent(indent);
1175 modifiedBlockFormat =
true;
1179 block.setHeadingLevel(headingLevel);
1180 modifiedBlockFormat =
true;
1183 if (currentNode->blockFormat.propertyCount() > 0) {
1184 modifiedBlockFormat =
true;
1185 block.merge(currentNode->blockFormat);
1188 if (currentNode->charFormat.propertyCount() > 0) {
1189 modifiedCharFormat =
true;
1190 charFmt.merge(currentNode->charFormat);
1196 if (wsm == QTextHtmlParserNode::WhiteSpacePre
1197 || wsm == QTextHtmlParserNode::WhiteSpaceNoWrap) {
1198 block.setNonBreakableLines(
true);
1199 modifiedBlockFormat =
true;
1202 if (currentNode->charFormat.background().style() != Qt::NoBrush && !currentNode->isTableCell()) {
1203 block.setBackground(currentNode->charFormat.background());
1204 modifiedBlockFormat =
true;
1207 if (hasBlock && (!currentNode->isEmptyParagraph || forceBlockMerging)) {
1208 if (modifiedBlockFormat)
1209 cursor.setBlockFormat(block);
1210 if (modifiedCharFormat)
1211 cursor.setBlockCharFormat(charFmt);
1213 if (currentNodeIdx == 1 && cursor.position() == 0 && currentNode->isEmptyParagraph) {
1214 cursor.setBlockFormat(block);
1215 cursor.setBlockCharFormat(charFmt);
1217 appendBlock(block, charFmt);
1221 if (currentNode->userState != -1)
1222 cursor.block().setUserState(currentNode->userState);
1224 if (currentNode->id == Html_li && !lists.isEmpty()) {
1225 List &l = lists.last();
1227 l.list->add(cursor.block());
1229 l.list = cursor.createList(l.format);
1230 const qreal listTopMargin = topMargin(l.listNode);
1231 if (listTopMargin > block.topMargin()) {
1232 block.setTopMargin(listTopMargin);
1233 cursor.mergeBlockFormat(block);
1237 QTextBlockFormat fmt;
1238 fmt.setIndent(currentNode->blockFormat.indent());
1239 cursor.mergeBlockFormat(fmt);
1243 forceBlockMerging =
false;
1244 if (currentNode->id == Html_body || currentNode->id == Html_html)
1245 forceBlockMerging =
true;
1247 if (currentNode->isEmptyParagraph) {
1249 return ContinueWithNextSibling;
1253 blockTagClosed =
false;
1254 return ContinueWithCurrentNode;
1257void QTextHtmlImporter::appendBlock(
const QTextBlockFormat &format, QTextCharFormat charFmt)
1259 if (!namedAnchors.isEmpty()) {
1260 charFmt.setAnchor(
true);
1261 charFmt.setAnchorNames(namedAnchors);
1262 namedAnchors.clear();
1265 cursor.insertBlock(format, charFmt);
1267 if (wsm != QTextHtmlParserNode::WhiteSpacePre && wsm != QTextHtmlParserNode::WhiteSpacePreWrap)
1268 compressNextWhitespace = RemoveWhiteSpace;
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1284QTextDocumentFragment QTextDocumentFragment::fromHtml(
const QString &html,
const QTextDocument *resourceProvider)
1286 QTextDocumentFragment res;
1287 res.d =
new QTextDocumentFragmentPrivate;
1289 QTextHtmlImporter importer(res.d->doc, html, QTextHtmlImporter::ImportToFragment, resourceProvider);
1296#if QT_CONFIG(textmarkdownreader)
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311QTextDocumentFragment QTextDocumentFragment::fromMarkdown(
const QString &markdown, QTextDocument::MarkdownFeatures features)
1313 QTextDocumentFragment res;
1314 res.d =
new QTextDocumentFragmentPrivate;
1316 QTextMarkdownImporter(res.d->doc, features).import(markdown);
void insert(QTextCursor &cursor) const
QTextDocumentFragmentPrivate(const QTextCursor &cursor=QTextCursor())
#define QTextBeginningOfFrame
static QTextListFormat::Style nextListStyle(QTextListFormat::Style style)