# UNDF: UNDF-2026-000000803 # UNDF: (leave blank) # scribus-0002: getUsedPatterns results.contains O(I×R) pattern collection # # In scribus/scribusdoc.cpp, getUsedPatterns() iterates over all page items # and for each checks results.contains(pattern) — a QStringList linear scan # O(R) where R is the number of results accumulated so far. With I page items # each potentially contributing 3 pattern names (fill, stroke, mask), the # overall complexity is O(3×I×R). For a document with 2000 items and 200 # patterns, that is ~1.2M string comparisons. # # The same pattern repeats in getUsedPatternsSelection() and # getUsedPatternsHelper() and getPatternDependencyList(). # # Fix: maintain a companion QSet for O(1) membership alongside the # QStringList for ordered results. # # Severity: MEDIUM — triggered during document save, export, and pattern # cleanup; scales with item count × pattern count. --- a/scribus/scribusdoc.cpp +++ b/scribus/scribusdoc.cpp @@ -3933,6 +3933,7 @@ QStringList ScribusDoc::getUsedPatterns() const { QStringList results; + QSet resultSet; for (PageItemIterator it(this, ...); *it; ++it) { const PageItem* currItem = *it; - if ((!results.contains(currItem->pattern())) && ...) + if ((!resultSet.contains(currItem->pattern())) && ...) + { results.append(currItem->pattern()); + resultSet.insert(currItem->pattern()); + } if (!currItem->strokePattern().isEmpty()) { - if (!results.contains(currItem->strokePattern())) + if (!resultSet.contains(currItem->strokePattern())) + { results.append(currItem->strokePattern()); + resultSet.insert(currItem->strokePattern()); + } } if (!currItem->patternMask().isEmpty()) { - if (!results.contains(currItem->patternMask())) + if (!resultSet.contains(currItem->patternMask())) + { results.append(currItem->patternMask()); + resultSet.insert(currItem->patternMask()); + } } } // Same fix for the inner docPatterns loop (lines 3955-3983) - // Replace results.contains(...) with resultSet.contains(...) + // and add resultSet.insert(...) after each results.append(...) return results; } // Same fix applies to: // getUsedPatternsSelection() (line 3988) // getUsedPatternsHelper() (line 4036) // getPatternDependencyList() (line 4087)