QDashStroker: cap the number of repetitions of the pattern
Since the dashing is computed even outside the clipping and device area, painting very long dashed lines could consume unexpected amounts of time and resources. Fix by placing a limit on the dashing, and fall back to solid line drawing if hit. Fixes: QTBUG-95594 Pick-to: 6.2 6.1 5.15 Change-Id: Ida05ecd8fe6df402c9e669206fd5cec4a9f5386a Reviewed-by: Robert Löhning <robert.loehning@qt.io> Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
parent
cf34fca4d0
commit
279a434c1c
@ -3265,6 +3265,11 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
|
|||||||
|
|
||||||
qreal length = line.length();
|
qreal length = line.length();
|
||||||
Q_ASSERT(length > 0);
|
Q_ASSERT(length > 0);
|
||||||
|
if (length / (patternLength * width) > QDashStroker::repetitionLimit()) {
|
||||||
|
rasterizer->rasterizeLine(line.p1(), line.p2(), width / length, squareCap);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
const bool rasterize = *inDash;
|
const bool rasterize = *inDash;
|
||||||
qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
|
qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
|
||||||
|
@ -426,7 +426,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
|
|||||||
patternLength *= pw;
|
patternLength *= pw;
|
||||||
if (qFuzzyIsNull(patternLength)) {
|
if (qFuzzyIsNull(patternLength)) {
|
||||||
pen.setStyle(Qt::NoPen);
|
pen.setStyle(Qt::NoPen);
|
||||||
} else if (extent / patternLength > 10000) {
|
} else if (extent / patternLength > QDashStroker::repetitionLimit()) {
|
||||||
// approximate stream of tiny dashes with semi-transparent solid line
|
// approximate stream of tiny dashes with semi-transparent solid line
|
||||||
pen.setStyle(Qt::SolidLine);
|
pen.setStyle(Qt::SolidLine);
|
||||||
QColor color(pen.color());
|
QColor color(pen.color());
|
||||||
|
@ -1179,32 +1179,41 @@ void QDashStroker::processCurrentSubpath()
|
|||||||
|
|
||||||
bool done = pos >= estop;
|
bool done = pos >= estop;
|
||||||
|
|
||||||
if (clipping) {
|
// Check if the entire line should be clipped away or simplified
|
||||||
// Check if the entire line can be clipped away.
|
bool clipIt = clipping && !lineIntersectsRect(prev, e, clip_tl, clip_br);
|
||||||
if (!lineIntersectsRect(prev, e, clip_tl, clip_br)) {
|
bool skipDashing = elen * invSumLength > repetitionLimit();
|
||||||
// Cut away full dash sequences.
|
if (skipDashing || clipIt) {
|
||||||
elen -= qFloor(elen * invSumLength) * sumLength;
|
// Cut away full dash sequences.
|
||||||
// Update dash offset.
|
elen -= std::floor(elen * invSumLength) * sumLength;
|
||||||
while (!done) {
|
// Update dash offset.
|
||||||
qreal dpos = pos + dashes[idash] - doffset - estart;
|
while (!done) {
|
||||||
|
qreal dpos = pos + dashes[idash] - doffset - estart;
|
||||||
|
|
||||||
Q_ASSERT(dpos >= 0);
|
Q_ASSERT(dpos >= 0);
|
||||||
|
|
||||||
if (dpos > elen) { // dash extends this line
|
if (dpos > elen) { // dash extends this line
|
||||||
doffset = dashes[idash] - (dpos - elen); // subtract the part already used
|
doffset = dashes[idash] - (dpos - elen); // subtract the part already used
|
||||||
pos = estop; // move pos to next path element
|
pos = estop; // move pos to next path element
|
||||||
done = true;
|
done = true;
|
||||||
} else { // Dash is on this line
|
} else { // Dash is on this line
|
||||||
pos = dpos + estart;
|
pos = dpos + estart;
|
||||||
done = pos >= estop;
|
done = pos >= estop;
|
||||||
if (++idash >= dashCount)
|
if (++idash >= dashCount)
|
||||||
idash = 0;
|
idash = 0;
|
||||||
doffset = 0; // full segment so no offset on next.
|
doffset = 0; // full segment so no offset on next.
|
||||||
}
|
|
||||||
}
|
}
|
||||||
hasMoveTo = false;
|
|
||||||
move_to_pos = e;
|
|
||||||
}
|
}
|
||||||
|
if (clipIt) {
|
||||||
|
hasMoveTo = false;
|
||||||
|
} else {
|
||||||
|
// skip costly dashing, just draw solid line
|
||||||
|
if (!hasMoveTo) {
|
||||||
|
emitMoveTo(move_to_pos.x, move_to_pos.y);
|
||||||
|
hasMoveTo = true;
|
||||||
|
}
|
||||||
|
emitLineTo(e.x, e.y);
|
||||||
|
}
|
||||||
|
move_to_pos = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dash away...
|
// Dash away...
|
||||||
|
@ -268,6 +268,7 @@ public:
|
|||||||
QStroker *stroker() const { return m_stroker; }
|
QStroker *stroker() const { return m_stroker; }
|
||||||
|
|
||||||
static QList<qfixed> patternForStyle(Qt::PenStyle style);
|
static QList<qfixed> patternForStyle(Qt::PenStyle style);
|
||||||
|
static int repetitionLimit() { return 10000; }
|
||||||
|
|
||||||
void setDashPattern(const QList<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
|
void setDashPattern(const QList<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
|
||||||
QList<qfixed> dashPattern() const { return m_dashPattern; }
|
QList<qfixed> dashPattern() const { return m_dashPattern; }
|
||||||
|
Loading…
Reference in New Issue
Block a user