Work around compiler bug in QTransform
gcc version 13.2.0 (Ubuntu 13.2.0-23ubuntu4) seems to remove some code in release builds that is embedded in a macro in qtransfrom.cpp. This patch changes the macro into a function such that it is not removed by gcc. It seems like the switch statement is (wrongly) optimized away if it is embedded in the QTransform::map(QPolygonF) overload. nx and ny are always 0 (as initialized by QPolygonF) after the macro (but only within the QTransform::map(QPolygonF) function. The bug happens only in a release build. Added debug messages of nx and ny created no output, adding qDebug() << t, which made the macro work. It seems that a complex combination of macro and switch statement can tigger the bug in gcc. So rewriting the macro as a function works around the bug. Fixes: QTBUG-127723 Change-Id: I7e0b02cde276e591cf773f4e18dd505134421957 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io> (cherry picked from commit 11b70b66de627d3bd0ef4193d5cfa624c88ac96a) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
11473410c2
commit
1909435b03
@ -26,40 +26,38 @@ static void nanWarning(const char *func)
|
||||
|
||||
#define Q_NEAR_CLIP (sizeof(qreal) == sizeof(double) ? 0.000001 : 0.0001)
|
||||
|
||||
#ifdef MAP
|
||||
# undef MAP
|
||||
#endif
|
||||
#define MAP(x, y, nx, ny) \
|
||||
do { \
|
||||
qreal FX_ = x; \
|
||||
qreal FY_ = y; \
|
||||
switch(t) { \
|
||||
case TxNone: \
|
||||
nx = FX_; \
|
||||
ny = FY_; \
|
||||
break; \
|
||||
case TxTranslate: \
|
||||
nx = FX_ + m_matrix[2][0]; \
|
||||
ny = FY_ + m_matrix[2][1]; \
|
||||
break; \
|
||||
case TxScale: \
|
||||
nx = m_matrix[0][0] * FX_ + m_matrix[2][0]; \
|
||||
ny = m_matrix[1][1] * FY_ + m_matrix[2][1]; \
|
||||
break; \
|
||||
case TxRotate: \
|
||||
case TxShear: \
|
||||
case TxProject: \
|
||||
nx = m_matrix[0][0] * FX_ + m_matrix[1][0] * FY_ + m_matrix[2][0]; \
|
||||
ny = m_matrix[0][1] * FX_ + m_matrix[1][1] * FY_ + m_matrix[2][1]; \
|
||||
if (t == TxProject) { \
|
||||
qreal w = (m_matrix[0][2] * FX_ + m_matrix[1][2] * FY_ + m_matrix[2][2]); \
|
||||
if (w < qreal(Q_NEAR_CLIP)) w = qreal(Q_NEAR_CLIP); \
|
||||
w = qreal(1.)/w; \
|
||||
nx *= w; \
|
||||
ny *= w; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
void QTransform::do_map(qreal x, qreal y, qreal &nx, qreal &ny) const
|
||||
{
|
||||
const TransformationType t = inline_type();
|
||||
switch (t) {
|
||||
case QTransform::TxNone:
|
||||
nx = x;
|
||||
ny = y;
|
||||
return;
|
||||
case QTransform::TxTranslate:
|
||||
nx = x + m_matrix[2][0];
|
||||
ny = y + m_matrix[2][1];
|
||||
return;
|
||||
case QTransform::TxScale:
|
||||
nx = m_matrix[0][0] * x + m_matrix[2][0];
|
||||
ny = m_matrix[1][1] * y + m_matrix[2][1];
|
||||
return;
|
||||
case QTransform::TxRotate:
|
||||
case QTransform::TxShear:
|
||||
case QTransform::TxProject:
|
||||
nx = m_matrix[0][0] * x + m_matrix[1][0] * y + m_matrix[2][0];
|
||||
ny = m_matrix[0][1] * x + m_matrix[1][1] * y + m_matrix[2][1];
|
||||
if (t == QTransform::TxProject) {
|
||||
qreal w = (m_matrix[0][2] * x + m_matrix[1][2] * y + m_matrix[2][2]);
|
||||
if (w < qreal(Q_NEAR_CLIP)) w = qreal(Q_NEAR_CLIP);
|
||||
w = qreal(1.)/w;
|
||||
nx *= w;
|
||||
ny *= w;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Q_UNREACHABLE_RETURN();
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QTransform
|
||||
@ -1144,8 +1142,7 @@ QPoint QTransform::map(const QPoint &p) const
|
||||
|
||||
qreal x = 0, y = 0;
|
||||
|
||||
TransformationType t = inline_type();
|
||||
MAP(fx, fy, x, y);
|
||||
do_map(fx, fy, x, y);
|
||||
|
||||
return QPoint(qRound(x), qRound(y));
|
||||
}
|
||||
@ -1173,8 +1170,7 @@ QPointF QTransform::map(const QPointF &p) const
|
||||
|
||||
qreal x = 0, y = 0;
|
||||
|
||||
TransformationType t = inline_type();
|
||||
MAP(fx, fy, x, y);
|
||||
do_map(fx, fy, x, y);
|
||||
|
||||
return QPointF(x, y);
|
||||
}
|
||||
@ -1222,9 +1218,8 @@ QLine QTransform::map(const QLine &l) const
|
||||
|
||||
qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
|
||||
|
||||
TransformationType t = inline_type();
|
||||
MAP(fx1, fy1, x1, y1);
|
||||
MAP(fx2, fy2, x2, y2);
|
||||
do_map(fx1, fy1, x1, y1);
|
||||
do_map(fx2, fy2, x2, y2);
|
||||
|
||||
return QLine(qRound(x1), qRound(y1), qRound(x2), qRound(y2));
|
||||
}
|
||||
@ -1249,9 +1244,8 @@ QLineF QTransform::map(const QLineF &l) const
|
||||
|
||||
qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
|
||||
|
||||
TransformationType t = inline_type();
|
||||
MAP(fx1, fy1, x1, y1);
|
||||
MAP(fx2, fy2, x2, y2);
|
||||
do_map(fx1, fy1, x1, y1);
|
||||
do_map(fx2, fy2, x2, y2);
|
||||
|
||||
return QLineF(x1, y1, x2, y2);
|
||||
}
|
||||
@ -1296,7 +1290,7 @@ QPolygonF QTransform::map(const QPolygonF &a) const
|
||||
QPointF *dp = p.data();
|
||||
|
||||
for(i = 0; i < size; ++i) {
|
||||
MAP(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp);
|
||||
do_map(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@ -1324,7 +1318,7 @@ QPolygon QTransform::map(const QPolygon &a) const
|
||||
|
||||
for(i = 0; i < size; ++i) {
|
||||
qreal nx = 0, ny = 0;
|
||||
MAP(da[i].xp, da[i].yp, nx, ny);
|
||||
do_map(da[i].xp, da[i].yp, nx, ny);
|
||||
dp[i].xp = qRound(nx);
|
||||
dp[i].yp = qRound(ny);
|
||||
}
|
||||
@ -1545,7 +1539,7 @@ QPainterPath QTransform::map(const QPainterPath &path) const
|
||||
// Full xform
|
||||
for (int i=0; i<path.elementCount(); ++i) {
|
||||
QPainterPath::Element &e = copy.d_ptr->elements[i];
|
||||
MAP(e.x, e.y, e.x, e.y);
|
||||
do_map(e.x, e.y, e.x, e.y);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1598,12 +1592,12 @@ QPolygon QTransform::mapToPolygon(const QRect &rect) const
|
||||
y[2] = y[0]+h;
|
||||
y[3] = y[2];
|
||||
} else {
|
||||
qreal right = rect.x() + rect.width();
|
||||
qreal bottom = rect.y() + rect.height();
|
||||
MAP(rect.x(), rect.y(), x[0], y[0]);
|
||||
MAP(right, rect.y(), x[1], y[1]);
|
||||
MAP(right, bottom, x[2], y[2]);
|
||||
MAP(rect.x(), bottom, x[3], y[3]);
|
||||
auto right = rect.x() + rect.width();
|
||||
auto bottom = rect.y() + rect.height();
|
||||
do_map(rect.x(), rect.y(), x[0], y[0]);
|
||||
do_map(right, rect.y(), x[1], y[1]);
|
||||
do_map(right, bottom, x[2], y[2]);
|
||||
do_map(rect.x(), bottom, x[3], y[3]);
|
||||
}
|
||||
|
||||
// all coordinates are correctly, transform to a pointarray
|
||||
@ -1768,22 +1762,22 @@ QRect QTransform::mapRect(const QRect &rect) const
|
||||
return QRect(x, y, w, h);
|
||||
} else {
|
||||
qreal x = 0, y = 0;
|
||||
MAP(rect.left(), rect.top(), x, y);
|
||||
do_map(rect.left(), rect.top(), x, y);
|
||||
qreal xmin = x;
|
||||
qreal ymin = y;
|
||||
qreal xmax = x;
|
||||
qreal ymax = y;
|
||||
MAP(rect.right() + 1, rect.top(), x, y);
|
||||
do_map(rect.right() + 1, rect.top(), x, y);
|
||||
xmin = qMin(xmin, x);
|
||||
ymin = qMin(ymin, y);
|
||||
xmax = qMax(xmax, x);
|
||||
ymax = qMax(ymax, y);
|
||||
MAP(rect.right() + 1, rect.bottom() + 1, x, y);
|
||||
do_map(rect.right() + 1, rect.bottom() + 1, x, y);
|
||||
xmin = qMin(xmin, x);
|
||||
ymin = qMin(ymin, y);
|
||||
xmax = qMax(xmax, x);
|
||||
ymax = qMax(ymax, y);
|
||||
MAP(rect.left(), rect.bottom() + 1, x, y);
|
||||
do_map(rect.left(), rect.bottom() + 1, x, y);
|
||||
xmin = qMin(xmin, x);
|
||||
ymin = qMin(ymin, y);
|
||||
xmax = qMax(xmax, x);
|
||||
@ -1833,22 +1827,22 @@ QRectF QTransform::mapRect(const QRectF &rect) const
|
||||
return QRectF(x, y, w, h);
|
||||
} else {
|
||||
qreal x = 0, y = 0;
|
||||
MAP(rect.x(), rect.y(), x, y);
|
||||
do_map(rect.x(), rect.y(), x, y);
|
||||
qreal xmin = x;
|
||||
qreal ymin = y;
|
||||
qreal xmax = x;
|
||||
qreal ymax = y;
|
||||
MAP(rect.x() + rect.width(), rect.y(), x, y);
|
||||
do_map(rect.x() + rect.width(), rect.y(), x, y);
|
||||
xmin = qMin(xmin, x);
|
||||
ymin = qMin(ymin, y);
|
||||
xmax = qMax(xmax, x);
|
||||
ymax = qMax(ymax, y);
|
||||
MAP(rect.x() + rect.width(), rect.y() + rect.height(), x, y);
|
||||
do_map(rect.x() + rect.width(), rect.y() + rect.height(), x, y);
|
||||
xmin = qMin(xmin, x);
|
||||
ymin = qMin(ymin, y);
|
||||
xmax = qMax(xmax, x);
|
||||
ymax = qMax(ymax, y);
|
||||
MAP(rect.x(), rect.y() + rect.height(), x, y);
|
||||
do_map(rect.x(), rect.y() + rect.height(), x, y);
|
||||
xmin = qMin(xmin, x);
|
||||
ymin = qMin(ymin, y);
|
||||
xmax = qMax(xmax, x);
|
||||
@ -1883,8 +1877,7 @@ QRectF QTransform::mapRect(const QRectF &rect) const
|
||||
*/
|
||||
void QTransform::map(qreal x, qreal y, qreal *tx, qreal *ty) const
|
||||
{
|
||||
TransformationType t = inline_type();
|
||||
MAP(x, y, *tx, *ty);
|
||||
do_map(x, y, *tx, *ty);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1897,9 +1890,8 @@ void QTransform::map(qreal x, qreal y, qreal *tx, qreal *ty) const
|
||||
*/
|
||||
void QTransform::map(int x, int y, int *tx, int *ty) const
|
||||
{
|
||||
TransformationType t = inline_type();
|
||||
qreal fx = 0, fy = 0;
|
||||
MAP(x, y, fx, fy);
|
||||
do_map(x, y, fx, fy);
|
||||
*tx = qRound(fx);
|
||||
*ty = qRound(fy);
|
||||
}
|
||||
|
@ -145,6 +145,7 @@ public:
|
||||
|
||||
private:
|
||||
inline TransformationType inline_type() const;
|
||||
void do_map(qreal x, qreal y, qreal &nx, qreal &ny) const;
|
||||
qreal m_matrix[3][3];
|
||||
|
||||
mutable uint m_type : 5;
|
||||
|
@ -34,6 +34,7 @@ private slots:
|
||||
void projectivePathMapping();
|
||||
void mapInt();
|
||||
void mapPathWithPoint();
|
||||
void mapRectToPolygon(); // QTBUG-127723
|
||||
|
||||
private:
|
||||
void mapping_data();
|
||||
@ -700,6 +701,19 @@ void tst_QTransform::mapPathWithPoint()
|
||||
QCOMPARE(p.currentPosition(), QPointF(20, 20));
|
||||
}
|
||||
|
||||
void tst_QTransform::mapRectToPolygon()
|
||||
{
|
||||
QRectF r(7, 7, 36, 36);
|
||||
QTransform tx(2, 0, 0, 2, 0, 0);
|
||||
QPolygonF polygon1 = tx.mapToPolygon(r.toRect()).toPolygonF();
|
||||
QPolygonF polygon2 = tx.map(QPolygonF(r));
|
||||
if (polygon1.size() > 4)
|
||||
polygon1.removeLast();
|
||||
if (polygon2.size() > 4)
|
||||
polygon2.removeLast();
|
||||
QCOMPARE(polygon1, polygon2);
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QTransform)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user