Revision control
++ // Copyright (C) 2020 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++
++ #include <QtQuick3D/qquick3dobject.h>
++ #include <QtQuick3D/private/qquick3ditem2d_p.h>
++
++ #include <QtQuick/private/qquickitem_p.h>
++ #include <QtQuick/private/qsgrenderer_p.h>
++ #include <QtQuick/private/qquickwindow_p.h>
++
++ #include <QtQuick3DRuntimeRender/private/qssgrenderitem2d_p.h>
++ #include "qquick3dnode_p_p.h"
++
++ #include <QtGui/rhi/qrhi.h>
++
++ QT_BEGIN_NAMESPACE
++
++ /*
++ internal
++ */
++
++ QQuick3DItem2D::QQuick3DItem2D(QQuickItem *item, QQuick3DNode *parent)
++ : QQuick3DNode(*(new QQuick3DNodePrivate(QQuick3DNodePrivate::Type::Item2D)), parent)
++ {
++ m_contentItem = new QQuickItem();
++ m_contentItem->setObjectName(QLatin1String("parent of ") + item->objectName()); // for debugging
++ // No size is set for m_contentItem. This is intentional, otherwise item2d anchoring breaks.
++ QQuickItemPrivate::get(m_contentItem)->ensureSubsceneDeliveryAgent();
++ QQmlEngine::setObjectOwnership(m_contentItem, QQmlEngine::CppOwnership);
++
++ connect(m_contentItem, &QQuickItem::childrenChanged, this, &QQuick3DObject::update);
++ addChildItem(item);
++ }
++
++ QQuick3DItem2D::~QQuick3DItem2D()
++ {
++ delete m_contentItem;
++ }
++
++ void QQuick3DItem2D::addChildItem(QQuickItem *item)
++ {
++ item->setParent(m_contentItem);
++ item->setParentItem(m_contentItem);
++ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::ChangeType::Destroyed);
++ connect(item, &QQuickItem::enabledChanged, this, &QQuick3DItem2D::updatePicking);
++ connect(item, &QQuickItem::visibleChanged, this, &QQuick3DItem2D::updatePicking);
++ m_sourceItems.append(item);
++ update();
++ }
++ void QQuick3DItem2D::removeChildItem(QQuickItem *item)
++ {
++ m_sourceItems.removeOne(item);
++ if (item)
++ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::ChangeType::Destroyed);
++ if (m_sourceItems.isEmpty())
++ emit allChildrenRemoved();
++ else
++ update();
++ }
++
++ QQuickItem *QQuick3DItem2D::contentItem() const
++ {
++ return m_contentItem;
++ }
++
++ void QQuick3DItem2D::itemDestroyed(QQuickItem *item)
++ {
++ removeChildItem(item);
++ }
++
++ void QQuick3DItem2D::updatePicking()
++ {
++ m_pickingDirty = true;
++ update();
++ }
++
++ QSSGRenderGraphObject *QQuick3DItem2D::updateSpatialNode(QSSGRenderGraphObject *node)
++ {
++ auto *sourceItemPrivate = QQuickItemPrivate::get(m_contentItem);
++ QQuickWindow *window = m_contentItem->window();
++
++ if (!window) {
++ const auto &manager = QQuick3DObjectPrivate::get(this)->sceneManager;
++ window = manager->window();
++ }
++
++ if (!node) {
++ markAllDirty();
++ auto *backEndNode = new QSSGRenderItem2D();
++ backEndNode->m_frontEndObject = this;
++ node = backEndNode;
++ }
++
++ QQuick3DNode::updateSpatialNode(node);
++
++ auto itemNode = static_cast<QSSGRenderItem2D *>(node);
++
++ itemNode->m_rootNode = sourceItemPrivate->rootNode();
++ if (!itemNode->m_rootNode) {
++ QQuickWindowPrivate::get(window)->updateDirtyNode(m_contentItem);
++ itemNode->m_rootNode = sourceItemPrivate->rootNode();
++ if (!itemNode->m_rootNode) {
++ qWarning() << "Item2D is not initialized. It will not be shown.";
++ return nullptr;
++ }
++ }
++
++ if (m_pickingDirty) {
++ m_pickingDirty = false;
++ bool isPickable = false;
++ for (const auto &item : std::as_const(m_sourceItems)) {
++ // Enable picking for Item2D if any of its child is visible and enabled.
++ if (item->isVisible() && item->isEnabled()) {
++ isPickable = true;
++ break;
++ }
++ }
++ itemNode->setState(QSSGRenderNode::LocalState::Pickable, isPickable);
++ }
++
++ return node;
++ }
++
++ void QQuick3DItem2D::markAllDirty()
++ {
++ m_pickingDirty = true;
++
++ QQuick3DNode::markAllDirty();
++ }
++
++ void QQuick3DItem2D::preSync()
++ {
++ const auto &manager = QQuick3DObjectPrivate::get(this)->sceneManager;
++ auto *sourcePrivate = QQuickItemPrivate::get(m_contentItem);
++ auto *window = manager->window();
++ if (m_window != window) {
++ update(); // Just schedule an upate immediately.
++ if (m_window) {
++ disconnect(m_window, SIGNAL(destroyed(QObject*)), this, SLOT(derefWindow(QObject*)));
++ sourcePrivate->derefWindow();
++ }
++ m_window = window;
++ sourcePrivate->refWindow(window);
++ connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(derefWindow(QObject*)));
++ sourcePrivate->refFromEffectItem(true);
++ }
++ }
++
++ static void detachWindow(QQuickItem *item, QObject *win)
++ {
++ auto *itemPriv = QQuickItemPrivate::get(item);
++
++ if (win == itemPriv->window) {
++ itemPriv->window = nullptr;
++ itemPriv->windowRefCount = 0;
++
++ itemPriv->prevDirtyItem = nullptr;
++ itemPriv->nextDirtyItem = nullptr;
++ }
++
++ for (auto *child : std::as_const(itemPriv->childItems))
++ detachWindow(child, win);
++ }
++
++ void QQuick3DItem2D::derefWindow(QObject *win)
++ {
++ detachWindow(m_contentItem, win);
++ }
++
++ QT_END_NAMESPACE