From 3945868670238358d8733fad71264f2a9996d3bd Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 26 Aug 2021 18:31:40 +0200 Subject: [PATCH] QmlDesigner: Render item inside the bounding rect We have to render an item inside the bounding rect, because if it is a component there might be child items outside its actual size. The way we calculate the bounding rectangle excludes children on the document level. We take clipping into account when calculating the bounding rect. When rendering the effect we do not have the instance. Therefore we fall back to the standard bounding rectangle. Change-Id: I7cd09d08d461d28c49a91fb891a5487185df0245 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../instances/qt5nodeinstanceserver.cpp | 20 +++++++-- .../instances/quickitemnodeinstance.cpp | 43 ++++++++++++++++--- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 13cdb4b9b93..aa786bac6aa 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -348,6 +348,14 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) ServerNodeInstance instance = instanceForObject(item); const auto childInstances = instance.childItems(); + // Setting layer enabled to false messes up the bounding rect. + // Therefore we calculate it upfront. + QRectF renderBoundingRect; + if (instance.isValid()) + renderBoundingRect = instance.boundingRect(); + else + renderBoundingRect = item->boundingRect(); + // Hide immediate children that have instances and are QQuickItems so we get only // the parent item's content, as compositing is handled on creator side. for (const auto &childInstance : childInstances) { @@ -372,11 +380,15 @@ QImage Qt5NodeInstanceServer::grabItem(QQuickItem *item) QSGRenderContext *rc = QQuickWindowPrivate::get(m_viewData.window.data())->context; QSGLayer *layer = rc->sceneGraphContext()->createLayer(rc); layer->setItem(pItem->itemNode()); - QSizeF itemSize = QSizeF(item->width(), item->height()); - layer->setRect(QRectF(0, itemSize.height(), itemSize.width(), -itemSize.height())); + + layer->setRect(QRectF(renderBoundingRect.x(), + renderBoundingRect.y() + renderBoundingRect.height(), + renderBoundingRect.width(), + -renderBoundingRect.height())); + const QSize minSize = rc->sceneGraphContext()->minimumFBOSize(); - layer->setSize(QSize(qMax(minSize.width(), int(itemSize.width())), - qMax(minSize.height(), int(itemSize.height())))); + layer->setSize(QSize(qMax(minSize.width(), int(renderBoundingRect.width())), + qMax(minSize.height(), int(renderBoundingRect.height())))); layer->scheduleUpdate(); if (layer->updateTexture()) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp index ab38b33aafe..33bc2ee156c 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -28,6 +28,9 @@ #include +#include +#include + #include #include #include @@ -476,11 +479,12 @@ QImage QuickItemNodeInstance::renderImage() const } renderImage.setDevicePixelRatio(devicePixelRatio); #else - if (s_unifiedRenderPath) + if (s_unifiedRenderPath) { renderImage = nodeInstanceServer()->grabWindow(); - else + renderImage = renderImage.copy(renderBoundingRect.toRect()); + } else { renderImage = nodeInstanceServer()->grabItem(quickItem()); - renderImage = renderImage.copy(renderBoundingRect.toRect()); + } /* When grabbing an offscren window the device pixel ratio is 1 */ renderImage.setDevicePixelRatio(1); @@ -613,6 +617,34 @@ static inline bool isRectangleSane(const QRectF &rect) return rect.isValid() && (rect.width() < 10000) && (rect.height() < 10000); } +static bool isEffectItem(QQuickItem *item) +{ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + Q_UNUSED(item) + return false; +#else + if (qobject_cast(item)) + return true; + + const auto propName = "source"; + + QQmlProperty prop(item, QString::fromLatin1(propName)); + if (!prop.isValid()) + return false; + + QQuickShaderEffectSource *source = prop.read().value(); + + if (source && source->sourceItem()) { + QQuickItemPrivate *pItem = QQuickItemPrivate::get(source->sourceItem()); + + if (pItem && pItem->layer() && pItem->layer()->enabled() && pItem->layer()->effect()) + return true; + } + + return false; +#endif +} + QRectF QuickItemNodeInstance::boundingRectWithStepChilds(QQuickItem *parentItem) const { QRectF boundingRect = parentItem->boundingRect(); @@ -620,8 +652,9 @@ QRectF QuickItemNodeInstance::boundingRectWithStepChilds(QQuickItem *parentItem) boundingRect = boundingRect.united(QRectF(QPointF(0, 0), size())); for (QQuickItem *childItem : parentItem->childItems()) { - if (!nodeInstanceServer()->hasInstanceForObject(childItem)) { - QRectF transformedRect = childItem->mapRectToItem(parentItem, boundingRectWithStepChilds(childItem)); + if (!nodeInstanceServer()->hasInstanceForObject(childItem) && !isEffectItem(childItem)) { + QRectF transformedRect = childItem->mapRectToItem(parentItem, + boundingRectWithStepChilds(childItem)); if (isRectangleSane(transformedRect)) boundingRect = boundingRect.united(transformedRect); }