summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@qt.io>2019-05-20 12:58:36 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2019-06-01 21:13:58 +0200
commit237fa21feef63884043bd6cf32682b2b08c78454 (patch)
treedabbd1a0ece334bfb37bce76042621d7ae94b907 /src
parentca0c9f82cbf7c8c37acdcbdfdc3fa0c5fc138059 (diff)
Markdown and HTML: support image alt text and title
It's a required CommonMark feature: https://spec.commonmark.org/0.29/#images and alt text is also required in HTML: https://www.w3.org/wiki/Html/Elements/img#Requirements_for_providing_text_to_act_as_an_alternative_for_images Now we are able to read these attributes from either html or markdown and rewrite either an html or markdown document that preserves them. This patch does not add viewing or editing support in QTextEdit etc. Change-Id: I51307389f8f9fc00809808390e583a83111a7b33 Reviewed-by: Gatis Paeglis <gatis.paeglis@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/gui/text/qtextdocument.cpp6
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp4
-rw-r--r--src/gui/text/qtextformat.cpp8
-rw-r--r--src/gui/text/qtextformat.h2
-rw-r--r--src/gui/text/qtexthtmlparser.cpp4
-rw-r--r--src/gui/text/qtexthtmlparser_p.h1
-rw-r--r--src/gui/text/qtextmarkdownimporter.cpp24
-rw-r--r--src/gui/text/qtextmarkdownimporter_p.h1
-rw-r--r--src/gui/text/qtextmarkdownwriter.cpp10
9 files changed, 48 insertions, 12 deletions
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..644dd5558d 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -659,7 +659,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..4f534fb65d 100644
--- a/src/gui/text/qtextformat.h
+++ b/src/gui/text/qtextformat.h
@@ -253,6 +253,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..49ee6394ee 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:
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..223eb01e55 100644
--- a/src/gui/text/qtextmarkdownimporter.cpp
+++ b/src/gui/text/qtextmarkdownimporter.cpp
@@ -362,15 +362,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 +401,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 +474,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()) {
diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h
index f905aa0f87..fdce74483b 100644
--- a/src/gui/text/qtextmarkdownimporter_p.h
+++ b/src/gui/text/qtextmarkdownimporter_p.h
@@ -125,6 +125,7 @@ private:
int m_paragraphMargin = 0;
int m_blockType = 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..58e0c86b95 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('.');
@@ -372,7 +373,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;