diff options
| author | Paul Olav Tvete <paul.tvete@qt.io> | 2023-11-23 13:00:42 +0100 |
|---|---|---|
| committer | Paul Olav Tvete <paul.tvete@qt.io> | 2024-01-23 11:23:22 +0000 |
| commit | bdebe5bc14cce7f3045d829ab7e83d42f5cb0144 (patch) | |
| tree | fa1b9947f8890969dec1a70a340fb19b3eda5132 /src | |
| parent | eb54a004799e39c8e06449c4851a988f273cd0db (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.cpp | 38 | ||||
| -rw-r--r-- | src/quick/scenegraph/qsgcurveprocessor_p.h | 2 | ||||
| -rw-r--r-- | src/quick/scenegraph/util/qquadpath.cpp | 8 | ||||
| -rw-r--r-- | src/quick/scenegraph/util/qquadpath_p.h | 2 |
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; |
