aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Olav Tvete <paul.tvete@qt.io>2023-11-23 13:00:42 +0100
committerPaul Olav Tvete <paul.tvete@qt.io>2024-01-23 11:23:22 +0000
commitbdebe5bc14cce7f3045d829ab7e83d42f5cb0144 (patch)
treefa1b9947f8890969dec1a70a340fb19b3eda5132 /src
parenteb54a004799e39c8e06449c4851a988f273cd0db (diff)
Preprocess paths in svgtoqml
Add --optimize-paths option to do expensive path manipulation at build time instead of at runtime. This may cause the generation of separate fill and stroke versions of the same source path. Task-number: QTBUG-116883 Task-number: QTBUG-121203 Pick-to: 6.7 Change-Id: Iacda16d8dbddf5b8219c290fac473d78c073576e Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/quick/scenegraph/qsgcurveprocessor.cpp38
-rw-r--r--src/quick/scenegraph/qsgcurveprocessor_p.h2
-rw-r--r--src/quick/scenegraph/util/qquadpath.cpp8
-rw-r--r--src/quick/scenegraph/util/qquadpath_p.h2
4 files changed, 32 insertions, 18 deletions
diff --git a/src/quick/scenegraph/qsgcurveprocessor.cpp b/src/quick/scenegraph/qsgcurveprocessor.cpp
index f5a13ef48d..f4ba4c6905 100644
--- a/src/quick/scenegraph/qsgcurveprocessor.cpp
+++ b/src/quick/scenegraph/qsgcurveprocessor.cpp
@@ -811,15 +811,16 @@ static QList<TriangleData> customTriangulator2(const QQuadPath &path, float penW
// TODO: we could optimize by preprocessing e1, since we call this function multiple times on the same
// elements
-static void handleOverlap(QQuadPath &path, int e1, int e2, int recursionLevel = 0)
+// Returns true if a change was made
+static bool handleOverlap(QQuadPath &path, int e1, int e2, int recursionLevel = 0)
{
if (!isOverlap(path, e1, e2)) {
- return;
+ return false;
}
if (recursionLevel > 8) {
qCDebug(lcSGCurveProcessor) << "Triangle overlap: recursion level" << recursionLevel << "aborting!";
- return;
+ return false;
}
if (path.elementAt(e1).childCount() > 1) {
@@ -839,7 +840,7 @@ static void handleOverlap(QQuadPath &path, int e1, int e2, int recursionLevel =
bool overlap1 = isOverlap(path, e11, e2);
bool overlap2 = isOverlap(path, e12, e2);
if (!overlap1 && !overlap2)
- return; // no more overlap: success!
+ return true; // no more overlap: success!
// We need to split more:
if (path.elementAt(e2).isLine()) {
@@ -863,33 +864,41 @@ static void handleOverlap(QQuadPath &path, int e1, int e2, int recursionLevel =
}
}
}
+ return true;
}
// Test if element contains a start point of another element
-static void handleOverlap(QQuadPath &path, int e1, const QVector2D vertex, int recursionLevel = 0)
+// Returns true if a change was made
+static bool handleOverlap(QQuadPath &path, int e1, const QVector2D vertex, int recursionLevel = 0)
{
// First of all: Ignore the next element: it trivially overlaps (maybe not necessary: we do check for strict containment)
if (vertex == path.elementAt(e1).endPoint() || !isOverlap(path, e1, vertex))
- return;
+ return false;
if (recursionLevel > 8) {
qCDebug(lcSGCurveIntersectionSolver) << "Vertex overlap: recursion level" << recursionLevel << "aborting!";
- return;
+ return false;
}
+ bool changed = false;
// Don't split if we're already split
- if (path.elementAt(e1).childCount() == 0)
+ if (path.elementAt(e1).childCount() == 0) {
path.splitElementAt(e1);
+ changed = true;
+ }
- handleOverlap(path, path.indexOfChildAt(e1, 0), vertex, recursionLevel + 1);
- handleOverlap(path, path.indexOfChildAt(e1, 1), vertex, recursionLevel + 1);
+ changed = handleOverlap(path, path.indexOfChildAt(e1, 0), vertex, recursionLevel + 1) || changed; // variable at the end to avoid accidentally short-cutting out the call
+ changed = handleOverlap(path, path.indexOfChildAt(e1, 1), vertex, recursionLevel + 1) || changed;
+ return changed;
}
}
-void QSGCurveProcessor::solveOverlaps(QQuadPath &path, OverlapSolveMode mode)
+// Returns true if the path was changed
+bool QSGCurveProcessor::solveOverlaps(QQuadPath &path, OverlapSolveMode mode)
{
+ bool changed = false;
if (path.testHint(QQuadPath::PathNonOverlappingControlPointTriangles))
- return;
+ return false;
for (int i = 0; i < path.elementCount(); i++) {
auto &element = path.elementAt(i);
// only concave curve overlap is problematic, as long as we don't allow self-intersecting curves
@@ -902,7 +911,7 @@ void QSGCurveProcessor::solveOverlaps(QQuadPath &path, OverlapSolveMode mode)
auto &other = path.elementAt(j);
if (!other.isConvex() && !other.isLine() && j < i)
continue; // We have already tested this combination, so no need to test again
- handleOverlap(path, i, j);
+ changed = handleOverlap(path, i, j) || changed;
}
}
@@ -926,11 +935,12 @@ void QSGCurveProcessor::solveOverlaps(QQuadPath &path, OverlapSolveMode mode)
if (i == j)
continue;
const auto &other = path.elementAt(j);
- handleOverlap(path, i, other.startPoint());
+ changed = handleOverlap(path, i, other.startPoint()) || changed;
}
}
}
path.setHint(QQuadPath::PathNonOverlappingControlPointTriangles);
+ return changed;
}
// A fast algorithm to find path elements that might overlap. We will only check the overlap of the
diff --git a/src/quick/scenegraph/qsgcurveprocessor_p.h b/src/quick/scenegraph/qsgcurveprocessor_p.h
index 18e08dcbae..b1059757a5 100644
--- a/src/quick/scenegraph/qsgcurveprocessor_p.h
+++ b/src/quick/scenegraph/qsgcurveprocessor_p.h
@@ -44,7 +44,7 @@ public:
Qt::PenCapStyle capStyle,
addStrokeTriangleCallback addTriangle,
int subdivisions = 3);
- static void solveOverlaps(QQuadPath &path, OverlapSolveMode mode = SkipConcaveJoinsSolve);
+ static bool solveOverlaps(QQuadPath &path, OverlapSolveMode mode = SkipConcaveJoinsSolve);
static QList<QPair<int, int>> findOverlappingCandidates(const QQuadPath &path);
static bool solveIntersections(QQuadPath &path, bool alwaysReorder = true);
};
diff --git a/src/quick/scenegraph/util/qquadpath.cpp b/src/quick/scenegraph/util/qquadpath.cpp
index 7af89d4bca..eff2508d8f 100644
--- a/src/quick/scenegraph/util/qquadpath.cpp
+++ b/src/quick/scenegraph/util/qquadpath.cpp
@@ -640,10 +640,10 @@ QString QQuadPath::asSvgString() const
// (technically changing it from O(n) to O(n^2))
// Note that this function should be called before splitting any elements,
// so we can assume that the structure is a list and not a tree
-QQuadPath QQuadPath::subPathsClosed() const
+QQuadPath QQuadPath::subPathsClosed(bool *didClose) const
{
Q_ASSERT(m_childElements.isEmpty());
-
+ bool closed = false;
QQuadPath res = *this;
res.m_elements = {};
res.m_elements.reserve(elementCount());
@@ -655,6 +655,7 @@ QQuadPath QQuadPath::subPathsClosed() const
if (subStart >= 0 && m_elements[i - 1].ep != m_elements[subStart].sp) {
res.currentPoint = m_elements[i - 1].ep;
res.lineTo(m_elements[subStart].sp);
+ closed = true;
auto &endElement = res.m_elements.last();
endElement.m_isSubpathEnd = true;
// lineTo() can bail out if the points are too close.
@@ -673,6 +674,7 @@ QQuadPath QQuadPath::subPathsClosed() const
if (subStart >= 0 && m_elements.last().ep != m_elements[subStart].sp) {
res.currentPoint = m_elements.last().ep;
res.lineTo(m_elements[subStart].sp);
+ closed = true;
}
if (!res.m_elements.isEmpty()) {
auto &endElement = res.m_elements.last();
@@ -687,6 +689,8 @@ QQuadPath QQuadPath::subPathsClosed() const
Q_ASSERT(res.elementCount() == 4);
}
+ if (didClose)
+ *didClose = closed;
return res;
}
diff --git a/src/quick/scenegraph/util/qquadpath_p.h b/src/quick/scenegraph/util/qquadpath_p.h
index 8bd389ecbe..ba0c017fd3 100644
--- a/src/quick/scenegraph/util/qquadpath_p.h
+++ b/src/quick/scenegraph/util/qquadpath_p.h
@@ -230,7 +230,7 @@ public:
QPainterPath toPainterPath() const;
QString asSvgString() const;
- QQuadPath subPathsClosed() const;
+ QQuadPath subPathsClosed(bool *didClose = nullptr) const;
void addCurvatureData();
QQuadPath flattened() const;
QQuadPath dashed(qreal lineWidth, const QList<qreal> &dashPattern, qreal dashOffset = 0) const;