summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/image/qimage_p.h2
-rw-r--r--src/gui/itemmodels/qstandarditemmodel.h7
-rw-r--r--src/gui/kernel/qinputdevicemanager.cpp4
-rw-r--r--src/gui/kernel/qinputdevicemanager_p.h4
-rw-r--r--src/gui/kernel/qinputdevicemanager_p_p.h5
-rw-r--r--src/gui/painting/qbrush.cpp16
-rw-r--r--src/gui/text/qdistancefield.cpp3
-rw-r--r--src/gui/text/qdistancefield_p.h1
-rw-r--r--src/gui/text/qtextdocument.cpp6
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp4
-rw-r--r--src/gui/text/qtextformat.cpp11
-rw-r--r--src/gui/text/qtextformat.h3
-rw-r--r--src/gui/text/qtexthtmlparser.cpp8
-rw-r--r--src/gui/text/qtexthtmlparser_p.h1
-rw-r--r--src/gui/text/qtextmarkdownimporter.cpp32
-rw-r--r--src/gui/text/qtextmarkdownimporter_p.h2
-rw-r--r--src/gui/text/qtextmarkdownwriter.cpp78
-rw-r--r--src/gui/text/qtextmarkdownwriter_p.h5
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.cpp5
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.h1
-rw-r--r--src/gui/vulkan/qvulkaninstance.cpp46
-rw-r--r--src/gui/vulkan/qvulkaninstance.h5
22 files changed, 210 insertions, 39 deletions
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index 9da6acd0a7..1cd0e8e0aa 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -140,7 +140,7 @@ QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetyp
qsizetype dummy;
if (mul_overflow(height, qsizetype(sizeof(uchar *)), &dummy))
return invalid; // why is this here?
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
+#if 1 || QT_VERSION < QT_VERSION_CHECK(6,0,0) // ### can only fix this if QImage dimensions are not int anymore
// Disallow images where width * depth calculations might overflow
if (width > (INT_MAX - 31) / depth)
return invalid;
diff --git a/src/gui/itemmodels/qstandarditemmodel.h b/src/gui/itemmodels/qstandarditemmodel.h
index a9ee25da75..435b66591c 100644
--- a/src/gui/itemmodels/qstandarditemmodel.h
+++ b/src/gui/itemmodels/qstandarditemmodel.h
@@ -344,8 +344,11 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
- // Qt 6: add override keyword
- bool clearItemData(const QModelIndex &index);
+ bool clearItemData(const QModelIndex &index)
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ override
+#endif
+ ;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
diff --git a/src/gui/kernel/qinputdevicemanager.cpp b/src/gui/kernel/qinputdevicemanager.cpp
index 6e4e5a9c93..11442407e1 100644
--- a/src/gui/kernel/qinputdevicemanager.cpp
+++ b/src/gui/kernel/qinputdevicemanager.cpp
@@ -75,13 +75,13 @@ int QInputDeviceManager::deviceCount(DeviceType type) const
int QInputDeviceManagerPrivate::deviceCount(QInputDeviceManager::DeviceType type) const
{
- return m_deviceCount.value(type);
+ return m_deviceCount[type];
}
void QInputDeviceManagerPrivate::setDeviceCount(QInputDeviceManager::DeviceType type, int count)
{
Q_Q(QInputDeviceManager);
- if (m_deviceCount.value(type) != count) {
+ if (m_deviceCount[type] != count) {
m_deviceCount[type] = count;
emit q->deviceListChanged(type);
}
diff --git a/src/gui/kernel/qinputdevicemanager_p.h b/src/gui/kernel/qinputdevicemanager_p.h
index 74494d712b..1d20b102e3 100644
--- a/src/gui/kernel/qinputdevicemanager_p.h
+++ b/src/gui/kernel/qinputdevicemanager_p.h
@@ -69,7 +69,9 @@ public:
DeviceTypePointer,
DeviceTypeKeyboard,
DeviceTypeTouch,
- DeviceTypeTablet
+ DeviceTypeTablet,
+
+ NumDeviceTypes
};
QInputDeviceManager(QObject *parent = nullptr);
diff --git a/src/gui/kernel/qinputdevicemanager_p_p.h b/src/gui/kernel/qinputdevicemanager_p_p.h
index 0a91252fbc..871f9315c3 100644
--- a/src/gui/kernel/qinputdevicemanager_p_p.h
+++ b/src/gui/kernel/qinputdevicemanager_p_p.h
@@ -52,10 +52,11 @@
//
#include <QtGui/private/qtguiglobal_p.h>
-#include <QtCore/qmap.h>
#include <private/qobject_p.h>
#include "qinputdevicemanager_p.h"
+#include <array>
+
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QInputDeviceManagerPrivate : public QObjectPrivate
@@ -68,7 +69,7 @@ public:
int deviceCount(QInputDeviceManager::DeviceType type) const;
void setDeviceCount(QInputDeviceManager::DeviceType type, int count);
- QMap<QInputDeviceManager::DeviceType, int> m_deviceCount;
+ std::array<int, QInputDeviceManager::NumDeviceTypes> m_deviceCount;
Qt::KeyboardModifiers keyboardModifiers;
};
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index 13d986073e..21e41979af 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -1385,16 +1385,16 @@ QGradient::QGradient(Preset preset)
setCoordinateMode(ObjectMode);
setSpread(PadSpread);
- const QJsonValue start = presetData[QLatin1Literal("start")];
- const QJsonValue end = presetData[QLatin1Literal("end")];
- m_data.linear.x1 = start[QLatin1Literal("x")].toDouble();
- m_data.linear.y1 = start[QLatin1Literal("y")].toDouble();
- m_data.linear.x2 = end[QLatin1Literal("x")].toDouble();
- m_data.linear.y2 = end[QLatin1Literal("y")].toDouble();
+ const QJsonValue start = presetData[QLatin1String("start")];
+ const QJsonValue end = presetData[QLatin1String("end")];
+ m_data.linear.x1 = start[QLatin1String("x")].toDouble();
+ m_data.linear.y1 = start[QLatin1String("y")].toDouble();
+ m_data.linear.x2 = end[QLatin1String("x")].toDouble();
+ m_data.linear.y2 = end[QLatin1String("y")].toDouble();
for (const QJsonValue &stop : presetData[QLatin1String("stops")].toArray()) {
- setColorAt(stop[QLatin1Literal("position")].toDouble(),
- QColor(QRgb(stop[QLatin1Literal("color")].toInt())));
+ setColorAt(stop[QLatin1String("position")].toDouble(),
+ QColor(QRgb(stop[QLatin1String("color")].toInt())));
}
cachedPresets.insert(preset, *this);
diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp
index 82bb617733..5967c8d3de 100644
--- a/src/gui/text/qdistancefield.cpp
+++ b/src/gui/text/qdistancefield.cpp
@@ -904,6 +904,9 @@ QDistanceField::QDistanceField(const QDistanceField &other)
d = other.d;
}
+QDistanceField &QDistanceField::operator=(const QDistanceField &)
+ = default;
+
QDistanceField::QDistanceField(const QRawFont &font, glyph_t glyph, bool doubleResolution)
{
setGlyph(font, glyph, doubleResolution);
diff --git a/src/gui/text/qdistancefield_p.h b/src/gui/text/qdistancefield_p.h
index 1a1b6866a2..dc5d5a9a02 100644
--- a/src/gui/text/qdistancefield_p.h
+++ b/src/gui/text/qdistancefield_p.h
@@ -95,6 +95,7 @@ public:
QDistanceField(QFontEngine *fontEngine, glyph_t glyph, bool doubleResolution = false);
QDistanceField(const QPainterPath &path, glyph_t glyph, bool doubleResolution = false);
QDistanceField(const QDistanceField &other);
+ QDistanceField &operator=(const QDistanceField &other);
bool isNull() const;
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index c800cea3f6..899801ca39 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -2709,6 +2709,12 @@ void QTextHtmlExporter::emitFragment(const QTextFragment &fragment)
if (imgFmt.hasProperty(QTextFormat::ImageName))
emitAttribute("src", imgFmt.name());
+ if (imgFmt.hasProperty(QTextFormat::ImageAltText))
+ emitAttribute("alt", imgFmt.stringProperty(QTextFormat::ImageAltText));
+
+ if (imgFmt.hasProperty(QTextFormat::ImageTitle))
+ emitAttribute("title", imgFmt.stringProperty(QTextFormat::ImageTitle));
+
if (imgFmt.hasProperty(QTextFormat::ImageWidth))
emitAttribute("width", QString::number(imgFmt.width()));
diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp
index aef4ea1522..1905d9a1b1 100644
--- a/src/gui/text/qtextdocumentfragment.cpp
+++ b/src/gui/text/qtextdocumentfragment.cpp
@@ -715,6 +715,10 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processSpecialNodes()
case Html_img: {
QTextImageFormat fmt;
fmt.setName(currentNode->imageName);
+ if (!currentNode->text.isEmpty())
+ fmt.setProperty(QTextFormat::ImageTitle, currentNode->text);
+ if (!currentNode->imageAlt.isEmpty())
+ fmt.setProperty(QTextFormat::ImageAltText, currentNode->imageAlt);
fmt.merge(currentNode->charFormat);
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 895b9034e0..090c6cc4ce 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -564,6 +564,9 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
\value BlockTrailingHorizontalRulerWidth The width of a horizontal ruler element.
\value HeadingLevel The level of a heading, for example 1 corresponds to an HTML H1 tag; otherwise 0.
This enum value has been added in Qt 5.12.
+ \value BlockCodeFence The character that was used in the "fences" around a Markdown code block.
+ If the code block was indented rather than fenced, the block should not have this property.
+ This enum value has been added in Qt 5.14.
\value BlockQuoteLevel The depth of nested quoting on this block: 1 means the block is a top-level block quote.
Blocks that are not block quotes should not have this property.
@@ -659,7 +662,13 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
Image properties
- \value ImageName
+ \value ImageName The filename or source of the image.
+ \value ImageTitle The title attribute of an HTML image tag, or
+ the quoted string that comes after the URL in a Markdown image link.
+ This enum value has been added in Qt 5.14.
+ \value ImageAltText The alt attribute of an HTML image tag, or
+ the image description in a Markdown image link.
+ This enum value has been added in Qt 5.14.
\value ImageWidth
\value ImageHeight
\value ImageQuality
diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h
index a631309ae0..a91461dcae 100644
--- a/src/gui/text/qtextformat.h
+++ b/src/gui/text/qtextformat.h
@@ -178,6 +178,7 @@ public:
HeadingLevel = 0x1070,
BlockQuoteLevel = 0x1080,
BlockCodeLanguage = 0x1090,
+ BlockCodeFence = 0x1091,
BlockMarker = 0x10A0,
// character properties
@@ -253,6 +254,8 @@ public:
// image properties
ImageName = 0x5000,
+ ImageTitle = 0x5001,
+ ImageAltText = 0x5002,
ImageWidth = 0x5010,
ImageHeight = 0x5011,
ImageQuality = 0x5014,
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index 37051502fa..642f0893b4 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -1556,6 +1556,10 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
} else if (key == QLatin1String("height")) {
node->imageHeight = -2; // register that there is a value for it.
setFloatAttribute(&node->imageHeight, value);
+ } else if (key == QLatin1String("alt")) {
+ node->imageAlt = value;
+ } else if (key == QLatin1String("title")) {
+ node->text = value;
}
break;
case Html_tr:
@@ -1631,6 +1635,10 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
else if (key == QLatin1String("type"))
linkType = value;
break;
+ case Html_pre:
+ if (key == QLatin1String("class") && value.startsWith(QLatin1String("language-")))
+ node->blockFormat.setProperty(QTextFormat::BlockCodeLanguage, value.mid(9));
+ break;
default:
break;
}
diff --git a/src/gui/text/qtexthtmlparser_p.h b/src/gui/text/qtexthtmlparser_p.h
index 73dac38b82..6ce294d211 100644
--- a/src/gui/text/qtexthtmlparser_p.h
+++ b/src/gui/text/qtexthtmlparser_p.h
@@ -184,6 +184,7 @@ struct QTextHtmlParserNode {
QString textListNumberPrefix;
QString textListNumberSuffix;
QString imageName;
+ QString imageAlt;
qreal imageWidth;
qreal imageHeight;
QTextLength width;
diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp
index b96acba0e6..8a9bb3953c 100644
--- a/src/gui/text/qtextmarkdownimporter.cpp
+++ b/src/gui/text/qtextmarkdownimporter.cpp
@@ -165,12 +165,13 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det)
MD_BLOCK_CODE_DETAIL *detail = static_cast<MD_BLOCK_CODE_DETAIL *>(det);
m_codeBlock = true;
m_blockCodeLanguage = QLatin1String(detail->lang.text, int(detail->lang.size));
+ m_blockCodeFence = detail->fence_char;
QString info = QLatin1String(detail->info.text, int(detail->info.size));
m_needsInsertBlock = true;
if (m_blockQuoteDepth)
- qCDebug(lcMD, "CODE lang '%s' info '%s' inside QUOTE %d", qPrintable(m_blockCodeLanguage), qPrintable(info), m_blockQuoteDepth);
+ qCDebug(lcMD, "CODE lang '%s' info '%s' fenced with '%c' inside QUOTE %d", qPrintable(m_blockCodeLanguage), qPrintable(info), m_blockCodeFence, m_blockQuoteDepth);
else
- qCDebug(lcMD, "CODE lang '%s' info '%s'", qPrintable(m_blockCodeLanguage), qPrintable(info));
+ qCDebug(lcMD, "CODE lang '%s' info '%s' fenced with '%c'", qPrintable(m_blockCodeLanguage), qPrintable(info), m_blockCodeFence);
} break;
case MD_BLOCK_H: {
MD_BLOCK_H_DETAIL *detail = static_cast<MD_BLOCK_H_DETAIL *>(det);
@@ -326,6 +327,7 @@ int QTextMarkdownImporter::cbLeaveBlock(int blockType, void *detail)
case MD_BLOCK_CODE: {
m_codeBlock = false;
m_blockCodeLanguage.clear();
+ m_blockCodeFence = 0;
if (m_blockQuoteDepth)
qCDebug(lcMD, "CODE ended inside QUOTE %d", m_blockQuoteDepth);
else
@@ -362,15 +364,10 @@ int QTextMarkdownImporter::cbEnterSpan(int spanType, void *det)
} break;
case MD_SPAN_IMG: {
m_imageSpan = true;
+ m_imageFormat = QTextImageFormat();
MD_SPAN_IMG_DETAIL *detail = static_cast<MD_SPAN_IMG_DETAIL *>(det);
- QString src = QString::fromUtf8(detail->src.text, int(detail->src.size));
- QString title = QString::fromUtf8(detail->title.text, int(detail->title.size));
- QTextImageFormat img;
- img.setName(src);
- if (m_needsInsertBlock)
- insertBlock();
- qCDebug(lcMD) << "image" << src << "title" << title << "relative to" << m_doc->baseUrl();
- m_cursor->insertImage(img);
+ m_imageFormat.setName(QString::fromUtf8(detail->src.text, int(detail->src.size)));
+ m_imageFormat.setProperty(QTextFormat::ImageTitle, QString::fromUtf8(detail->title.text, int(detail->title.size)));
break;
}
case MD_SPAN_CODE:
@@ -406,8 +403,6 @@ int QTextMarkdownImporter::cbLeaveSpan(int spanType, void *detail)
int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size)
{
- if (m_imageSpan)
- return 0; // it's the alt-text
if (m_needsInsertBlock)
insertBlock();
#if QT_CONFIG(regularexpression)
@@ -481,6 +476,17 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size)
break;
}
+ if (m_imageSpan) {
+ // TODO we don't yet support alt text with formatting, because of the cases where m_cursor
+ // already inserted the text above. Rather need to accumulate it in case we need it here.
+ m_imageFormat.setProperty(QTextFormat::ImageAltText, s);
+ qCDebug(lcMD) << "image" << m_imageFormat.name()
+ << "title" << m_imageFormat.stringProperty(QTextFormat::ImageTitle)
+ << "alt" << s << "relative to" << m_doc->baseUrl();
+ m_cursor->insertImage(m_imageFormat);
+ return 0; // no error
+ }
+
if (!s.isEmpty())
m_cursor->insertText(s);
if (m_cursor->currentList()) {
@@ -536,6 +542,8 @@ void QTextMarkdownImporter::insertBlock()
}
if (m_codeBlock) {
blockFormat.setProperty(QTextFormat::BlockCodeLanguage, m_blockCodeLanguage);
+ if (m_blockCodeFence)
+ blockFormat.setProperty(QTextFormat::BlockCodeFence, QString(QLatin1Char(m_blockCodeFence)));
charFormat.setFont(m_monoFont);
} else {
blockFormat.setTopMargin(m_paragraphMargin);
diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h
index f905aa0f87..1b8c2ca354 100644
--- a/src/gui/text/qtextmarkdownimporter_p.h
+++ b/src/gui/text/qtextmarkdownimporter_p.h
@@ -124,7 +124,9 @@ private:
int m_tableCol = -1; // because relative cell movements (e.g. m_cursor->movePosition(QTextCursor::NextCell)) don't work
int m_paragraphMargin = 0;
int m_blockType = 0;
+ char m_blockCodeFence = 0;
Features m_features;
+ QTextImageFormat m_imageFormat;
QTextListFormat m_listFormat;
QTextBlockFormat::MarkerType m_markerType = QTextBlockFormat::NoMarker;
bool m_needsInsertBlock = false;
diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp
index 02643acdca..f351c8d20b 100644
--- a/src/gui/text/qtextmarkdownwriter.cpp
+++ b/src/gui/text/qtextmarkdownwriter.cpp
@@ -55,6 +55,7 @@ Q_LOGGING_CATEGORY(lcMDW, "qt.text.markdown.writer")
static const QChar Space = QLatin1Char(' ');
static const QChar Newline = QLatin1Char('\n');
static const QChar LineBreak = QChar(0x2028);
+static const QChar DoubleQuote = QLatin1Char('"');
static const QChar Backtick = QLatin1Char('`');
static const QChar Period = QLatin1Char('.');
@@ -133,6 +134,24 @@ void QTextMarkdownWriter::writeFrame(const QTextFrame *frame)
writeFrame(iterator.currentFrame());
else { // no frame, it's a block
QTextBlock block = iterator.currentBlock();
+ // Look ahead and detect some cases when we should
+ // suppress needless blank lines, when there will be a big change in block format
+ bool nextIsDifferent = false;
+ bool ending = false;
+ {
+ QTextFrame::iterator next = iterator;
+ ++next;
+ if (next.atEnd()) {
+ nextIsDifferent = true;
+ ending = true;
+ } else {
+ QTextBlockFormat format = iterator.currentBlock().blockFormat();
+ QTextBlockFormat nextFormat = next.currentBlock().blockFormat();
+ if (nextFormat.indent() != format.indent() ||
+ nextFormat.property(QTextFormat::BlockCodeLanguage) != format.property(QTextFormat::BlockCodeLanguage))
+ nextIsDifferent = true;
+ }
+ }
if (table) {
QTextTableCell cell = table->cellAt(block.position());
if (tableRow < cell.row()) {
@@ -149,7 +168,7 @@ void QTextMarkdownWriter::writeFrame(const QTextFrame *frame)
if (lastWasList)
m_stream << Newline;
}
- int endingCol = writeBlock(block, !table, table && tableRow == 0);
+ int endingCol = writeBlock(block, !table, table && tableRow == 0, nextIsDifferent);
m_doubleNewlineWritten = false;
if (table) {
QTextTableCell cell = table->cellAt(block.position());
@@ -161,11 +180,19 @@ void QTextMarkdownWriter::writeFrame(const QTextFrame *frame)
m_stream << QString(paddingLen, Space);
for (int col = cell.column(); col < spanEndCol; ++col)
m_stream << "|";
- } else if (block.textList() || block.blockFormat().hasProperty(QTextFormat::BlockCodeLanguage)) {
+ } else if (m_fencedCodeBlock && ending) {
+ m_stream << m_linePrefix << QString(m_wrappedLineIndent, Space)
+ << m_codeBlockFence << Newline << Newline;
+ m_codeBlockFence.clear();
+ } else if (m_indentedCodeBlock && nextIsDifferent) {
m_stream << Newline;
} else if (endingCol > 0) {
- m_stream << Newline << Newline;
- m_doubleNewlineWritten = true;
+ if (block.textList() || block.blockFormat().hasProperty(QTextFormat::BlockCodeLanguage)) {
+ m_stream << Newline;
+ } else {
+ m_stream << Newline << Newline;
+ m_doubleNewlineWritten = true;
+ }
}
lastWasList = block.textList();
}
@@ -258,11 +285,13 @@ static void maybeEscapeFirstChar(QString &s)
}
}
-int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ignoreFormat)
+int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ignoreFormat, bool ignoreEmpty)
{
+ if (block.text().isEmpty() && ignoreEmpty)
+ return 0;
const int ColumnLimit = 80;
QTextBlockFormat blockFmt = block.blockFormat();
- bool indentedCodeBlock = false;
+ bool missedBlankCodeBlockLine = false;
if (block.textList()) { // it's a list-item
auto fmt = block.textList()->format();
const int listLevel = fmt.indent();
@@ -323,7 +352,28 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
} else if (blockFmt.hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)) {
m_stream << "- - -\n"; // unambiguous horizontal rule, not an underline under a heading
return 0;
+ } else if (blockFmt.hasProperty(QTextFormat::BlockCodeFence) || blockFmt.stringProperty(QTextFormat::BlockCodeLanguage).length() > 0) {
+ // It's important to preserve blank lines in code blocks. But blank lines in code blocks
+ // inside block quotes are getting preserved anyway (along with the "> " prefix).
+ if (!blockFmt.hasProperty(QTextFormat::BlockQuoteLevel))
+ missedBlankCodeBlockLine = true; // only if we don't get any fragments below
+ if (!m_fencedCodeBlock) {
+ QString fenceChar = blockFmt.stringProperty(QTextFormat::BlockCodeFence);
+ if (fenceChar.isEmpty())
+ fenceChar = QLatin1String("`");
+ m_codeBlockFence = QString(3, fenceChar.at(0));
+ // A block quote can contain an indented code block, but not vice-versa.
+ m_stream << m_linePrefix << QString(m_wrappedLineIndent, Space) << m_codeBlockFence
+ << Space << blockFmt.stringProperty(QTextFormat::BlockCodeLanguage) << Newline;
+ m_fencedCodeBlock = true;
+ }
} else if (!blockFmt.indent()) {
+ if (m_fencedCodeBlock) {
+ m_stream << m_linePrefix << QString(m_wrappedLineIndent, Space)
+ << m_codeBlockFence << Newline;
+ m_fencedCodeBlock = false;
+ m_codeBlockFence.clear();
+ }
m_wrappedLineIndent = 0;
m_linePrefix.clear();
if (blockFmt.hasProperty(QTextFormat::BlockQuoteLevel)) {
@@ -336,7 +386,7 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
if (blockFmt.hasProperty(QTextFormat::BlockCodeLanguage)) {
// A block quote can contain an indented code block, but not vice-versa.
m_linePrefix += QString(4, Space);
- indentedCodeBlock = true;
+ m_indentedCodeBlock = true;
}
}
if (blockFmt.headingLevel())
@@ -357,6 +407,7 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
bool strikeOut = false;
QString backticks(Backtick);
for (QTextBlock::Iterator frag = block.begin(); !frag.atEnd(); ++frag) {
+ missedBlankCodeBlockLine = false;
QString fragmentText = frag.fragment().text();
while (fragmentText.endsWith(Newline))
fragmentText.chop(1);
@@ -372,7 +423,14 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
QTextCharFormat fmt = frag.fragment().charFormat();
if (fmt.isImageFormat()) {
QTextImageFormat ifmt = fmt.toImageFormat();
- QString s = QLatin1String("![image](") + ifmt.name() + QLatin1Char(')');
+ QString desc = ifmt.stringProperty(QTextFormat::ImageAltText);
+ if (desc.isEmpty())
+ desc = QLatin1String("image");
+ QString s = QLatin1String("![") + desc + QLatin1String("](") + ifmt.name();
+ QString title = ifmt.stringProperty(QTextFormat::ImageTitle);
+ if (!title.isEmpty())
+ s += Space + DoubleQuote + title + DoubleQuote;
+ s += QLatin1Char(')');
if (wrap && col + s.length() > ColumnLimit) {
m_stream << Newline << wrapIndentString;
col = m_wrappedLineIndent;
@@ -393,7 +451,7 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
bool monoFrag = fontInfo.fixedPitch();
QString markers;
if (!ignoreFormat) {
- if (monoFrag != mono && !indentedCodeBlock) {
+ if (monoFrag != mono && !m_indentedCodeBlock && !m_fencedCodeBlock) {
if (monoFrag)
backticks = QString(adjacentBackticksCount(fragmentText) + 1, Backtick);
markers += backticks;
@@ -493,6 +551,8 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
m_stream << "~~";
col += 2;
}
+ if (missedBlankCodeBlockLine)
+ m_stream << Newline;
return col;
}
diff --git a/src/gui/text/qtextmarkdownwriter_p.h b/src/gui/text/qtextmarkdownwriter_p.h
index 96ceb445cd..90310250ac 100644
--- a/src/gui/text/qtextmarkdownwriter_p.h
+++ b/src/gui/text/qtextmarkdownwriter_p.h
@@ -67,7 +67,7 @@ public:
bool writeAll(const QTextDocument *document);
void writeTable(const QAbstractItemModel *table);
- int writeBlock(const QTextBlock &block, bool table, bool ignoreFormat);
+ int writeBlock(const QTextBlock &block, bool table, bool ignoreFormat, bool ignoreEmpty);
void writeFrame(const QTextFrame *frame);
private:
@@ -82,9 +82,12 @@ private:
QTextDocument::MarkdownFeatures m_features;
QMap<QTextList *, ListInfo> m_listInfo;
QString m_linePrefix;
+ QString m_codeBlockFence;
int m_wrappedLineIndent = 0;
int m_lastListIndent = 1;
bool m_doubleNewlineWritten = false;
+ bool m_indentedCodeBlock = false;
+ bool m_fencedCodeBlock = false;
};
QT_END_NAMESPACE
diff --git a/src/gui/vulkan/qplatformvulkaninstance.cpp b/src/gui/vulkan/qplatformvulkaninstance.cpp
index 6201d3ec11..9d044bfd58 100644
--- a/src/gui/vulkan/qplatformvulkaninstance.cpp
+++ b/src/gui/vulkan/qplatformvulkaninstance.cpp
@@ -85,4 +85,9 @@ void QPlatformVulkanInstance::presentQueued(QWindow *window)
Q_UNUSED(window);
}
+void QPlatformVulkanInstance::setDebugFilters(const QVector<QVulkanInstance::DebugFilter> &filters)
+{
+ Q_UNUSED(filters);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/vulkan/qplatformvulkaninstance.h b/src/gui/vulkan/qplatformvulkaninstance.h
index 9f34803f7b..d47c59b5db 100644
--- a/src/gui/vulkan/qplatformvulkaninstance.h
+++ b/src/gui/vulkan/qplatformvulkaninstance.h
@@ -78,6 +78,7 @@ public:
virtual PFN_vkVoidFunction getInstanceProcAddr(const char *name) = 0;
virtual bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) = 0;
virtual void presentQueued(QWindow *window);
+ virtual void setDebugFilters(const QVector<QVulkanInstance::DebugFilter> &filters);
private:
QScopedPointer<QPlatformVulkanInstancePrivate> d_ptr;
diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp
index 2941bfd01f..0605d88cca 100644
--- a/src/gui/vulkan/qvulkaninstance.cpp
+++ b/src/gui/vulkan/qvulkaninstance.cpp
@@ -269,6 +269,7 @@ public:
VkResult errorCode;
QScopedPointer<QVulkanFunctions> funcs;
QHash<VkDevice, QVulkanDeviceFunctions *> deviceFuncs;
+ QVector<QVulkanInstance::DebugFilter> debugFilters;
};
bool QVulkanInstancePrivate::ensureVulkan()
@@ -570,6 +571,7 @@ bool QVulkanInstance::create()
d_ptr->extensions = d_ptr->platformInst->enabledExtensions();
d_ptr->errorCode = VK_SUCCESS;
d_ptr->funcs.reset(new QVulkanFunctions(this));
+ d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
return true;
}
@@ -785,6 +787,50 @@ void QVulkanInstance::presentQueued(QWindow *window)
d_ptr->platformInst->presentQueued(window);
}
+/*!
+ \typedef QVulkanInstance::DebugFilter
+
+ Typedef for debug filtering callback functions.
+
+ \sa installDebugOutputFilter(), removeDebugOutputFilter()
+ */
+
+/*!
+ Installs a \a filter function that is called for every Vulkan debug
+ message. When the callback returns \c true, the message is stopped (filtered
+ out) and will not appear on the debug output.
+
+ \note Filtering is only effective when NoDebugOutputRedirect is not
+ \l{setFlags()}{set}. Installing filters has no effect otherwise.
+
+ \note This function can be called before create().
+
+ \sa removeDebugOutputFilter()
+ */
+void QVulkanInstance::installDebugOutputFilter(DebugFilter filter)
+{
+ if (!d_ptr->debugFilters.contains(filter)) {
+ d_ptr->debugFilters.append(filter);
+ if (d_ptr->platformInst)
+ d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
+ }
+}
+
+/*!
+ Removes a \a filter function previously installed by
+ installDebugOutputFilter().
+
+ \note This function can be called before create().
+
+ \sa installDebugOutputFilter()
+ */
+void QVulkanInstance::removeDebugOutputFilter(DebugFilter filter)
+{
+ d_ptr->debugFilters.removeOne(filter);
+ if (d_ptr->platformInst)
+ d_ptr->platformInst->setDebugFilters(d_ptr->debugFilters);
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QVulkanLayer &layer)
{
diff --git a/src/gui/vulkan/qvulkaninstance.h b/src/gui/vulkan/qvulkaninstance.h
index f28975f911..70f2fd5102 100644
--- a/src/gui/vulkan/qvulkaninstance.h
+++ b/src/gui/vulkan/qvulkaninstance.h
@@ -188,6 +188,11 @@ public:
void presentQueued(QWindow *window);
+ typedef bool (*DebugFilter)(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object,
+ size_t location, int32_t messageCode, const char *pLayerPrefix, const char *pMessage);
+ void installDebugOutputFilter(DebugFilter filter);
+ void removeDebugOutputFilter(DebugFilter filter);
+
private:
QScopedPointer<QVulkanInstancePrivate> d_ptr;
Q_DISABLE_COPY(QVulkanInstance)