diff options
Diffstat (limited to 'tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp')
-rw-r--r-- | tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp | 873 |
1 files changed, 687 insertions, 186 deletions
diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp index 1a644d1bdd..600b45575f 100644 --- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp +++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> @@ -96,6 +71,7 @@ private slots: void toHtml2(); void setFragmentMarkersInHtmlExport(); + void setMediaRule(); void toHtmlBodyBgColor(); void toHtmlBodyBgColorRgba(); @@ -124,7 +100,10 @@ private slots: void clonePreservesIndentWidth(); void clonePreservesFormatsWhenEmpty(); void blockCount(); + void defaultStyleSheet(); + void defaultTableStyle_data(); + void defaultTableStyle(); void resolvedFontInEmptyFormat(); @@ -195,6 +174,18 @@ private slots: void resourceProvider(); + void contentsChangeIndices_data(); + void contentsChangeIndices(); + + void insertHtmlWithComments_data(); + void insertHtmlWithComments(); + + void delayedLayout(); + void undoContentChangeIndices(); + + void restoreStrokeFromHtml(); + void restoreForegroundGradientFromHtml(); + private: void backgroundImage_checkExpectedHtml(const QTextDocument &doc); void buildRegExpData(); @@ -286,6 +277,9 @@ void tst_QTextDocument::init() "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" + "hr { height: 1px; border-width: 0; }\n" + "li.unchecked::marker { content: \"\\2610\"; }\n" + "li.checked::marker { content: \"\\2612\"; }\n" "</style></head>" "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\">\n"); htmlHead = htmlHead.arg(defaultFont.family()) @@ -475,17 +469,17 @@ void tst_QTextDocument::basicIsModifiedChecks() QVERIFY(!doc->isModified()); cursor.insertText("Hello World"); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(spy.takeFirst().at(0).toBool()); doc->undo(); QVERIFY(!doc->isModified()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(!spy.takeFirst().at(0).toBool()); doc->redo(); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(spy.takeFirst().at(0).toBool()); } @@ -576,16 +570,16 @@ void tst_QTextDocument::noundo_basicIsModifiedChecks() QVERIFY(!doc->isModified()); cursor.insertText("Hello World"); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(spy.takeFirst().at(0).toBool()); doc->undo(); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); doc->redo(); QVERIFY(doc->isModified()); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QTextDocument::task240325() @@ -605,9 +599,6 @@ void tst_QTextDocument::task240325() QCOMPARE(doc->blockCount(), 1); for (QTextBlock block = doc->begin() ; block!=doc->end() ; block = block.next()) { QTextLayout *layout = block.layout(); -#ifdef Q_OS_ANDROID - QEXPECT_FAIL("", "QTBUG-69242", Abort); -#endif QCOMPARE(layout->lineCount(), 4); for (int lineIdx=0;lineIdx<layout->lineCount();++lineIdx) { @@ -756,6 +747,9 @@ void tst_QTextDocument::mightBeRichText_data() " PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">"; QVERIFY(Qt::mightBeRichText(QString::fromLatin1(qtDocuHeader))); + QVERIFY(Qt::mightBeRichText(QLatin1StringView(qtDocuHeader))); + QVERIFY(QUtf8StringView(qtDocuHeader).isValidUtf8()); + QVERIFY(Qt::mightBeRichText(QUtf8StringView(qtDocuHeader))); QTest::addColumn<QString>("input"); QTest::addColumn<bool>("result"); @@ -775,6 +769,10 @@ void tst_QTextDocument::mightBeRichText() QFETCH(QString, input); QFETCH(bool, result); QCOMPARE(result, Qt::mightBeRichText(input)); + QCOMPARE(result, Qt::mightBeRichText(QStringView(input))); + QCOMPARE(result, Qt::mightBeRichText(QUtf8StringView(input.toUtf8()))); + QVERIFY(QtPrivate::isLatin1(input)); + QCOMPARE(result, Qt::mightBeRichText(QLatin1StringView(input.toLatin1()))); } Q_DECLARE_METATYPE(QTextDocumentFragment) @@ -1174,7 +1172,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(2, 2); QTest::newRow("simpletable") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); @@ -1188,7 +1186,7 @@ void tst_QTextDocument::toHtml_data() table->mergeCells(0, 2, 1, 2); QTest::newRow("tablespans") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td colspan=\"2\"></td>\n<td colspan=\"2\"></td></tr>" "</table>"); } @@ -1207,7 +1205,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(2, 2, fmt); QTest::newRow("tableattrs") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" style=\" float: right;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" + << QString("<table border=\"1\" style=\" float: right; border-collapse:collapse;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); @@ -1229,7 +1227,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(2, 2, fmt); QTest::newRow("tableattrs2") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" style=\" float: right; margin-top:0px; margin-bottom:35px; margin-left:25px; margin-right:0px;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" + << QString("<table border=\"1\" style=\" float: right; margin-top:0px; margin-bottom:35px; margin-left:25px; margin-right:0px; border-collapse:collapse;\" align=\"center\" width=\"50%\" cellspacing=\"3\" cellpadding=\"3\" bgcolor=\"#ff00ff\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); @@ -1243,7 +1241,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(4, 2, fmt); QTest::newRow("tableheader") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "<thead>\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr></thead>" "\n<tr>\n<td></td>\n<td></td></tr>" @@ -1259,8 +1257,8 @@ void tst_QTextDocument::toHtml_data() subTable->cellAt(0, 0).firstCursorPosition().insertText("Hey"); QTest::newRow("nestedtable") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" - "\n<tr>\n<td></td>\n<td>\n<table border=\"1\" cellspacing=\"2\">\n<tr>\n<td>\n<p DEFAULTBLOCKSTYLE>Hey</p></td></tr></table></td></tr>" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" + "\n<tr>\n<td></td>\n<td>\n<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">\n<tr>\n<td>\n<p DEFAULTBLOCKSTYLE>Hey</p></td></tr></table></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); } @@ -1277,7 +1275,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(1, 3, fmt); QTest::newRow("colwidths") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td></td>\n<td width=\"30%\"></td>\n<td width=\"40\"></td></tr>" "</table>"); } @@ -1294,7 +1292,7 @@ void tst_QTextDocument::toHtml_data() cellCurs.mergeBlockCharFormat(fmt); QTest::newRow("cellproperties") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td bgcolor=\"#ffffff\"></td></tr>" "</table>"); } @@ -1386,7 +1384,7 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("lists") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + - QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li DEFAULTBLOCKSTYLE>Blubb</li>\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); } { @@ -1409,7 +1407,7 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("charfmt-for-list-item") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + - QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blubb</li>\n<li style=\" color:#0000ff;\" DEFAULTBLOCKSTYLE><span style=\" color:#ff0000;\">Blah</span></li></ul>"); + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li DEFAULTBLOCKSTYLE>Blubb</li>\n<li style=\" color:#0000ff;\" DEFAULTBLOCKSTYLE><span style=\" color:#ff0000;\">Blah</span></li></ul>"); } { @@ -1439,7 +1437,7 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("list-indent") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + - QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 4;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 4;\">\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); } { @@ -1498,7 +1496,19 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("horizontal-ruler-with-width") << QTextDocumentFragment::fromHtml("<hr width=\"50%\"/>") << QString("EMPTYBLOCK") + - QString("<hr width=\"50%\"/>"); + QString("<hr width=\"50%\" />"); + } + { + QTest::newRow("horizontal-ruler-with-color") << QTextDocumentFragment::fromHtml("<hr style=\"background-color:green;\"/>") + << + QString("EMPTYBLOCK") + + QString("<hr style=\"background-color:#008000;\"/>"); + } + { + QTest::newRow("horizontal-ruler-with-width-and-color") << QTextDocumentFragment::fromHtml("<hr width=\"50%\" style=\"background-color:green;\"/>") + << + QString("EMPTYBLOCK") + + QString("<hr width=\"50%\" style=\"background-color:#008000;\"/>"); } { CREATE_DOC_AND_CURSOR(); @@ -1549,7 +1559,7 @@ void tst_QTextDocument::toHtml_data() table->setFormat(fmt); QTest::newRow("mergedtablecolwidths") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td colspan=\"2\"></td></tr>" "\n<tr>\n<td width=\"20\"></td>\n<td width=\"40\"></td></tr>" "</table>"); @@ -1612,7 +1622,7 @@ void tst_QTextDocument::toHtml_data() table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); QTest::newRow("table-vertical-alignment") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td style=\" vertical-align:middle;\">\n" "<p DEFAULTBLOCKSTYLE>Blah</p></td>" "\n<td style=\" vertical-align:top;\"></td></tr>" @@ -1641,7 +1651,7 @@ void tst_QTextDocument::toHtml_data() table->cellAt(0, 0).firstCursorPosition().insertText("Blah"); QTest::newRow("table-cell-paddings") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td style=\" padding-left:1;\">\n" "<p DEFAULTBLOCKSTYLE>Blah</p></td>" "\n<td style=\" padding-right:1;\"></td></tr>" @@ -1659,7 +1669,7 @@ void tst_QTextDocument::toHtml_data() cursor.insertTable(2, 2, fmt); QTest::newRow("tableborder") << QTextDocumentFragment(&doc) - << QString("<table border=\"1\" style=\" border-color:#0000ff; border-style:solid;\" cellspacing=\"2\">" + << QString("<table border=\"1\" style=\" border-color:#0000ff; border-style:solid; border-collapse:collapse;\" cellpadding=\"4\">" "\n<tr>\n<td></td>\n<td></td></tr>" "\n<tr>\n<td></td>\n<td></td></tr>" "</table>"); @@ -1701,7 +1711,7 @@ void tst_QTextDocument::toHtml_data() << QString("EMPTYBLOCK") + QString("<p OPENDEFAULTBLOCKSTYLE page-break-before:always;\">Foo</p>" "\n<p OPENDEFAULTBLOCKSTYLE page-break-before:always; page-break-after:always;\">Bar</p>" - "\n<table border=\"1\" style=\" page-break-after:always;\" cellspacing=\"2\">\n<tr>\n<td></td></tr></table>"); + "\n<table border=\"1\" style=\" page-break-after:always; border-collapse:collapse;\" cellpadding=\"4\">\n<tr>\n<td></td></tr></table>"); } { @@ -1715,7 +1725,7 @@ void tst_QTextDocument::toHtml_data() QTest::newRow("list-ul-margin") << QTextDocumentFragment(&doc) << QString("EMPTYBLOCK") + - QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li DEFAULTBLOCKSTYLE>Blah</li></ul>"); + QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li DEFAULTBLOCKSTYLE>Blah</li></ul>"); } { CREATE_DOC_AND_CURSOR(); @@ -1725,12 +1735,12 @@ void tst_QTextDocument::toHtml_data() cursor.insertHtml(listHtml); QTest::newRow("nested-lists-one") << QTextDocumentFragment(&doc) - << QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; " + << QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; " "margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" - "item-1</li>\n<li DEFAULTBLOCKSTYLE>item-2\n<ul DEFAULTULSTYLE 2;\"><li " + "item-1</li>\n<li DEFAULTBLOCKSTYLE>item-2\n<ul DEFAULTULSTYLE 2;\">\n<li " "DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2\n<ul " - "DEFAULTULSTYLE 3;\"><li DEFAULTBLOCKSTYLE>item-2.2.1</li></ul></li>\n" - "<li DEFAULTBLOCKSTYLE>item-2.3\n<ul DEFAULTULSTYLE 3;\"><li DEFAULTBLOCKSTYLE>" + "DEFAULTULSTYLE 3;\">\n<li DEFAULTBLOCKSTYLE>item-2.2.1</li></ul></li>\n" + "<li DEFAULTBLOCKSTYLE>item-2.3\n<ul DEFAULTULSTYLE 3;\">\n<li DEFAULTBLOCKSTYLE>" "item-2.3.1</li></ul></li></ul></li>\n<li DEFAULTLASTLISTYLE>item-3</li></ul>"); } { @@ -1739,9 +1749,9 @@ void tst_QTextDocument::toHtml_data() cursor.insertHtml(listHtml); QTest::newRow("nested-lists-two") << QTextDocumentFragment(&doc) - << QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; " + << QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; " "margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" - "item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\"><li " + "item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\">\n<li " "DEFAULTBLOCKSTYLE>item-2.1</li></ul></li></ul>"); } { @@ -1751,9 +1761,9 @@ void tst_QTextDocument::toHtml_data() cursor.insertHtml(listHtml); QTest::newRow("nested-lists-three") << QTextDocumentFragment(&doc) - << QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; " + << QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; " "margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" - "item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\"><li " + "item-1</li>\n<li DEFAULTLASTLISTYLE>item-2\n<ul DEFAULTULSTYLE 2;\">\n<li " "DEFAULTBLOCKSTYLE>item-2.1</li>\n<li DEFAULTBLOCKSTYLE>item-2.2</li></ul>" "</li></ul>"); } @@ -1764,12 +1774,39 @@ void tst_QTextDocument::toHtml_data() cursor.insertHtml(listHtml); QTest::newRow("not-nested-list") << QTextDocumentFragment(&doc) - << QString("<ul DEFAULTULSTYLE 1;\"><li style=\" margin-top:12px; margin-bottom:0px; " + << QString("<ul DEFAULTULSTYLE 1;\">\n<li style=\" margin-top:12px; margin-bottom:0px; " "margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" - "item-1.1</li>\n<li DEFAULTBLOCKSTYLE>item-1.2</li></ul>\n<ul DEFAULTULSTYLE 1;\">" + "item-1.1</li>\n<li DEFAULTBLOCKSTYLE>item-1.2</li></ul>\n<ul DEFAULTULSTYLE 1;\">\n" "<li style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; " "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">item-2.1</li></ul>"); } + { + CREATE_DOC_AND_CURSOR(); + const QString listHtml = "<ul><li>bullet</li><li class=\"unchecked\">unchecked item</li><li class=\"checked\">checked item</li></ul>"; + cursor.insertHtml(listHtml); + + QTest::newRow("list with and without checkboxes") << QTextDocumentFragment(&doc) + << QString("<ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n" + "<li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">bullet</li>\n" + "<li class=\"unchecked\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">unchecked item</li>\n" + "<li class=\"checked\" style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">checked item</li></ul>"); + } + + { + CREATE_DOC_AND_CURSOR(); + + QTextListFormat fmt; + fmt.setStyle(QTextListFormat::ListDecimal); + fmt.setStart(4); + cursor.insertList(fmt); + cursor.insertText("Blah"); + cursor.insertBlock(); + cursor.insertText("Bleh"); + + QTest::newRow("ordered list with start") << QTextDocumentFragment(&doc) + << QString("EMPTYBLOCK") + + QString("<ol start=\"4\" style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\">\n<li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</li>\n<li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Bleh</li></ol>"); + } } void tst_QTextDocument::toHtml() @@ -1891,6 +1928,39 @@ void tst_QTextDocument::setFragmentMarkersInHtmlExport() } } +void tst_QTextDocument::setMediaRule() +{ + { + CREATE_DOC_AND_CURSOR(); + doc.setDefaultStyleSheet("@media screen { p { background:#000000 } } @media print { p { background:#ffffff } }"); + doc.setHtml("<p>Hello World</p>"); + + QString expected = htmlHead; + expected += QString("<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#000000;\"><span style=\" background-color:#000000;\">Hello World</span></p>") + htmlTail; + QCOMPARE(doc.toHtml(), expected); + } + { + CREATE_DOC_AND_CURSOR(); + doc.setDefaultStyleSheet("@media screen { p { background:#000000 } } @media print { p { background:#ffffff } }"); + doc.setMetaInformation(QTextDocument::CssMedia, "screen"); + doc.setHtml("<p>Hello World</p>"); + + QString expected = htmlHead; + expected += QString("<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#000000;\"><span style=\" background-color:#000000;\">Hello World</span></p>") + htmlTail; + QCOMPARE(doc.toHtml(), expected); + } + { + CREATE_DOC_AND_CURSOR(); + doc.setDefaultStyleSheet("@media screen { p { background:#000000 } } @media print { p { background:#ffffff } }"); + doc.setMetaInformation(QTextDocument::CssMedia, "print"); + doc.setHtml("<p>Hello World</p>"); + + QString expected = htmlHead; + expected += QString("<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;\"><span style=\" background-color:#ffffff;\">Hello World</span></p>") + htmlTail; + QCOMPARE(doc.toHtml(), expected); + } +} + void tst_QTextDocument::toHtmlBodyBgColor() { CREATE_DOC_AND_CURSOR(); @@ -1901,20 +1971,12 @@ void tst_QTextDocument::toHtmlBodyBgColor() fmt.setBackground(QColor("#0000ff")); doc.rootFrame()->setFrameFormat(fmt); - QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\"" - " bgcolor=\"#0000ff\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</body></html>"); + QString expectedHtml = htmlHead; + expectedHtml.insert(htmlHead.size() - 2, " bgcolor=\"#0000ff\""); + expectedHtml += "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + + htmlTail; - expectedHtml = expectedHtml.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + writeActualAndExpected(QTest::currentDataTag(), doc.toHtml(), expectedHtml); QCOMPARE(doc.toHtml(), expectedHtml); } @@ -1929,20 +1991,12 @@ void tst_QTextDocument::toHtmlBodyBgColorRgba() fmt.setBackground(QColor(255, 0, 0, 51)); doc.rootFrame()->setFrameFormat(fmt); - QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\"" - " bgcolor=\"rgba(255,0,0,0.2)\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</body></html>"); + QString expectedHtml = htmlHead; + expectedHtml.insert(htmlHead.size() - 2, " bgcolor=\"rgba(255,0,0,0.2)\""); + expectedHtml += "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + + htmlTail; - expectedHtml = expectedHtml.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + writeActualAndExpected(QTest::currentDataTag(), doc.toHtml(), expectedHtml); QCOMPARE(doc.toHtml(), expectedHtml); } @@ -1957,20 +2011,12 @@ void tst_QTextDocument::toHtmlBodyBgColorTransparent() fmt.setBackground(QColor(255, 0, 0, 0)); doc.rootFrame()->setFrameFormat(fmt); - QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\"" - " bgcolor=\"transparent\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</body></html>"); + QString expectedHtml = htmlHead; + expectedHtml.insert(htmlHead.size() - 2, " bgcolor=\"transparent\""); + expectedHtml += "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + + htmlTail; - expectedHtml = expectedHtml.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + writeActualAndExpected(QTest::currentDataTag(), doc.toHtml(), expectedHtml); QCOMPARE(doc.toHtml(), expectedHtml); } @@ -2031,21 +2077,13 @@ void tst_QTextDocument::toHtmlDefaultFontSpacingProperties() fnt.setWordSpacing(15); doc.setDefaultFont(fnt); - QString expectedOutput = QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" />" - "<meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; " - "font-weight:%3; font-style:%4; letter-spacing:13px; " - "word-spacing:15px;\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</body></html>"); - expectedOutput = expectedOutput.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + QString expectedOutput = htmlHead; + expectedOutput.insert(htmlHead.size() - 3, " letter-spacing:13px; word-spacing:15px;"); + expectedOutput += + "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" + + htmlTail; + + writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedOutput); QCOMPARE(doc.toHtml(), expectedOutput); } @@ -2059,23 +2097,13 @@ void tst_QTextDocument::toHtmlTextDecorationUnderline() fnt.setUnderline(true); doc.setDefaultFont(fnt); - QString expectedOutput = - QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" />" - "<meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; " - "font-weight:%3; font-style:%4; text-decoration: underline;\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; " - "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Some text</p>" - "</body></html>"); - - expectedOutput = expectedOutput.arg(doc.defaultFont().family()) - .arg(cssFontSizeString(doc.defaultFont())) - .arg(doc.defaultFont().weight()) - .arg((doc.defaultFont().italic() ? "italic" : "normal")); + QString expectedOutput = htmlHead; + expectedOutput.insert(htmlHead.size() - 3, " text-decoration: underline;"); + expectedOutput += + "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Some text</p>" + + htmlTail; + + writeActualAndExpected("toHtmlTextDecorationUnderline1", doc.toHtml(), expectedOutput); QCOMPARE(doc.toHtml(), expectedOutput); @@ -2084,26 +2112,17 @@ void tst_QTextDocument::toHtmlTextDecorationUnderline() cursor.select(QTextCursor::Document); cursor.mergeCharFormat(format); - QString expectedOutput2 = - QString("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" />" - "<meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; " - "font-weight:%3; font-style:%4; text-decoration: underline;\">\n" - "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; " - "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" - "<span style=\" text-decoration:none;\">Some text</span></p>" - "</body></html>"); + expectedOutput = htmlHead; + expectedOutput.insert(htmlHead.size() - 3, " text-decoration: underline;"); + expectedOutput += + "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; " + "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">" + "<span style=\" text-decoration:none;\">Some text</span></p>" + + htmlTail; - expectedOutput2 = expectedOutput2.arg(doc.defaultFont().family()) - .arg(cssFontSizeString(doc.defaultFont())) - .arg(doc.defaultFont().weight()) - .arg((doc.defaultFont().italic() ? "italic" : "normal")); + writeActualAndExpected("toHtmlTextDecorationUnderline2", doc.toHtml(), expectedOutput); - QCOMPARE(doc.toHtml(), expectedOutput2); + QCOMPARE(doc.toHtml(), expectedOutput); } void tst_QTextDocument::capitalizationHtmlInExport() @@ -2326,14 +2345,18 @@ void tst_QTextDocument::clonePreservesMetaInformation() { const QString title("Foobar"); const QString url("about:blank"); + const QString media("print"); doc->setHtml("<html><head><title>" + title + "</title></head><body>Hrm</body></html>"); doc->setMetaInformation(QTextDocument::DocumentUrl, url); + doc->setMetaInformation(QTextDocument::CssMedia, media); QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), title); QCOMPARE(doc->metaInformation(QTextDocument::DocumentUrl), url); + QCOMPARE(doc->metaInformation(QTextDocument::CssMedia), media); QTextDocument *clone = doc->clone(); QCOMPARE(clone->metaInformation(QTextDocument::DocumentTitle), title); QCOMPARE(clone->metaInformation(QTextDocument::DocumentUrl), url); + QCOMPARE(clone->metaInformation(QTextDocument::CssMedia), media); delete clone; } @@ -2648,6 +2671,127 @@ void tst_QTextDocument::defaultStyleSheet() QVERIFY(fmt.background().color() != QColor("green")); } +void tst_QTextDocument::defaultTableStyle_data() +{ + QTest::addColumn<QString>("css"); + QTest::addColumn<QString>("html"); + QTest::addColumn<QList<QBrush>>("borderBrushes"); + + const QString htmlHeader(R"( + <tr> + <th>1</th> <th>2</th> + </tr> + )"); + + const QString htmlCells(R"( + <tr> + <td>A</td> <td>B</td> + </tr> + )"); + + const QString cssEachSide = R"({ + border-top-color: red; + border-bottom-color: blue; + border-left-color: green; + border-right-color: yellow; + })"; + const QString cssOneColor = R"({ border-color: red; })"; + const QString cssFourColors = R"({ border-color: red blue green yellow; })"; + + QTest::addRow("td, each side") << QString("td ") + cssEachSide + << htmlCells + << QList<QBrush>{Qt::red, Qt::blue, QColor("green"), Qt::yellow}; + + QTest::addRow("th, each side") << QString("th ") + cssEachSide + << htmlHeader + << QList<QBrush>{Qt::red, Qt::blue, QColor("green"), Qt::yellow}; + + QTest::addRow("th+td, each side") << QString("th %1 td %1").arg(cssEachSide) + << htmlHeader + htmlCells + << QList<QBrush>{Qt::red, Qt::blue, QColor("green"), Qt::yellow}; + + QTest::addRow("td, one color") << QString("td ") + cssOneColor + << htmlCells + << QList<QBrush>{Qt::red, Qt::red, Qt::red, Qt::red}; + + QTest::addRow("th, one color") << QString("th ") + cssOneColor + << htmlHeader + << QList<QBrush>{Qt::red, Qt::red, Qt::red, Qt::red}; + + QTest::addRow("th+td, one color") << QString("th %1 td %1").arg(cssOneColor) + << htmlHeader + htmlCells + << QList<QBrush>{Qt::red, Qt::red, Qt::red, Qt::red}; + + // css order is top, right, bottom, left + QTest::addRow("td, four colors") << QString("td ") + cssFourColors + << htmlCells + << QList<QBrush>{Qt::red, QColor("green"), Qt::yellow, Qt::blue}; + +} + +void tst_QTextDocument::defaultTableStyle() +{ + QFETCH(QString, css); + QFETCH(QString, html); + QFETCH(QList<QBrush>, borderBrushes); + + CREATE_DOC_AND_CURSOR(); + doc.setDefaultStyleSheet(css); + doc.setHtml(QString("<html><body><table>%1</table></body></html>").arg(html)); + + const QTextFrame *frame = doc.rootFrame(); + const QTextTable *table = nullptr; + for (auto it = frame->begin(); !table && !it.atEnd(); ++it) + table = qobject_cast<const QTextTable*>(it.currentFrame()); + QVERIFY(table); + + const QList<QTextFormat::Property> brushProperties = { + QTextFormat::TableCellTopBorderBrush, + QTextFormat::TableCellBottomBorderBrush, + QTextFormat::TableCellLeftBorderBrush, + QTextFormat::TableCellRightBorderBrush + }; + + for (int row = 0; row < table->rows(); ++row) { + for (int column = 0; column < table->columns(); ++column) { + auto cellDetails = qScopeGuard([&]{ + qWarning("Failure was in cell %d/%d", row, column); + }); + const QTextTableCell cell = table->cellAt(row, column); + const QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QList<QBrush> brushes; + for (const auto side : brushProperties) { + QVariant sideProperty = cellFormat.property(side); + QVERIFY(sideProperty.isValid()); + QVERIFY(sideProperty.typeId() == qMetaTypeId<QBrush>()); + brushes << sideProperty.value<QBrush>(); + } + auto errorDetails = qScopeGuard([&]{ + if (brushes.size() != borderBrushes.size()) { + qWarning("Different count: %lld vs %lld", brushes.size(), borderBrushes.size()); + return; + } + for (int i = 0; i < brushes.size(); ++i) { + QString side; + QDebug(&side) << QTextFormat::Property(QTextFormat::TableCellTopBorderBrush + i); + QString actual; + QDebug(&actual) << brushes.at(i); + QString expected; + QDebug(&expected) << borderBrushes.at(i); + if (expected != actual) { + qWarning("\n %s:\n\tActual: %s\n\tExpected:%s", qPrintable(side), + qPrintable(actual), qPrintable(expected)); + } + } + }); + QVERIFY2(borderBrushes == brushes, // QCOMPARE doesn't generate helpful output anyway + qPrintable(QString("for cell %1/%2").arg(row).arg(column))); + errorDetails.dismiss(); + cellDetails.dismiss(); + } + } +} + void tst_QTextDocument::maximumBlockCount() { QCOMPARE(doc->maximumBlockCount(), 0); @@ -2751,13 +2895,13 @@ void tst_QTextDocument::blockCountChanged() doc->setPlainText("Foo"); QCOMPARE(doc->blockCount(), 1); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); doc->setPlainText("Foo\nBar"); QCOMPARE(doc->blockCount(), 2); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).value(0).toInt(), 2); spy.clear(); @@ -2765,16 +2909,16 @@ void tst_QTextDocument::blockCountChanged() cursor.movePosition(QTextCursor::End); cursor.insertText("Blahblah"); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); cursor.insertBlock(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).value(0).toInt(), 3); spy.clear(); doc->undo(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy.at(0).value(0).toInt(), 2); } @@ -2861,21 +3005,11 @@ const QString backgroundImage_html("<body><table><tr><td background=\"foo.png\"> void tst_QTextDocument::backgroundImage_checkExpectedHtml(const QTextDocument &doc) { - QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" " - "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" - "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n" - "p, li { white-space: pre-wrap; }\n" - "</style></head>" - "<body style=\" font-family:'%1'; font-size:%2; font-weight:%3; font-style:%4;\">\n" + QString expectedHtml = htmlHead + "<table border=\"0\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;\" cellspacing=\"2\" cellpadding=\"0\">" "\n<tr>\n<td background=\"foo.png\">" "\n<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>" - "</td></tr></table></body></html>"); - - expectedHtml = expectedHtml.arg(defaultFont.family()) - .arg(cssFontSizeString(defaultFont)) - .arg(defaultFont.weight()) - .arg((defaultFont.italic() ? "italic" : "normal")); + "</td></tr></table>" + htmlTail; writeActualAndExpected(QTest::currentTestFunction(), doc.toHtml(), expectedHtml); @@ -2963,12 +3097,12 @@ void tst_QTextDocument::characterAt() QString text("12345\n67890"); cursor.insertText(text); int length = doc.characterCount(); - QCOMPARE(length, text.length() + 1); + QCOMPARE(length, text.size() + 1); QCOMPARE(doc.characterAt(length-1), QChar(QChar::ParagraphSeparator)); QCOMPARE(doc.characterAt(-1), QChar()); QCOMPARE(doc.characterAt(length), QChar()); QCOMPARE(doc.characterAt(length + 1), QChar()); - for (int i = 0; i < text.length(); ++i) { + for (int i = 0; i < text.size(); ++i) { QChar c = text.at(i); if (c == QLatin1Char('\n')) c = QChar(QChar::ParagraphSeparator); @@ -3048,11 +3182,11 @@ void tst_QTextDocument::testUndoCommandAdded() QVERIFY(spy.isEmpty()); cursor.insertText("a"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); cursor.insertText("b"); // should be merged - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); cursor.insertText("c"); // should be merged - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(doc->toPlainText(), QString("abc")); doc->undo(); QCOMPARE(doc->toPlainText(), QString("")); @@ -3060,11 +3194,11 @@ void tst_QTextDocument::testUndoCommandAdded() doc->clear(); spy.clear(); cursor.insertText("aaa"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); cursor.insertText("aaaa\nbcd"); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); cursor.beginEditBlock(); @@ -3074,11 +3208,11 @@ void tst_QTextDocument::testUndoCommandAdded() cursor.insertText("\nccc"); QVERIFY(spy.isEmpty()); cursor.endEditBlock(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); cursor.insertBlock(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); cursor.setPosition(5); @@ -3090,18 +3224,18 @@ void tst_QTextDocument::testUndoCommandAdded() QTextCharFormat cf; cf.setFontItalic(true); cursor.mergeCharFormat(cf); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); spy.clear(); doc->undo(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); doc->undo(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); spy.clear(); doc->redo(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); doc->redo(); - QCOMPARE(spy.count(), 0); + QCOMPARE(spy.size(), 0); } void tst_QTextDocument::testUndoBlocks() @@ -3681,7 +3815,7 @@ void tst_QTextDocument::mergeFontFamilies() QTextCursor cursor = QTextCursor(&td); cursor.setPosition(0); - cursor.setPosition(QByteArray("Hello World").length(), QTextCursor::KeepAnchor); + cursor.setPosition(QByteArray("Hello World").size(), QTextCursor::KeepAnchor); cursor.mergeCharFormat(newFormat); QVERIFY(td.toHtml().contains(QLatin1String("font-family:'Jokerman';"))); @@ -3744,5 +3878,372 @@ void tst_QTextDocument::resourceProvider() QCOMPARE(providerCalled, 2); } +void tst_QTextDocument::contentsChangeIndices_data() +{ + QTest::addColumn<QString>("html"); + // adding list entries change the entire block, so change position is + // not the same as the cursor position if this value is >= 0 + QTest::addColumn<int>("expectedBegin"); + + QTest::addRow("text") << "Test" << -1; + QTest::addRow("unnumbered list") << "<ul><li>Test</li></ul>" << 0; + QTest::addRow("numbered list") << "<ol><li>Test</li></ol>" << 0; + QTest::addRow("table") << "<table><tr><td>Test</td></tr></table>" << -1; +} + +void tst_QTextDocument::contentsChangeIndices() +{ + QFETCH(QString, html); + QFETCH(int, expectedBegin); + + QTextDocument doc; + QTestDocumentLayout *layout = new QTestDocumentLayout(&doc); + doc.setDocumentLayout(layout); + doc.setHtml(QString("<html><body>%1</body></html>").arg(html)); + + int documentLength = 0; + int cursorLength = 0; + int changeBegin = 0; + int changeRemoved = 0; + int changeAdded = 0; + connect(&doc, &QTextDocument::contentsChange, this, [&](int pos, int removed, int added){ + documentLength = doc.characterCount(); + + QTextCursor cursor(&doc); + cursor.movePosition(QTextCursor::End); + // includes end-of-paragraph character + cursorLength = cursor.position() + 1; + + changeBegin = pos; + changeRemoved = removed; + changeAdded = added; + }); + + QTextCursor cursor(&doc); + cursor.movePosition(QTextCursor::End); + if (expectedBegin < 0) + expectedBegin = cursor.position(); + cursor.insertBlock(); + + const int changeEnd = changeBegin + changeAdded; + + QVERIFY(documentLength > 0); + QCOMPARE(documentLength, cursorLength); + QVERIFY(documentLength >= changeEnd); + QCOMPARE(changeBegin, expectedBegin); + QCOMPARE(changeAdded - changeRemoved, 1); +} + +void tst_QTextDocument::insertHtmlWithComments_data() +{ + QTest::addColumn<QString>("html"); + QTest::addColumn<QStringList>("expectedBlocks"); + + QTest::newRow("commentless") << "<p>first</p><p>second</p><p>third</p>" + << QStringList { "first", "second", "third" }; + QTest::newRow("normal") << "<p>first</p><!--<p>second</p>--><p>third</p>" + << QStringList { "first", "third" }; + QTest::newRow("nonClosing") << "<p>first</p><!--<p>second</p><p>third</p>" + << QStringList { "first" }; + QTest::newRow("immediatelyClosing") << "<p>first</p><!----><p>second</p><p>third</p>" + << QStringList { "first", "second", "third" }; + QTest::newRow("fake") << "<p>first</p><!-<p>second</p><p>third</p>" + << QStringList { "first", "second", "third" }; + QTest::newRow("endingNonExistant") << "<p>first</p>--><p>second</p><p>third</p>" + << QStringList { "first", "-->", "second", "third" }; +} + +void tst_QTextDocument::insertHtmlWithComments() +{ + QFETCH(QString, html); + QFETCH(QStringList, expectedBlocks); + + QTextDocument doc; + doc.setHtml(html); + + QCOMPARE(doc.blockCount(), expectedBlocks.size()); + + QStringList blockContent; + auto currentBlock = doc.begin(); + while (currentBlock != doc.end()) { + blockContent.append(currentBlock.text()); + currentBlock = currentBlock.next(); + } + + QCOMPARE(blockContent, expectedBlocks); +} + +void tst_QTextDocument::delayedLayout() +{ + QTextDocument doc; + doc.setHtml("<html>Foobar</html>"); + QCOMPARE(doc.blockCount(), 1); + + doc.setLayoutEnabled(false); + + // Force creation of a layout + QVERIFY(doc.documentLayout()); + + QTextBlock block = doc.begin(); + QTextLayout *layout = block.layout(); + QCOMPARE(layout->lineCount(), 0); // layout didn't happen yet + + doc.setLayoutEnabled(true); + QCOMPARE(layout->lineCount(), 1); // layout happened +} + +void tst_QTextDocument::undoContentChangeIndices() // QTBUG-113865 +{ + QTextDocument doc; + QTestDocumentLayout *layout = new QTestDocumentLayout(&doc); + QString content = QString("<html><body>" + "<ul><li>Undo</li></ul>" + "<ul><li>operation</li></ul>" + "<ul><li>of</li></ul>" + "<ul><li>unnumbered</li></ul>" + "<ul><li>lists</li></ul>" + "<ul><li>shows</li></ul>" + "<ul><li>invalid</li></ul>" + "<ul><li>content</li></ul>" + "<ul><li>indices</li></ul>" + "</body></html>"); + doc.setDocumentLayout(layout); + doc.setHtml(content); + + // Select the entire document content + QTextCursor cursor(&doc); + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); + + // Undo above operation + doc.undo(); + + // Move the cursor to the end + cursor.movePosition(QTextCursor::End); + cursor.insertHtml(content); + + // Select the whole document and remove the content + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); + + int documentLength = 0; + int changeRemoved = 0; + int changeAdded = 0; + int changePos = 0; + connect(&doc, &QTextDocument::contentsChange, this, [&](int pos, int removed, int added){ + documentLength = doc.characterCount(); + changeRemoved = removed; + changeAdded = added; + changePos = pos; + }); + + // Undo above operation + doc.undo(); + + const int changeEnd = changeAdded + changeRemoved; + + QVERIFY(documentLength > 0); + QCOMPARE(changePos, 0); + QVERIFY(changeRemoved >= 0); + QVERIFY(documentLength >= changeEnd); +} + +void tst_QTextDocument::restoreStrokeFromHtml() +{ + QTextDocument document; + QTextCursor textCursor(&document); + QTextCharFormat textOutline; + + // Set stroke color and width + { + QPen pen(Qt::red, 2.3, Qt::SolidLine); + textOutline.setTextOutline(pen); + textCursor.insertText("Outlined text", textOutline); + } + + // Set Cap and Join styles + { + QPen pen; + pen.setCapStyle(Qt::FlatCap); + pen.setJoinStyle(Qt::RoundJoin); + textOutline.setTextOutline(pen); + textCursor.insertBlock(); + textCursor.insertText("Cap and Join Style", textOutline); + } + + // Set Miter limit + { + QPen pen; + pen.setJoinStyle(Qt::MiterJoin); + pen.setMiterLimit(4); + textOutline.setTextOutline(pen); + textCursor.insertBlock(); + textCursor.insertText("Miter Limit", textOutline); + } + + // Set Dash Array and Dash Offset + { + QPen pen; + QList<qreal> pattern; + const int dash = 2; + const int gap = 4; + pattern << dash << gap << dash << gap << dash << gap; + pen.setDashPattern(pattern); + pen.setDashOffset(3); + textOutline.setTextOutline(pen); + textCursor.insertBlock(); + textCursor.insertText("Dash Pattern", textOutline); + } + + { + QTextDocument otherDocument; + otherDocument.setHtml(document.toHtml()); + QCOMPARE(otherDocument.blockCount(), document.blockCount()); + + QTextBlock block; + QTextFragment fragment; + QTextCharFormat fmt; + QPen pen; + + { + block = otherDocument.findBlockByNumber(0); + fragment = block.begin().fragment(); + QCOMPARE(fragment.text(), QStringLiteral("Outlined text")); + fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline)); + pen = fmt.textOutline(); + QCOMPARE(pen.color(), QColor(Qt::red)); + QCOMPARE(pen.widthF(), 2.3); + } + + { + block = otherDocument.findBlockByNumber(1); + qDebug() << block.text(); + fragment = block.begin().fragment(); + QCOMPARE(fragment.text(), QStringLiteral("Cap and Join Style")); + fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline)); + pen = fmt.textOutline(); + QCOMPARE(pen.capStyle(), Qt::FlatCap); + QCOMPARE(pen.joinStyle(), Qt::RoundJoin); + } + + { + block = otherDocument.findBlockByNumber(2); + fragment = block.begin().fragment(); + QCOMPARE(fragment.text(), QStringLiteral("Miter Limit")); + fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline)); + pen = fmt.textOutline(); + QCOMPARE(pen.joinStyle(), Qt::MiterJoin); + QCOMPARE(pen.miterLimit(), 4); + } + + + { + block = otherDocument.findBlockByNumber(3); + fragment = block.begin().fragment(); + QCOMPARE(fragment.text(), QStringLiteral("Dash Pattern")); + fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::TextOutline)); + pen = fmt.textOutline(); + QCOMPARE(pen.dashOffset(), 3); + QList<qreal> pattern; + const int dash = 2; + const int gap = 4; + pattern << dash << gap << dash << gap << dash << gap; + QCOMPARE(pen.dashPattern(), pattern); + } + } +} + +void tst_QTextDocument::restoreForegroundGradientFromHtml() +{ + QTextDocument document; + + QTextCursor textCursor(&document); + + QTextCharFormat foregroundGradient; + QLinearGradient lg; + lg.setColorAt(0.0, Qt::green); + lg.setColorAt(1.0, Qt::blue); + lg.setStart(QPointF(0,0)); + lg.setFinalStop(QPointF(800, 1000)); + foregroundGradient.setForeground(QBrush(lg)); + textCursor.insertText("Linear gradient text\n", foregroundGradient); + + QRadialGradient rg; + rg.setCoordinateMode(QGradient::ObjectBoundingMode); + rg.setSpread(QGradient::ReflectSpread); + rg.setColorAt(0.0, Qt::green); + rg.setColorAt(1.0, Qt::blue); + QPointF center(0.5, 0.5); + rg.setCenter(center); + rg.setFocalPoint(center); + rg.setRadius(0.5); + foregroundGradient.setForeground(QBrush(rg)); + textCursor.insertText("Radial gradient text\n", foregroundGradient); + + QConicalGradient cg; + cg.setCoordinateMode(QGradient::ObjectMode); + cg.setSpread(QGradient::RepeatSpread); + cg.setColorAt(0.0, Qt::green); + cg.setColorAt(1.0, Qt::blue); + cg.setCenter(QPointF(0.5, 0.5)); + cg.setAngle(0.0); + foregroundGradient.setForeground(QBrush(cg)); + textCursor.insertText("Conical gradient text\n", foregroundGradient); + + { + QTextDocument otherDocument; + otherDocument.setHtml(document.toHtml()); + + QCOMPARE(otherDocument.blockCount(), document.blockCount()); + + QTextBlock block = otherDocument.firstBlock(); + QTextFragment fragment = block.begin().fragment(); + + QCOMPARE(fragment.text(), QStringLiteral("Linear gradient text")); + + QTextCharFormat fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::ForegroundBrush)); + + QBrush brush = fmt.foreground(); + QCOMPARE(brush.style(), Qt::LinearGradientPattern); + QCOMPARE(brush.gradient()->coordinateMode(), lg.coordinateMode()); + QCOMPARE(brush.gradient()->spread(), lg.spread()); + QCOMPARE(brush.gradient()->stops().size(), lg.stops().size()); + QCOMPARE(static_cast<const QLinearGradient *>(brush.gradient())->start(), lg.start()); + QCOMPARE(static_cast<const QLinearGradient *>(brush.gradient())->finalStop(), lg.finalStop()); + + block = block.next(); + fragment = block.begin().fragment(); + + fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::ForegroundBrush)); + + brush = fmt.foreground(); + QCOMPARE(brush.style(), Qt::RadialGradientPattern); + QCOMPARE(brush.gradient()->coordinateMode(), rg.coordinateMode()); + QCOMPARE(brush.gradient()->spread(), rg.spread()); + QCOMPARE(static_cast<const QRadialGradient *>(brush.gradient())->center(), rg.center()); + QCOMPARE(static_cast<const QRadialGradient *>(brush.gradient())->focalPoint(), rg.focalPoint()); + QCOMPARE(static_cast<const QRadialGradient *>(brush.gradient())->radius(), rg.radius()); + + block = block.next(); + fragment = block.begin().fragment(); + + fmt = fragment.charFormat(); + QVERIFY(fmt.hasProperty(QTextCharFormat::ForegroundBrush)); + + brush = fmt.foreground(); + QCOMPARE(brush.style(), Qt::ConicalGradientPattern); + QCOMPARE(brush.gradient()->coordinateMode(), cg.coordinateMode()); + QCOMPARE(brush.gradient()->spread(), cg.spread()); + QCOMPARE(static_cast<const QConicalGradient *>(brush.gradient())->center(), cg.center()); + QCOMPARE(static_cast<const QConicalGradient *>(brush.gradient())->angle(), cg.angle()); + } +} + QTEST_MAIN(tst_QTextDocument) #include "tst_qtextdocument.moc" |