summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias Rauter <matthias.rauter@qt.io>2023-12-27 14:03:00 +0100
committerMatthias Rauter <matthias.rauter@qt.io>2024-01-06 11:17:10 +0100
commit604fe97dd110dbac52d9fafc81549788df33b482 (patch)
tree90db863ac31c1e4f3d8215c265f2ecb7ab30ad9d /src
parent1aaaf8b40f870c9113d5b77ceacaea521d2fdef0 (diff)
Fix a crash when SVG filters fail
This bug was triggered by a test in the resvg test suit: filters/filters/in=BackgroundAlpha.svg The patch further includes a small optimization: The sourceAlpha filter buffer is only created on request. Pick-to: 6.7 Change-Id: I208d43c54f07d530f476b459f30c1b8aa62c2018 Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/svg/qsvgfilter.cpp40
-rw-r--r--src/svg/qsvgfilter_p.h6
-rw-r--r--src/svg/qsvgstructure.cpp40
-rw-r--r--src/svg/qsvgtinydocument_p.h1
4 files changed, 72 insertions, 15 deletions
diff --git a/src/svg/qsvgfilter.cpp b/src/svg/qsvgfilter.cpp
index 2c86f7d..59d928d 100644
--- a/src/svg/qsvgfilter.cpp
+++ b/src/svg/qsvgfilter.cpp
@@ -61,6 +61,25 @@ void QSvgFeFilterPrimitive::clipToTransformedBounds(QImage *buffer, QPainter *p,
painter.fillPath(clipPath, Qt::transparent);
}
+bool QSvgFeFilterPrimitive::requiresSourceAlpha() const
+{
+ return m_input == QLatin1StringView("SourceAlpha");
+}
+
+const QSvgFeFilterPrimitive *QSvgFeFilterPrimitive::castToFilterPrimitive(const QSvgNode *node)
+{
+ if (node->type() == QSvgNode::FeMerge ||
+ node->type() == QSvgNode::FeColormatrix ||
+ node->type() == QSvgNode::FeGaussianblur ||
+ node->type() == QSvgNode::FeOffset ||
+ node->type() == QSvgNode::FeComposite ||
+ node->type() == QSvgNode::FeFlood ) {
+ return reinterpret_cast<const QSvgFeFilterPrimitive*>(node);
+ } else {
+ return nullptr;
+ }
+}
+
QSvgFeColorMatrix::QSvgFeColorMatrix(QSvgNode *parent, QString input, QString result, const QSvgRectF &rect,
ColorShiftType type, Matrix matrix)
: QSvgFeFilterPrimitive(parent, input, result, rect)
@@ -449,6 +468,19 @@ QImage QSvgFeMerge::apply(QSvgNode *item, const QMap<QString, QImage> &sources,
return result;
}
+bool QSvgFeMerge::requiresSourceAlpha() const
+{
+ for (int i = 0; i < renderers().size(); i++) {
+ QSvgNode *child = renderers().at(i);
+ if (child->type() == QSvgNode::FeMergenode) {
+ QSvgFeMergeNode *filter = static_cast<QSvgFeMergeNode *>(child);
+ if (filter->requiresSourceAlpha())
+ return true;
+ }
+ }
+ return false;
+}
+
QSvgFeMergeNode::QSvgFeMergeNode(QSvgNode *parent, QString input, QString result, const QSvgRectF &rect)
: QSvgFeFilterPrimitive(parent, input, result, rect)
{
@@ -601,6 +633,14 @@ QImage QSvgFeComposite::apply(QSvgNode *item, const QMap<QString, QImage> &sourc
return result;
}
+bool QSvgFeComposite::requiresSourceAlpha() const
+{
+ if (QSvgFeFilterPrimitive::requiresSourceAlpha())
+ return true;
+ return m_input2 == QLatin1StringView("SourceAlpha");
+}
+
+
QSvgFeFlood::QSvgFeFlood(QSvgNode *parent, QString input, QString result,
const QSvgRectF &rect, const QColor &color)
: QSvgFeFilterPrimitive(parent, input, result, rect)
diff --git a/src/svg/qsvgfilter_p.h b/src/svg/qsvgfilter_p.h
index baeb0dc..22ecc59 100644
--- a/src/svg/qsvgfilter_p.h
+++ b/src/svg/qsvgfilter_p.h
@@ -43,12 +43,16 @@ public:
virtual QImage apply(QSvgNode *item, const QMap<QString, QImage> &sources,
QPainter *p, const QRectF &itemBounds, const QRectF &filterBounds,
QSvg::UnitTypes primitiveUnits, QSvg::UnitTypes filterUnits) const = 0;
+ virtual bool requiresSourceAlpha() const;
QString input() const {
return m_input;
}
QString result() const {
return m_result;
}
+
+ static const QSvgFeFilterPrimitive *castToFilterPrimitive(const QSvgNode *node);
+
protected:
QString m_input;
QString m_result;
@@ -124,6 +128,7 @@ public:
QImage apply(QSvgNode *item, const QMap<QString, QImage> &sources,
QPainter *p, const QRectF &itemBounds, const QRectF &filterBounds,
QSvg::UnitTypes primitiveUnits, QSvg::UnitTypes filterUnits) const override;
+ bool requiresSourceAlpha() const override;
};
class Q_SVG_EXPORT QSvgFeMergeNode : public QSvgFeFilterPrimitive
@@ -154,6 +159,7 @@ public:
QImage apply(QSvgNode *item, const QMap<QString, QImage> &sources,
QPainter *p, const QRectF &itemBounds, const QRectF &filterBounds,
QSvg::UnitTypes primitiveUnits, QSvg::UnitTypes filterUnits) const override;
+ bool requiresSourceAlpha() const override;
private:
QString m_input2;
Operator m_operator;
diff --git a/src/svg/qsvgstructure.cpp b/src/svg/qsvgstructure.cpp
index 9234fe5..1cfd441 100644
--- a/src/svg/qsvgstructure.cpp
+++ b/src/svg/qsvgstructure.cpp
@@ -387,28 +387,38 @@ QImage QSvgFilterContainer::applyFilter(QSvgNode *item, const QImage &buffer, QP
QImage proxy = buffer.copy(filterBoundsGlobRel);
proxy.setOffset(filterBoundsGlob.topLeft());
-
- QImage proxyAlpha = proxy.convertedTo(QImage::Format_Alpha8).convertedTo(proxy.format());
- // ### TODO: allocation check
- proxyAlpha.setOffset(proxy.offset());
+ if (proxy.isNull())
+ return buffer;
QMap<QString, QImage> buffers;
buffers[QStringLiteral("")] = proxy;
buffers[QStringLiteral("SourceGraphic")] = proxy;
- buffers[QStringLiteral("SourceAlpha")] = proxyAlpha;
+
+ bool requiresSourceAlpha = false;
+
+ const QList<QSvgNode *> children = renderers();
+ for (const QSvgNode *renderer : children) {
+ const QSvgFeFilterPrimitive *filter = QSvgFeFilterPrimitive::castToFilterPrimitive(renderer);
+ if (filter && filter->requiresSourceAlpha()) {
+ requiresSourceAlpha = true;
+ break;
+ }
+ }
+
+ if (requiresSourceAlpha) {
+ QImage proxyAlpha = proxy.convertedTo(QImage::Format_Alpha8).convertedTo(proxy.format());
+ proxyAlpha.setOffset(proxy.offset());
+ if (proxyAlpha.isNull())
+ return buffer;
+ buffers[QStringLiteral("SourceAlpha")] = proxyAlpha;
+ }
QImage result;
- for (int i = 0; i < renderers().size(); i++) {
- QSvgNode *child = renderers().at(i);
- if (child->type() == QSvgNode::FeMerge ||
- child->type() == QSvgNode::FeColormatrix ||
- child->type() == QSvgNode::FeGaussianblur ||
- child->type() == QSvgNode::FeOffset ||
- child->type() == QSvgNode::FeComposite ||
- child->type() == QSvgNode::FeFlood ) {
- QSvgFeFilterPrimitive *filter = reinterpret_cast<QSvgFeFilterPrimitive*>(child);
+ for (const QSvgNode *renderer : children) {
+ const QSvgFeFilterPrimitive *filter = QSvgFeFilterPrimitive::castToFilterPrimitive(renderer);
+ if (filter) {
result = filter->apply(item, buffers, p, bounds, filterBounds, m_primitiveUnits, m_filterUnits);
- if (result.size().isValid()) {
+ if (!result.isNull()) {
buffers[QStringLiteral("")] = result;
buffers[filter->result()] = result;
}
diff --git a/src/svg/qsvgtinydocument_p.h b/src/svg/qsvgtinydocument_p.h
index d0b1dbb..b6780ae 100644
--- a/src/svg/qsvgtinydocument_p.h
+++ b/src/svg/qsvgtinydocument_p.h
@@ -86,6 +86,7 @@ public:
int currentFrame() const;
void setCurrentFrame(int);
void setFramesPerSecond(int num);
+
private:
void mapSourceToTarget(QPainter *p, const QRectF &targetRect, const QRectF &sourceRect = QRectF());
private: