diff options
author | Shawn Rutledge <shawn.rutledge@qt.io> | 2023-09-06 17:18:42 +0200 |
---|---|---|
committer | Shawn Rutledge <shawn.rutledge@qt.io> | 2023-09-12 21:03:21 +0200 |
commit | 584cd7239020e598df088a1b4669d3e69ff4650f (patch) | |
tree | e91d743576d8dd41ad9b25b2f7358bb6472abf4b /src | |
parent | 2bee7cf744f711df3b8ab9fa3905de086bb019bb (diff) |
Loader: re-set ItemObservesViewport flag on child if already set
When QQuickLoaderPrivate::load() loads a Text item, its ctor calls
QQuickTextPrivate::init(), which calls setFlag(ItemObservesViewport).
QQuickItem::setFlag() tries to go up the parent hierarchy to get
subtreeTransformChangedEnabled turned on; but at that time, the Text
does not yet have a parent.
If a Flickable contains a Loader that loads a Text with large content,
QQuickTextPrivate::transformChanged() needs to get called during
scrolling. Loader is not interested in these notifications for itself;
so its parent's QQuickItemPrivate::transformChanged() detects that and
turns off subtreeTransformChangedEnabled. After the child is loaded,
QQuickLoader::itemChange() detects that the child's ItemObservesViewport
is already set, and sets the same flag again. setFlag() doesn't have a
guard, so the parent traversal happens again, and
subtreeTransformChangedEnabled gets turned back on.
If a different child were loaded, and that child did not want the
notifications, the next QQuickItemPrivate::transformChanged()
would detect it. If the child changed its own flag later on (e.g.
because a small amount of text was replaced with a larger document,
exceeding QQUICKTEXT_LARGETEXT_THRESHOLD), QQuickItem::setFlag() would
be able to go up the parent chain at that time.
For the autotest, long.qml has about 15KB of text. Maybe it will
be reusable. At least it should compress well in git packfiles,
since we have this license text elsewhere.
Fixes: QTBUG-115687
Change-Id: I87b6a42f5735b8f9c2267f91a4112681da05de5d
Reviewed-by: Santhosh Kumar <santhosh.kumar.selvaraj@qt.io>
(cherry picked from commit 8c7c60fff37ea7bb7420d925e2f88e62764bf86b)
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/quick/items/qquickitem.cpp | 2 | ||||
-rw-r--r-- | src/quick/items/qquickloader.cpp | 13 |
2 files changed, 14 insertions, 1 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 4c638e51f7..53276f6c49 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -6972,6 +6972,8 @@ void QQuickItem::setFlag(Flag flag, bool enabled) else setFlags((Flags)(d->flags & ~(quint32)flag)); + // We don't return early if the flag did not change. That's useful in case + // we need to intentionally trigger this parent-chain traversal again. if (enabled && flag == ItemObservesViewport) { QQuickItem *par = parentItem(); while (par) { diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index fdee5d0b35..dad2e5a8a7 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -804,12 +804,23 @@ void QQuickLoader::componentComplete() void QQuickLoader::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) { - if (change == ItemSceneChange) { + switch (change) { + case ItemSceneChange: { QQuickWindow *loadedWindow = qmlobject_cast<QQuickWindow *>(item()); if (loadedWindow) { qCDebug(lcTransient) << loadedWindow << "is transient for" << value.window; loadedWindow->setTransientParent(value.window); } + break; + } + case ItemChildAddedChange: + Q_ASSERT(value.item); + if (value.item->flags().testFlag(QQuickItem::ItemObservesViewport)) + // Re-trigger the parent traversal to get subtreeTransformChangedEnabled turned on + value.item->setFlag(QQuickItem::ItemObservesViewport); + break; + default: + break; } QQuickItem::itemChange(change, value); } |