Avoid floating point exceptions in rasterizeLine.
Task-number: QTBUG-16757 Change-Id: I3ef988f1e039c12529d62197d85a62f201e4ae12 Reviewed-by: Lars Knoll <lars.knoll@digia.com>bb10
parent
425af59f53
commit
85b4f0d2d3
|
|
@ -734,6 +734,35 @@ static inline QPointF snapTo26Dot6Grid(const QPointF &p)
|
|||
qFloorF(p.y() * 64) * (1 / qreal(64)));
|
||||
}
|
||||
|
||||
/*
|
||||
The rasterize line function relies on some div by zero which should
|
||||
result in +/-inf values. However, when floating point exceptions are
|
||||
enabled, this will cause crashes, so we return high numbers instead.
|
||||
As the returned value is used in further arithmetic, returning
|
||||
FLT_MAX/DBL_MAX will also cause values, so instead return a value
|
||||
that is well outside the int-range.
|
||||
*/
|
||||
static inline qreal qSafeDivide(qreal x, qreal y)
|
||||
{
|
||||
if (y == 0)
|
||||
return x > 0 ? 1e20 : -1e20;
|
||||
return x / y;
|
||||
}
|
||||
|
||||
/* Conversion to int fails if the value is too large to fit into INT_MAX or
|
||||
too small to fit into INT_MIN, so we need this slightly safer conversion
|
||||
when floating point exceptions are enabled
|
||||
*/
|
||||
static inline int qSafeFloatToQ16Dot16(qreal x)
|
||||
{
|
||||
qreal tmp = x * 65536.;
|
||||
if (tmp > qreal(INT_MAX))
|
||||
return INT_MAX;
|
||||
else if (tmp < qreal(INT_MIN))
|
||||
return -INT_MAX;
|
||||
return int(tmp);
|
||||
}
|
||||
|
||||
void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width, bool squareCap)
|
||||
{
|
||||
if (a == b || width == 0 || d->clipRect.isEmpty())
|
||||
|
|
@ -946,23 +975,23 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
const QPointF bottomLeftEdge = bottom - left;
|
||||
const QPointF bottomRightEdge = bottom - right;
|
||||
|
||||
const qreal topLeftSlope = topLeftEdge.x() / topLeftEdge.y();
|
||||
const qreal bottomLeftSlope = bottomLeftEdge.x() / bottomLeftEdge.y();
|
||||
const qreal topLeftSlope = qSafeDivide(topLeftEdge.x(), topLeftEdge.y());
|
||||
const qreal bottomLeftSlope = qSafeDivide(bottomLeftEdge.x(), bottomLeftEdge.y());
|
||||
|
||||
const qreal topRightSlope = topRightEdge.x() / topRightEdge.y();
|
||||
const qreal bottomRightSlope = bottomRightEdge.x() / bottomRightEdge.y();
|
||||
const qreal topRightSlope = qSafeDivide(topRightEdge.x(), topRightEdge.y());
|
||||
const qreal bottomRightSlope = qSafeDivide(bottomRightEdge.x(), bottomRightEdge.y());
|
||||
|
||||
const Q16Dot16 topLeftSlopeFP = FloatToQ16Dot16(topLeftSlope);
|
||||
const Q16Dot16 topRightSlopeFP = FloatToQ16Dot16(topRightSlope);
|
||||
const Q16Dot16 topLeftSlopeFP = qSafeFloatToQ16Dot16(topLeftSlope);
|
||||
const Q16Dot16 topRightSlopeFP = qSafeFloatToQ16Dot16(topRightSlope);
|
||||
|
||||
const Q16Dot16 bottomLeftSlopeFP = FloatToQ16Dot16(bottomLeftSlope);
|
||||
const Q16Dot16 bottomRightSlopeFP = FloatToQ16Dot16(bottomRightSlope);
|
||||
const Q16Dot16 bottomLeftSlopeFP = qSafeFloatToQ16Dot16(bottomLeftSlope);
|
||||
const Q16Dot16 bottomRightSlopeFP = qSafeFloatToQ16Dot16(bottomRightSlope);
|
||||
|
||||
const Q16Dot16 invTopLeftSlopeFP = FloatToQ16Dot16(1 / topLeftSlope);
|
||||
const Q16Dot16 invTopRightSlopeFP = FloatToQ16Dot16(1 / topRightSlope);
|
||||
const Q16Dot16 invTopLeftSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, topLeftSlope));
|
||||
const Q16Dot16 invTopRightSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, topRightSlope));
|
||||
|
||||
const Q16Dot16 invBottomLeftSlopeFP = FloatToQ16Dot16(1 / bottomLeftSlope);
|
||||
const Q16Dot16 invBottomRightSlopeFP = FloatToQ16Dot16(1 / bottomRightSlope);
|
||||
const Q16Dot16 invBottomLeftSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, bottomLeftSlope));
|
||||
const Q16Dot16 invBottomRightSlopeFP = qSafeFloatToQ16Dot16(qSafeDivide(1, bottomRightSlope));
|
||||
|
||||
if (d->antialiased) {
|
||||
const Q16Dot16 iTopFP = IntToQ16Dot16(int(topBound));
|
||||
|
|
@ -1137,10 +1166,10 @@ void QRasterizer::rasterizeLine(const QPointF &a, const QPointF &b, qreal width,
|
|||
int iBottom = bottom.y() < 0.5f? -1 : int(bottom.y() - 0.5f);
|
||||
int iMiddle = qMin(iLeft, iRight);
|
||||
|
||||
Q16Dot16 leftIntersectAf = FloatToQ16Dot16(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope);
|
||||
Q16Dot16 leftIntersectBf = FloatToQ16Dot16(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope);
|
||||
Q16Dot16 rightIntersectAf = FloatToQ16Dot16(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope);
|
||||
Q16Dot16 rightIntersectBf = FloatToQ16Dot16(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope);
|
||||
Q16Dot16 leftIntersectAf = qSafeFloatToQ16Dot16(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope);
|
||||
Q16Dot16 leftIntersectBf = qSafeFloatToQ16Dot16(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope);
|
||||
Q16Dot16 rightIntersectAf = qSafeFloatToQ16Dot16(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope);
|
||||
Q16Dot16 rightIntersectBf = qSafeFloatToQ16Dot16(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope);
|
||||
|
||||
int ny;
|
||||
int y = iTop;
|
||||
|
|
|
|||
Loading…
Reference in New Issue