diff --git a/src/texthandler.cpp b/src/texthandler.cpp index dcfbfc02f..33be763a5 100644 --- a/src/texthandler.cpp +++ b/src/texthandler.cpp @@ -4,6 +4,7 @@ #include "texthandler.h" #include +#include #include #include #include @@ -34,7 +35,8 @@ static const QHash allowedAttributes = { {QStringLiteral("font"), {QStringLiteral("data-mx-bg-color"), QStringLiteral("data-mx-color"), QStringLiteral("color")}}, {QStringLiteral("span"), {QStringLiteral("data-mx-bg-color"), QStringLiteral("data-mx-color"), QStringLiteral("data-mx-spoiler")}}, {QStringLiteral("a"), {QStringLiteral("name"), QStringLiteral("target"), QStringLiteral("href")}}, - {QStringLiteral("img"), {QStringLiteral("width"), QStringLiteral("height"), QStringLiteral("alt"), QStringLiteral("title"), QStringLiteral("src")}}, + {QStringLiteral("img"), + {QStringLiteral("style"), QStringLiteral("width"), QStringLiteral("height"), QStringLiteral("alt"), QStringLiteral("title"), QStringLiteral("src")}}, {QStringLiteral("ol"), {QStringLiteral("start")}}, {QStringLiteral("code"), {QStringLiteral("class")}}}; static const QStringList allowedLinkSchemes = {QStringLiteral("https"), @@ -50,6 +52,8 @@ static const QStringList blockTags = {QStringLiteral("blockquote"), QStringLiteral("table"), QStringLiteral("pre")}; +static const QString customEmojiStyle = QStringLiteral("vertical-align:bottom"); + QString TextHandler::data() const { return m_data; @@ -131,9 +135,29 @@ TextHandler::handleRecieveRichText(Qt::TextFormat inputFormat, const NeoChatRoom while (i.hasNext()) { const QRegularExpressionMatch match = i.next(); const QUrl mediaUrl = room->makeMediaUrl(event->id(), QUrl(QStringLiteral("mxc://") + match.captured(2) + u'/' + match.captured(3))); + + QStringList extraAttributes = match.captured(4).split(QChar::Space); + const bool isEmoticon = match.captured(1).contains(QStringLiteral("data-mx-emoticon")); + + // If the image does not have an explicit width, but has a vertical-align it's most likely an emoticon. + // We must do some pre-processing for it to show up nicely in and around text. + if (isEmoticon) { + // Remove any pre-existing height + extraAttributes.removeIf([](const QString &s) { + return s.contains(QStringLiteral("height=")); + }); + + // Make sure it's the same height as the rest of the text + const QFontMetrics metrics(QGuiApplication::font()); + extraAttributes.append(QStringLiteral("height=\"%1\"").arg(metrics.height())); + + // Align it properly + extraAttributes.append(QStringLiteral("style=\"%1\"").arg(customEmojiStyle)); + } + m_dataBuffer.replace(match.captured(0), - QStringLiteral("'); + QStringLiteral("'); } } @@ -493,6 +517,12 @@ QString TextHandler::cleanAttributes(const QString &tag, const QString &tagStrin if (getAttributeData(nextAttribute).remove(u'"').startsWith(QStringLiteral("language-"))) { outputString.append(u' ' + nextAttribute); } + } else if (tag == QStringLiteral("img") && getAttributeType(nextAttribute) == QStringLiteral("style")) { + const QString attributeData = TextRegex::attributeData.match(getAttributeData(nextAttribute)).captured(1); + // Ignore every other style attribute except for our own, which we use to align custom emoticons + if (attributeData == customEmojiStyle) { + outputString.append(u' ' + nextAttribute); + } } else { outputString.append(u' ' + nextAttribute); }