aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKwanghyo Park <kwanghyo.park@qt.io>2026-09-09 07:11:07 +0300
committerKwanghyo Park <kwanghyo.park@qt.io>2026-09-14 14:27:25 +0000
commitbd44240ab368f094860b8327673add261510dacc (patch)
tree0a63c250ebe34bef77371ddb8e06f5bdd59c3426
parent72baa4b0ad665aba4d527241ddbf305a070fe907 (diff)
quickvectorimage: honor bounds references in the item generator
A node can state its bounds as a reference to another node rather than as a rectangle of its own, but the item generator only read the rectangle. Resolve the reference against the bounds the referenced node was given. Task-number: QTBUG-147743 Change-Id: I943fc4df2a356e9d9764e6eb770f9d95478f8cc3 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
-rw-r--r--src/quickvectorimage/generator/qquickitemgenerator.cpp47
-rw-r--r--src/quickvectorimage/generator/qquickitemgenerator_p.h4
2 files changed, 41 insertions, 10 deletions
diff --git a/src/quickvectorimage/generator/qquickitemgenerator.cpp b/src/quickvectorimage/generator/qquickitemgenerator.cpp
index 6c5b84d5c5..a06a4a3c20 100644
--- a/src/quickvectorimage/generator/qquickitemgenerator.cpp
+++ b/src/quickvectorimage/generator/qquickitemgenerator.cpp
@@ -204,10 +204,27 @@ QQuickItem *QQuickItemGenerator::currentItem() const
return m_itemStack.isEmpty() ? nullptr : m_itemStack.top();
}
-QString QQuickItemGenerator::generateNodeBase(const NodeInfo &info, const QString &idSuffix)
+QRectF QQuickItemGenerator::resolveBounds(const NodeInfo &info) const
{
- Q_UNUSED(idSuffix)
+ if (!info.bounds.isNull())
+ return info.bounds;
+
+ if (info.boundsReferenceId.isEmpty())
+ return {};
+ return m_bounds.value(info.boundsReferenceId);
+}
+
+void QQuickItemGenerator::registerBounds(const QString &id, const QRectF &bounds)
+{
+ if (id.isEmpty() || bounds.isNull())
+ return;
+
+ m_bounds.insert(id, bounds);
+}
+
+QString QQuickItemGenerator::generateNodeBase(const NodeInfo &info, const QString &idSuffix)
+{
static qint64 maxNodes =
qEnvironmentVariableIntegerValue("QT_QUICKVECTORIMAGE_MAX_NODES").value_or(10000);
if (Q_UNLIKELY(!checkSanityLimit(++m_nodeCounter, maxNodes, "nodes"_L1)))
@@ -222,9 +239,11 @@ QString QQuickItemGenerator::generateNodeBase(const NodeInfo &info, const QStrin
item->setTransformOrigin(QQuickItem::TopLeft);
- if (!info.bounds.isNull()) {
- item->setWidth(info.bounds.width());
- item->setHeight(info.bounds.height());
+ const QRectF bounds = resolveBounds(info);
+ if (!bounds.isNull()) {
+ registerBounds(info.id + idSuffix, bounds);
+ item->setWidth(bounds.width());
+ item->setHeight(bounds.height());
}
if (info.filterId.isEmpty() && info.maskId.isEmpty()) {
@@ -965,6 +984,10 @@ void QQuickItemGenerator::generateDefsInstantiationNode(const StructureNodeInfo
return;
}
+ const QRectF bounds = resolveBounds(info);
+ registerBounds(info.id, bounds);
+ registerBounds(info.defsId + "_defs"_L1, bounds);
+
const qsizetype pendingStart = m_pendingLinkedTransforms.size();
const QHash<QString, QQuickTransformSource *> outerSources = m_transformSourceItems;
@@ -1113,9 +1136,11 @@ void QQuickItemGenerator::generateMaskContainer(const MaskNodeInfo &info)
popItem();
auto *container = currentItem();
+ const bool hasBoundsReference = !info.boundsReferenceId.isEmpty();
+ const QRectF maskRect = hasBoundsReference ? resolveBounds(info) : info.maskRect;
m_maskDefs[info.id] = { container,
- info.maskRect,
- info.isMaskRectRelativeCoordinates,
+ maskRect,
+ hasBoundsReference ? false : info.isMaskRectRelativeCoordinates,
info.isMaskContentRelativeCoordinates,
transformer,
transformerMatrix };
@@ -1135,8 +1160,9 @@ void QQuickItemGenerator::generateMask(QQuickItem *item, const NodeInfo &info,
const qreal w = item->width();
const qreal h = item->height();
+ const QRectF resolvedBounds = resolveBounds(info);
const QRectF svgBounds =
- info.bounds.isNull() ? QRectF(item->x(), item->y(), w, h) : info.bounds;
+ resolvedBounds.isNull() ? QRectF(item->x(), item->y(), w, h) : resolvedBounds;
QRectF svgMaskRect;
if (maskDef.isMaskRectRelativeCoordinates) {
svgMaskRect = QRectF(maskDef.maskRect.x() * svgBounds.width() + svgBounds.x(),
@@ -1256,9 +1282,10 @@ QQuickItem *QQuickItemGenerator::generateFilter(QQuickItem *item, const NodeInfo
return nullptr;
QQuickItem *parentItem = item->parentItem();
- const QRectF itemBounds = info.bounds.isNull()
+ const QRectF resolvedBounds = resolveBounds(info);
+ const QRectF itemBounds = resolvedBounds.isNull()
? QRectF(item->x(), item->y(), item->width(), item->height())
- : info.bounds;
+ : resolvedBounds;
QRectF filterRect = resolveRect(filterInfo.filterRect, filterInfo.csFilterRect, itemBounds);
if (filterRect.isEmpty())
diff --git a/src/quickvectorimage/generator/qquickitemgenerator_p.h b/src/quickvectorimage/generator/qquickitemgenerator_p.h
index 05bb169a82..6dc90d0609 100644
--- a/src/quickvectorimage/generator/qquickitemgenerator_p.h
+++ b/src/quickvectorimage/generator/qquickitemgenerator_p.h
@@ -120,6 +120,7 @@ private:
QHash<QString, PatternDef> m_patternDefs;
QHash<QString, MarkerDef> m_markerDefs;
QHash<QString, FilterNodeInfo> m_filterDefs;
+ QHash<QString, QRectF> m_bounds;
QQuickItemSpy *m_topLevelScaleSpy = nullptr;
QHash<QString, QQuickTransformSource *> m_transformSourceItems;
@@ -128,6 +129,9 @@ private:
QStack<bool> m_scopePushed;
QMap<std::array<qreal, 4>, QEasingCurve> m_easingCache;
+ QRectF resolveBounds(const NodeInfo &info) const;
+ void registerBounds(const QString &id, const QRectF &bounds);
+
void beginDefsRecord(const QString &id);
void endDefsRecord();
void replayDefsRecord(const QString &id);