From 82cc779ee6eee63ff52629ea1463a442d99776fa Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Mon, 5 Feb 2024 22:53:22 -0700 Subject: [PATCH] tst_QTextMarkdownWriter: test both ways of setting font characteristics We have explicit QFont properties, and QTextFormat::setProperty(). Setting FontFixedPitch doesn't necessarily affect the view (QTextEdit or Qt Quick Text/TextEdit); and setting the font to the one we get from QFontDatabase::systemFont(QFontDatabase::FixedFont) is also unreliable, because the "monospace" fallback might actually be proportional. QTextMarkdownWriter checks for both to decide whether to use backticks; so markdown writing works if an editor UI makes the format monospace both ways to be safe. But in the opposite case that the main font is actually a monospace font, it's always been broken. The rest of the QTextCharFormat properties are generally working, to the extent that they are applicable to Markdown. But we lacked explicit test coverage: so far we were just reading Markdown or HTML and writing Markdown to test the writer. Also amend an old comment about writing underlines: writing was always possible, and since f5c7799f59ba53c634906b11e2135190093bf87b reading is supported too. So the underline support is symmetric (except that we don't heed the QTextDocument::MarkdownFeatures argument to the writer ctor: we probably should do that some day). Task-number: QTBUG-54623 Task-number: QTBUG-75648 Task-number: QTBUG-75649 Task-number: QTBUG-79900 Task-number: QTBUG-99676 Task-number: QTBUG-103484 Change-Id: Iacb4ed0ea59030570702d4eadfdadfad872065c6 Reviewed-by: Qt CI Bot Reviewed-by: Axel Spoerl (cherry picked from commit bf8167c5fc513861ba9ecadf491db256de65eafd) Reviewed-by: Qt Cherry-pick Bot --- src/gui/text/qtextmarkdownwriter.cpp | 6 +- .../tst_qtextmarkdownwriter.cpp | 122 ++++++++++++++++++ 2 files changed, 125 insertions(+), 3 deletions(-) diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp index d32ec4f6dc8..ad4859f3987 100644 --- a/src/gui/text/qtextmarkdownwriter.cpp +++ b/src/gui/text/qtextmarkdownwriter.cpp @@ -575,9 +575,9 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign endingMarkers = true; } if (fontInfo.underline() != underline) { - // Markdown doesn't support underline, but the parser will treat a single underline - // the same as a single asterisk, and the marked fragment will be rendered in italics. - // That will have to do. + // CommonMark specifies underline as another way to get emphasis (italics): + // https://spec.commonmark.org/0.31.2/#example-148 + // but md4c allows us to distinguish them; so we support underlining (in GitHub dialect). markers += u'_'; underline = fontInfo.underline(); if (!underline) diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp index 903baa4b93c..ea99c87840d 100644 --- a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp +++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp @@ -38,6 +38,8 @@ private slots: void testWriteTable(); void charFormatWrapping_data(); void charFormatWrapping(); + void charFormat_data(); + void charFormat(); void rewriteDocument_data(); void rewriteDocument(); void fromHtml_data(); @@ -50,6 +52,8 @@ private: private: QTextDocument *document; + QFont m_monoFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + QFont m_defaultFont; }; void tst_QTextMarkdownWriter::init() @@ -607,6 +611,124 @@ void tst_QTextMarkdownWriter::charFormatWrapping() // QTBUG-116927 } } +void tst_QTextMarkdownWriter::charFormat_data() +{ + QTest::addColumn("property"); + QTest::addColumn("propertyValue"); + QTest::addColumn("explicitFont"); + QTest::addColumn("expectedOutput"); + + const QTextFormat::Property NoProperty = QTextFormat::ObjectIndex; + + QTest::newRow("FontFixedPitch") + << QTextFormat::FontFixedPitch << QVariant(true) << m_defaultFont + << "before `formatted` after"; + if (!isFixedFontProportional()) { + // QTBUG-54623 QTBUG-75649 QTBUG-79900 QTBUG-103484 etc. + QTest::newRow("mono font") << NoProperty << QVariant() << m_monoFont + << "before `formatted` after"; + } + + { + QFont font; + font.setItalic(true); + QTest::newRow("italic font") + << NoProperty << QVariant() << font + << "before *formatted* after"; + } + QTest::newRow("FontItalic") + << QTextFormat::FontItalic << QVariant(true) << m_defaultFont + << "before *formatted* after"; + + { + QFont font; + font.setUnderline(true); + QTest::newRow("underline font") + << NoProperty << QVariant() << font + << "before _formatted_ after"; + } + QTest::newRow("FontUnderline") + << QTextFormat::FontUnderline << QVariant(true) << m_defaultFont + << "before _formatted_ after"; + + { + QFont font; + font.setStrikeOut(true); + QTest::newRow("strikeout font") + << NoProperty << QVariant() << font + << "before ~~formatted~~ after"; + } + QTest::newRow("FontStrikeOut") + << QTextFormat::FontStrikeOut << QVariant(true) << m_defaultFont + << "before ~~formatted~~ after"; + + { + QFont font; + font.setBold(true); + QTest::newRow("bold font") + << NoProperty << QVariant() << font + << "before **formatted** after"; + } + { + QFont font; + font.setWeight(QFont::Black); + QTest::newRow("black font") + << NoProperty << QVariant() << font + << "before **formatted** after"; + } + QTest::newRow("FontWeight") + << QTextFormat::FontWeight << QVariant(700) << m_defaultFont + << "before **formatted** after"; + + QTest::newRow("AnchorHref") + << QTextFormat::AnchorHref << QVariant("linky linky") << m_defaultFont + << "before [formatted](linky linky) after"; + + QTest::newRow("TextToolTip") // no effect without AnchorHref + << QTextFormat::TextToolTip << QVariant("such a tool") << m_defaultFont + << "before formatted after"; +} + +void tst_QTextMarkdownWriter::charFormat() +{ + if (isMainFontFixed()) + QSKIP("QTextMarkdownWriter would generate bogus backticks"); + + QFETCH(QTextFormat::Property, property); + QFETCH(QVariant, propertyValue); + QFETCH(QFont, explicitFont); + QFETCH(QString, expectedOutput); + + QTextCursor cursor(document); + cursor.insertText("before "); + + QTextCharFormat fmt; + if (explicitFont != m_defaultFont) + fmt.setFont(explicitFont); + if (property != QTextFormat::ObjectIndex) // != 0 + fmt.setProperty(property, propertyValue); + if (explicitFont == m_monoFont) { + QFontInfo fontInfo(fmt.font()); + qCDebug(lcTests) << "mono font" << explicitFont << "fontInfo fixedPitch" << fontInfo.fixedPitch() << "fmt fixedPitch" << fmt.fontFixedPitch(); + } + cursor.setCharFormat(fmt); + cursor.insertText("formatted"); + + cursor.setCharFormat({}); + cursor.insertText(" after"); + + const QString output = documentToUnixMarkdown(); +#ifdef DEBUG_WRITE_OUTPUT + { + QFile out(QDir::temp().filePath(QLatin1String(QTest::currentDataTag()) + ".md")); + out.open(QFile::WriteOnly); + out.write(output.toUtf8()); + out.close(); + } +#endif + QCOMPARE(output.trimmed(), expectedOutput); +} + void tst_QTextMarkdownWriter::rewriteDocument_data() { QTest::addColumn("inputFile");