Skip to content

Commit 3d76dae

Browse files
authored
Merge pull request #9697 from nextcloud/bugfix/9685/appicon-request
fix(asyncimageresponse): enhance check for received SVG response
2 parents d841932 + 4b852e4 commit 3d76dae

File tree

1 file changed

+43
-34
lines changed

1 file changed

+43
-34
lines changed

src/gui/tray/asyncimageresponse.cpp

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
#include "asyncimageresponse.h"
77

88
#include <QIcon>
9+
#include <QMimeDatabase>
910
#include <QPainter>
1011
#include <QSvgRenderer>
1112

1213
#include "accountmanager.h"
1314

15+
using namespace Qt::StringLiterals;
16+
1417
AsyncImageResponse::AsyncImageResponse(const QString &id, const QSize &requestedSize)
1518
{
1619
if (id.isEmpty()) {
@@ -19,15 +22,15 @@ AsyncImageResponse::AsyncImageResponse(const QString &id, const QSize &requested
1922
}
2023

2124
auto actualId = id;
22-
const auto idSplit = id.split(QStringLiteral("/"), Qt::SkipEmptyParts);
25+
const auto idSplit = id.split('/'_L1, Qt::SkipEmptyParts);
2326
const auto color = QColor(idSplit.last());
2427

2528
if(color.isValid()) {
2629
_svgRecolor = color;
2730
actualId.remove("/" % idSplit.last());
2831
}
2932

30-
_imagePaths = actualId.split(QLatin1Char(';'), Qt::SkipEmptyParts);
33+
_imagePaths = actualId.split(';'_L1, Qt::SkipEmptyParts);
3134
_requestedImageSize = requestedSize;
3235

3336
if (_imagePaths.isEmpty()) {
@@ -56,10 +59,10 @@ void AsyncImageResponse::processNextImage()
5659
}
5760

5861
const auto imagePath = _imagePaths.at(_index);
59-
if (imagePath.startsWith(QStringLiteral(":/client"))) {
62+
if (imagePath.startsWith(u":/client"_s)) {
6063
setImageAndEmitFinished(QIcon(imagePath).pixmap(_requestedImageSize).toImage());
6164
return;
62-
} else if (imagePath.startsWith(QStringLiteral(":/fileicon"))) {
65+
} else if (imagePath.startsWith(u":/fileicon"_s)) {
6366
const auto filePath = imagePath.mid(10);
6467
const auto fileInfo = QFileInfo(filePath);
6568
setImageAndEmitFinished(_fileIconProvider.icon(fileInfo).pixmap(_requestedImageSize).toImage());
@@ -83,7 +86,7 @@ void AsyncImageResponse::processNextImage()
8386
// for some reason trying to use `accountInRequestedServer` causes clang 21 to crash for me :(
8487
const auto accountQnam = accountInRequestedServer->networkAccessManager();
8588
QMetaObject::invokeMethod(accountQnam, [this, accountInRequestedServer, iconUrl]() -> void {
86-
const auto reply = accountInRequestedServer->sendRawRequest(QByteArrayLiteral("GET"), iconUrl);
89+
const auto reply = accountInRequestedServer->sendRawRequest("GET"_ba, iconUrl);
8790
connect(reply, &QNetworkReply::finished, this, [this, reply]() -> void {
8891
QMetaObject::invokeMethod(this, [this, reply]() -> void {
8992
processNetworkReply(reply);
@@ -109,36 +112,42 @@ void AsyncImageResponse::processNetworkReply(QNetworkReply *reply)
109112
const QByteArray imageData = reply->readAll();
110113
// server returns "[]" for some some file previews (have no idea why), so, we use another image
111114
// from the list if available
112-
if (imageData.isEmpty() || imageData == QByteArrayLiteral("[]")) {
115+
if (imageData.isEmpty() || imageData == "[]"_ba) {
113116
processNextImage();
114-
} else {
115-
if (imageData.startsWith(QByteArrayLiteral("<svg"))) {
116-
// SVG image needs proper scaling, let's do it with QPainter and QSvgRenderer
117-
QSvgRenderer svgRenderer;
118-
if (svgRenderer.load(imageData)) {
119-
QImage scaledSvg(_requestedImageSize, QImage::Format_ARGB32);
120-
scaledSvg.fill("transparent");
121-
QPainter painterForSvg(&scaledSvg);
122-
svgRenderer.render(&painterForSvg);
123-
124-
if(!_svgRecolor.isValid()) {
125-
setImageAndEmitFinished(scaledSvg);
126-
return;
127-
}
128-
129-
QImage image(_requestedImageSize, QImage::Format_ARGB32);
130-
image.fill(_svgRecolor);
131-
QPainter imagePainter(&image);
132-
imagePainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
133-
imagePainter.drawImage(0, 0, scaledSvg);
134-
setImageAndEmitFinished(image);
135-
return;
136-
} else {
137-
processNextImage();
138-
}
139-
} else {
140-
setImageAndEmitFinished(QImage::fromData(imageData));
141-
}
117+
return;
118+
}
119+
120+
// Some graphics programs export SVGs that begin with `<?xml version="1.0" [...]` and/or include some comments after that (e.g.
121+
// `<!-- Generator: ...`), so we can't rely on just the response to start with `<svg`.
122+
if (const auto mimetype = QMimeDatabase().mimeTypeForData(imageData);
123+
!(mimetype.isValid() && mimetype.inherits("image/svg+xml"_L1))) {
124+
// Not an SVG: let's let QImage deal with the response.
125+
setImageAndEmitFinished(QImage::fromData(imageData).scaled(_requestedImageSize));
126+
return;
127+
}
128+
129+
// SVG image needs proper scaling, let's do it with QPainter and QSvgRenderer
130+
QSvgRenderer svgRenderer;
131+
if (!svgRenderer.load(imageData)) {
132+
processNextImage();
133+
return;
134+
}
135+
136+
QImage scaledSvg(_requestedImageSize, QImage::Format_ARGB32);
137+
scaledSvg.fill("transparent");
138+
QPainter painterForSvg(&scaledSvg);
139+
svgRenderer.render(&painterForSvg);
140+
141+
if (!_svgRecolor.isValid()) {
142+
setImageAndEmitFinished(scaledSvg);
143+
return;
142144
}
145+
146+
QImage image(_requestedImageSize, QImage::Format_ARGB32);
147+
image.fill(_svgRecolor);
148+
QPainter imagePainter(&image);
149+
imagePainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
150+
imagePainter.drawImage(0, 0, scaledSvg);
151+
setImageAndEmitFinished(image);
143152
}
144153

0 commit comments

Comments
 (0)