summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEirik Aavitsland <[email protected]>2021-08-17 13:50:50 +0200
committerEirik Aavitsland <[email protected]>2021-08-24 08:49:36 +0200
commit279a434c1c8689f00b1ab8ed571f8732a803a7eb (patch)
tree6db158f0f30616b13edb3f3ec59088f140b390c3
parentcf34fca4d078acee56781540ac98b34bb790554e (diff)
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 <[email protected]> Reviewed-by: Allan Sandfeld Jensen <[email protected]>
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp5
-rw-r--r--src/gui/painting/qpaintengineex.cpp2
-rw-r--r--src/gui/painting/qstroker.cpp55
-rw-r--r--src/gui/painting/qstroker_p.h1
4 files changed, 39 insertions, 24 deletions
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 5ac1f748e5b..70fce7d253d 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -3265,6 +3265,11 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
qreal length = line.length();
Q_ASSERT(length > 0);
+ if (length / (patternLength * width) > QDashStroker::repetitionLimit()) {
+ rasterizer->rasterizeLine(line.p1(), line.p2(), width / length, squareCap);
+ return;
+ }
+
while (length > 0) {
const bool rasterize = *inDash;
qreal dash = (pattern.at(*dashIndex) - *dashOffset) * width;
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index d85c2a951c8..9ca3de5cf29 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -426,7 +426,7 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
patternLength *= pw;
if (qFuzzyIsNull(patternLength)) {
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
pen.setStyle(Qt::SolidLine);
QColor color(pen.color());
diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp
index cd1a49150be..79194c7cf81 100644
--- a/src/gui/painting/qstroker.cpp
+++ b/src/gui/painting/qstroker.cpp
@@ -1179,32 +1179,41 @@ void QDashStroker::processCurrentSubpath()
bool done = pos >= estop;
- if (clipping) {
- // Check if the entire line can be clipped away.
- if (!lineIntersectsRect(prev, e, clip_tl, clip_br)) {
- // Cut away full dash sequences.
- elen -= qFloor(elen * invSumLength) * sumLength;
- // Update dash offset.
- while (!done) {
- qreal dpos = pos + dashes[idash] - doffset - estart;
-
- Q_ASSERT(dpos >= 0);
-
- if (dpos > elen) { // dash extends this line
- doffset = dashes[idash] - (dpos - elen); // subtract the part already used
- pos = estop; // move pos to next path element
- done = true;
- } else { // Dash is on this line
- pos = dpos + estart;
- done = pos >= estop;
- if (++idash >= dashCount)
- idash = 0;
- doffset = 0; // full segment so no offset on next.
- }
+ // Check if the entire line should be clipped away or simplified
+ bool clipIt = clipping && !lineIntersectsRect(prev, e, clip_tl, clip_br);
+ bool skipDashing = elen * invSumLength > repetitionLimit();
+ if (skipDashing || clipIt) {
+ // Cut away full dash sequences.
+ elen -= std::floor(elen * invSumLength) * sumLength;
+ // Update dash offset.
+ while (!done) {
+ qreal dpos = pos + dashes[idash] - doffset - estart;
+
+ Q_ASSERT(dpos >= 0);
+
+ if (dpos > elen) { // dash extends this line
+ doffset = dashes[idash] - (dpos - elen); // subtract the part already used
+ pos = estop; // move pos to next path element
+ done = true;
+ } else { // Dash is on this line
+ pos = dpos + estart;
+ done = pos >= estop;
+ if (++idash >= dashCount)
+ idash = 0;
+ doffset = 0; // full segment so no offset on next.
}
+ }
+ if (clipIt) {
hasMoveTo = false;
- move_to_pos = e;
+ } 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...
diff --git a/src/gui/painting/qstroker_p.h b/src/gui/painting/qstroker_p.h
index eb0e5d7ffac..0934ef5df79 100644
--- a/src/gui/painting/qstroker_p.h
+++ b/src/gui/painting/qstroker_p.h
@@ -268,6 +268,7 @@ public:
QStroker *stroker() const { return m_stroker; }
static QList<qfixed> patternForStyle(Qt::PenStyle style);
+ static int repetitionLimit() { return 10000; }
void setDashPattern(const QList<qfixed> &dashPattern) { m_dashPattern = dashPattern; }
QList<qfixed> dashPattern() const { return m_dashPattern; }