hc
2023-02-13 e440ec23c5a540cdd3f7464e8779219be6fd3d95
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
From 93ac853387996cdb5dd44d3db02a0fd7f58e7e57 Mon Sep 17 00:00:00 2001
From: Eirik Aavitsland <eirik.aavitsland@qt.io>
Date: Tue, 13 Apr 2021 14:23:45 +0200
Subject: [PATCH 10/31] Avoid processing-intensive painting of high number of
 tiny dashes
 
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 indivdually visible
anyway, just replace with a semi-transparent solid line for such
cases.
 
Pick-to: 6.1 6.0 5.15
Change-Id: I9e9f7861257ad5bce46a0cf113d1a9d7824911e6
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
(cherry picked from commit f4d791b330d02777fcaf02938732892eb3167e9b)
 
* asturmlechner 2021-08-21:
Conflict from preceding 94dd2ceb in dev branch:
   src/gui/painting/qpaintengineex.cpp
   Resolved via:
 
     if (pen.style() > Qt::SolidLine) {
         QRectF cpRect = path.controlPointRect();
         const QTransform &xf = state()->matrix;
-        if (pen.isCosmetic()) {
+        if (qt_pen_is_cosmetic(pen, state()->renderHints)){
             clipRect = d->exDeviceRect;
             cpRect.translate(xf.dx(), xf.dy());
         } else {
 
FTBFS from preceding 471e4fcb in dev branch changing QVector to QList:
   Resolved via:
 
         QRectF extentRect = cpRect.adjusted(-pw, -pw, pw, pw) & clipRect;
         qreal extent = qMax(extentRect.width(), extentRect.height());
         qreal patternLength = 0;
-        const QList<qreal> pattern = pen.dashPattern();
+        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));
 
[Retrieved from: https://invent.kde.org/qt/qt/qtbase/-/commit/081d835c040a90f8ee76807354355062ac521dfb]
Signed-off-by: Quentin Schulz <quentin.schulz@theobroma-systems.com>
---
 src/gui/painting/qpaintengineex.cpp           | 44 +++++++++++++++----
 .../other/lancelot/scripts/tinydashes.qps     | 34 ++++++++++++++
 2 files changed, 69 insertions(+), 9 deletions(-)
 create mode 100644 tests/auto/other/lancelot/scripts/tinydashes.qps
 
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 5d8f89ea..55fdb0c2 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -385,7 +385,7 @@ 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;
@@ -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
+        QRectF extentRect = cpRect & 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));
+        if (pen.widthF())
+            patternLength *= pen.widthF();
+        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());
diff --git a/tests/auto/other/lancelot/scripts/tinydashes.qps b/tests/auto/other/lancelot/scripts/tinydashes.qps
new file mode 100644
index 00000000..d41ced7f
--- /dev/null
+++ b/tests/auto/other/lancelot/scripts/tinydashes.qps
@@ -0,0 +1,34 @@
+# Version: 1
+# CheckVsReference: 5%
+
+path_addEllipse mypath 20.0 20.0 200.0 200.0
+
+save
+setPen blue 20 SolidLine FlatCap
+pen_setCosmetic true
+pen_setDashPattern [ 0.0004 0.0004 ]
+setBrush yellow
+
+drawPath mypath
+translate 300 0
+setRenderHint Antialiasing true
+drawPath mypath
+restore
+
+path_addEllipse bigpath 200000.0 200000.0 2000000.0 2000000.0
+
+setPen blue 20 DotLine FlatCap
+setBrush yellow
+
+save
+translate 0 300
+scale 0.0001 0.00011
+drawPath bigpath
+restore
+
+save
+translate 300 300
+setRenderHint Antialiasing true
+scale 0.0001 0.00011
+drawPath bigpath
+restore
-- 
2.20.1