avoid processing-intensive painting of high number of tiny dashes
authorDebian Qt/KDE Maintainers <debian-qt-kde@lists.debian.org>
Sun, 7 Aug 2022 13:56:40 +0000 (14:56 +0100)
committerDmitry Shachnev <mitya57@debian.org>
Sun, 7 Aug 2022 13:56:40 +0000 (14:56 +0100)
Origin: upstream, commits:
 https://code.qt.io/cgit/qt/qtbase.git/commit/?id=f4d791b330d02777
 https://code.qt.io/cgit/qt/qtbase.git/commit/?id=6b400e3147dcfd8c
 https://code.qt.io/cgit/qt/qtbase.git/commit/?id=84aba80944a2e1c3
 https://code.qt.io/cgit/qt/qtbase.git/commit/?id=cca8ed0547405b1c
Last-Update: 2021-11-27

When stroking a dashed path, an unnecessary amount of processing would
be spent if there is a huge number of dashes visible, e.g. because of
scaling. Since the dashes are too small to be individually visible
anyway, just replace with a semi-transparent solid line for such
cases.

Gbp-Pq: Name CVE-2021-38593.diff

src/gui/painting/qpaintengineex.cpp

index 5d8f89eaddb9297c43047c6c2ceb25556748ddb0..a7d2e7a94840f4383c494f85fe78b6cf96eb9050 100644 (file)
@@ -385,10 +385,10 @@ QPainterState *QPaintEngineEx::createState(QPainterState *orig) const
 
 Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
 
-void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
+void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen)
 {
 #ifdef QT_DEBUG_DRAW
-    qDebug() << "QPaintEngineEx::stroke()" << pen;
+    qDebug() << "QPaintEngineEx::stroke()" << inPen;
 #endif
 
     Q_D(QPaintEngineEx);
@@ -403,6 +403,38 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
         d->stroker.setCubicToHook(qpaintengineex_cubicTo);
     }
 
+    QRectF clipRect;
+    QPen pen = inPen;
+    if (pen.style() > Qt::SolidLine) {
+        QRectF cpRect = path.controlPointRect();
+        const QTransform &xf = state()->matrix;
+        if (qt_pen_is_cosmetic(pen, state()->renderHints)) {
+            clipRect = d->exDeviceRect;
+            cpRect.translate(xf.dx(), xf.dy());
+        } else {
+            clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect));
+        }
+        // Check to avoid generating unwieldy amount of dashes that will not be visible anyway
+        qreal pw = pen.widthF() ? pen.widthF() : 1;
+        QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
+        qreal extent = qMax(extentRect.width(), extentRect.height());
+        qreal patternLength = 0;
+        const QVector<qreal> pattern = pen.dashPattern();
+        const int patternSize = qMin(pattern.size(), 32);
+        for (int i = 0; i < patternSize; i++)
+            patternLength += qMax(pattern.at(i), qreal(0));
+        patternLength *= pw;
+        if (qFuzzyIsNull(patternLength)) {
+            pen.setStyle(Qt::NoPen);
+        } else if (extent / patternLength > 10000) {
+            // approximate stream of tiny dashes with semi-transparent solid line
+            pen.setStyle(Qt::SolidLine);
+            QColor color(pen.color());
+            color.setAlpha(color.alpha() / 2);
+            pen.setColor(color);
+        }
+    }
+
     if (!qpen_fast_equals(pen, d->strokerPen)) {
         d->strokerPen = pen;
         d->stroker.setJoinStyle(pen.joinStyle());
@@ -430,14 +462,8 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
         return;
     }
 
-    if (pen.style() > Qt::SolidLine) {
-        if (qt_pen_is_cosmetic(pen, state()->renderHints)){
-            d->activeStroker->setClipRect(d->exDeviceRect);
-        } else {
-            QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect));
-            d->activeStroker->setClipRect(clipRect);
-        }
-    }
+    if (!clipRect.isNull())
+        d->activeStroker->setClipRect(clipRect);
 
     if (d->activeStroker == &d->stroker)
         d->stroker.setForceOpen(path.hasExplicitOpen());