Fix crash in font distancefield computation

If setting a larger-than-default distance field base font size
(renderTypeQuality in qml), an exceptionally large glyph could cause
integer overflows in the distance filed computation, causing asserts
or crashes.
Change the computation types to avoid the overflow.

This improves on b6f962c87f5084eaf962bfb033b1398f80475120.

Fixes: QTBUG-124310
Pick-to: 6.7 6.5 6.2 5.15
Change-Id: I48b7dc3c0a0f35859d45c40d03498ac057e9fa70
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
(cherry picked from commit 30a753944300c13e96f9239a9891cbc8e2e378c1)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Eirik Aavitsland 2024-08-12 10:55:25 +02:00 committed by Qt Cherry-pick Bot
parent 65a1e71700
commit 940ba11f8c

View File

@ -130,11 +130,15 @@ QPoint IntersectionPoint::round() const
// Return positive value if 'p' is to the right of the line 'v1'->'v2', negative if left of the
// line and zero if exactly on the line.
// The returned value is the z-component of the qCross product between 'v2-v1' and 'p-v1',
// which is twice the signed area of the triangle 'p'->'v1'->'v2' (positive for CW order).
inline int pointDistanceFromLine(const QPoint &p, const QPoint &v1, const QPoint &v2)
// The returned value is the sign of the cross product between 'v2-v1' and 'p-v1'.
inline int pointSideOfLine(const QPoint &p, const QPoint &v1, const QPoint &v2)
{
return cross(v2 - v1, p - v1);
qint64 ux = qint64(v2.x()) - v1.x();
qint64 uy = qint64(v2.y()) - v1.y();
qint64 vx = qint64(p.x()) - v1.x();
qint64 vy = qint64(p.y()) - v1.y();
qint64 c = (ux * vy) - (uy * vx);
return (c > 0) ? 1 : (c < 0) ? -1 : 0;
}
IntersectionPoint intersectionPoint(const QPoint &u1, const QPoint &u2,
@ -1399,19 +1403,19 @@ bool PathSimplifier::elementIsLeftOf(const Element *left, const Element *right)
return true;
if (leftU.x() > qMax(rightL.x(), rightU.x()))
return false;
int d = pointDistanceFromLine(leftU, rightL, rightU);
int d = pointSideOfLine(leftU, rightL, rightU);
// d < 0: left, d > 0: right, d == 0: on top
if (d == 0) {
d = pointDistanceFromLine(leftL, rightL, rightU);
d = pointSideOfLine(leftL, rightL, rightU);
if (d == 0) {
if (right->degree > Element::Line) {
d = pointDistanceFromLine(leftL, rightL, m_points->at(right->indices[1]));
d = pointSideOfLine(leftL, rightL, m_points->at(right->indices[1]));
if (d == 0)
d = pointDistanceFromLine(leftL, rightL, m_points->at(right->indices[2]));
d = pointSideOfLine(leftL, rightL, m_points->at(right->indices[2]));
} else if (left->degree > Element::Line) {
d = pointDistanceFromLine(m_points->at(left->indices[1]), rightL, rightU);
d = pointSideOfLine(m_points->at(left->indices[1]), rightL, rightU);
if (d == 0)
d = pointDistanceFromLine(m_points->at(left->indices[2]), rightL, rightU);
d = pointSideOfLine(m_points->at(left->indices[2]), rightL, rightU);
}
}
}
@ -1431,13 +1435,13 @@ QPair<PathSimplifier::RBNode *, PathSimplifier::RBNode *> PathSimplifier::outerB
Q_ASSERT(point >= v2 && point <= v1);
if (point == v1 || point == v2)
break;
int d = pointDistanceFromLine(point, v1, v2);
int d = pointSideOfLine(point, v1, v2);
if (d == 0) {
if (element->degree == Element::Line)
break;
d = pointDistanceFromLine(point, v1, m_points->at(element->indices[1]));
d = pointSideOfLine(point, v1, m_points->at(element->indices[1]));
if (d == 0)
d = pointDistanceFromLine(point, v1, m_points->at(element->indices[2]));
d = pointSideOfLine(point, v1, m_points->at(element->indices[2]));
Q_ASSERT(d != 0);
}
if (d < 0) {
@ -1463,7 +1467,7 @@ QPair<PathSimplifier::RBNode *, PathSimplifier::RBNode *> PathSimplifier::outerB
Q_ASSERT(point >= v2 && point <= v1);
bool equal = (point == v1 || point == v2);
if (!equal) {
int d = pointDistanceFromLine(point, v1, v2);
int d = pointSideOfLine(point, v1, v2);
Q_ASSERT(d >= 0);
equal = (d == 0 && element->degree == Element::Line);
}
@ -1484,7 +1488,7 @@ QPair<PathSimplifier::RBNode *, PathSimplifier::RBNode *> PathSimplifier::outerB
Q_ASSERT(point >= v2 && point <= v1);
bool equal = (point == v1 || point == v2);
if (!equal) {
int d = pointDistanceFromLine(point, v1, v2);
int d = pointSideOfLine(point, v1, v2);
Q_ASSERT(d <= 0);
equal = (d == 0 && element->degree == Element::Line);
}