aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2025-04-01 13:25:37 +0800
committerMitch Curtis <mitch.curtis@qt.io>2025-04-26 02:56:36 +0800
commitbeebdbf5ef482d9253709158aac099a1247df24a (patch)
tree9f4817bbba49e420eb54a024e26fa7d041bd7686
parentfdcdacf5c5473fb62eac60bd185feafe7f2ddcef (diff)
Fix division by zero in QQuickSvgParser
df97b6b2de6282bd6422f1e531a42475dadc980d in Qt Base added an assert which detected this. This patch adds an early return if we're about to divide by zero, similar to 7ca1222296a9650f24979df57cc2c974a7e571ed. It also amends that patch to move the start point == end point check to pathArc(), since it's called from more places. Fixes: QTBUG-135387 Change-Id: If9c5655d5e736825e98d3e93201bf889a1785e49 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> (cherry picked from commit 8d597bea22728268beff583a79e2005b1df423bf) Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io> (cherry picked from commit 503cbb4ad07a06941761607f46964c9540595225) Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit 5482f67da7705ede34c987c61ee45e3221d7b2b7) (cherry picked from commit 98edc631a960bca758dde79ec5e63496eaed1b55)
-rw-r--r--src/quick/util/qquickpath.cpp2
-rw-r--r--src/quick/util/qquicksvgparser.cpp12
-rw-r--r--tests/auto/quick/qquickshape/data/changeElementsImperatively.qml21
-rw-r--r--tests/auto/quick/qquickshape/tst_qquickshape.cpp10
4 files changed, 43 insertions, 2 deletions
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index 292d777036..71331c0a4a 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -2031,8 +2031,6 @@ void QQuickPathArc::addToPath(QPainterPath &path, const QQuickPathData &data)
{
const QPointF &startPoint = path.currentPosition();
const QPointF &endPoint = positionForCurve(data, startPoint);
- if (startPoint == endPoint)
- return;
QQuickSvgParser::pathArc(path,
_radiusX,
_radiusY,
diff --git a/src/quick/util/qquicksvgparser.cpp b/src/quick/util/qquicksvgparser.cpp
index 3215753027..c1607be86a 100644
--- a/src/quick/util/qquicksvgparser.cpp
+++ b/src/quick/util/qquicksvgparser.cpp
@@ -195,6 +195,10 @@ void QQuickSvgParser::pathArc(QPainterPath &path,
qreal y,
qreal curx, qreal cury)
{
+ // Check if the start point is equal to the end point.
+ if (QPointF(curx, cury) == QPointF(x, y))
+ return;
+
qreal sin_th, cos_th;
qreal a00, a01, a10, a11;
qreal x0, y0, x1, y1, xc, yc;
@@ -205,6 +209,14 @@ void QQuickSvgParser::pathArc(QPainterPath &path,
rx = qAbs(rx);
ry = qAbs(ry);
+ // Avoid nans and division by zero.
+ if (qFuzzyIsNull(rx) || qFuzzyIsNull(ry)) {
+ // https://www.w3.org/TR/SVG/paths.html#ArcOutOfRangeParameters says:
+ // "If either rx or ry is 0, then this arc is treated as a straight line
+ // segment (a "lineto") joining the endpoints."
+ path.lineTo(x, y);
+ return;
+ }
sin_th = qSin(qDegreesToRadians(x_axis_rotation));
cos_th = qCos(qDegreesToRadians(x_axis_rotation));
diff --git a/tests/auto/quick/qquickshape/data/changeElementsImperatively.qml b/tests/auto/quick/qquickshape/data/changeElementsImperatively.qml
new file mode 100644
index 0000000000..129be7222a
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/changeElementsImperatively.qml
@@ -0,0 +1,21 @@
+import QtQuick
+import QtQuick.Shapes
+
+Shape {
+ width: 640
+ height: 480
+
+ Component.onCompleted: {
+ bottomPathLine.x = 20
+ }
+
+ ShapePath {
+ PathLine {}
+ PathLine {
+ id: bottomPathLine
+ }
+ PathArc {}
+ PathLine {}
+ PathArc {}
+ }
+}
diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
index 578d8d4e3a..0e20cec9ab 100644
--- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp
+++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
@@ -87,6 +87,7 @@ private slots:
void multilineDataTypes_data();
void multilineDataTypes();
void multilineStronglyTyped();
+ void changeElementsImperatively();
private:
QVector<QPolygonF> m_lowPolyLogo;
@@ -707,6 +708,15 @@ void tst_QQuickShape::multilineStronglyTyped()
}
}
+void tst_QQuickShape::changeElementsImperatively()
+{
+ // Shouldn't crash.
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("changeElementsImperatively.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+}
+
QTEST_MAIN(tst_QQuickShape)
#include "tst_qquickshape.moc"