1// Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qgfxsourceproxy_p.h"
5
6#include <private/qquickshadereffectsource_p.h>
7#include <private/qquickitem_p.h>
8#include <private/qquickimage_p.h>
9
10QT_BEGIN_NAMESPACE
11
12QGfxSourceProxy::QGfxSourceProxy(QQuickItem *parentItem)
13 : QQuickItem(parentItem)
14 , m_input(0)
15 , m_output(0)
16 , m_proxy(0)
17 , m_interpolation(AnyInterpolation)
18{
19}
20
21QGfxSourceProxy::~QGfxSourceProxy()
22{
23 delete m_proxy;
24}
25
26void QGfxSourceProxy::setInput(QQuickItem *input)
27{
28 if (m_input == input)
29 return;
30
31 if (m_input != nullptr)
32 disconnect(sender: m_input, signal: nullptr, receiver: this, member: nullptr);
33 m_input = input;
34 polish();
35 if (m_input != nullptr) {
36 if (QQuickImage *image = qobject_cast<QQuickImage *>(object: m_input)) {
37 connect(sender: image, signal: &QQuickImage::sourceSizeChanged, context: this, slot: &QGfxSourceProxy::repolish);
38 connect(sender: image, signal: &QQuickImage::fillModeChanged, context: this, slot: &QGfxSourceProxy::repolish);
39 }
40 connect(sender: m_input, signal: &QQuickItem::childrenChanged, context: this, slot: &QGfxSourceProxy::repolish);
41 }
42 emit inputChanged();
43}
44
45void QGfxSourceProxy::setOutput(QQuickItem *output)
46{
47 if (m_output == output)
48 return;
49 m_output = output;
50 emit activeChanged();
51 emit outputChanged();
52}
53
54void QGfxSourceProxy::setSourceRect(const QRectF &sourceRect)
55{
56 if (m_sourceRect == sourceRect)
57 return;
58 m_sourceRect = sourceRect;
59 polish();
60 emit sourceRectChanged();
61}
62
63void QGfxSourceProxy::setInterpolation(Interpolation i)
64{
65 if (m_interpolation == i)
66 return;
67 m_interpolation = i;
68 polish();
69 emit interpolationChanged();
70}
71
72
73void QGfxSourceProxy::useProxy()
74{
75 if (!m_proxy)
76 m_proxy = new QQuickShaderEffectSource(this);
77 m_proxy->setSourceRect(m_sourceRect);
78 m_proxy->setSourceItem(m_input);
79 m_proxy->setSmooth(m_interpolation != NearestInterpolation);
80 setOutput(m_proxy);
81}
82
83void QGfxSourceProxy::repolish()
84{
85 polish();
86}
87
88QObject *QGfxSourceProxy::findLayer(QQuickItem *item)
89{
90 if (!item)
91 return 0;
92 QQuickItemPrivate *d = QQuickItemPrivate::get(item);
93 if (d->extra.isAllocated() && d->extra->layer) {
94 QObject *layer = qvariant_cast<QObject *>(v: item->property(name: "layer"));
95 if (layer && layer->property(name: "enabled").toBool())
96 return layer;
97 }
98 return 0;
99}
100
101void QGfxSourceProxy::updatePolish()
102{
103 if (m_input == 0) {
104 setOutput(0);
105 return;
106 }
107
108 QQuickImage *image = qobject_cast<QQuickImage *>(object: m_input);
109 QQuickShaderEffectSource *shaderSource = qobject_cast<QQuickShaderEffectSource *>(object: m_input);
110 bool childless = m_input->childItems().size() == 0;
111 bool interpOk = m_interpolation == AnyInterpolation
112 || (m_interpolation == LinearInterpolation && m_input->smooth() == true)
113 || (m_interpolation == NearestInterpolation && m_input->smooth() == false);
114
115 // Layers can be used in two different ways. Option 1 is when the item is
116 // used as input to a separate ShaderEffect component. In this case,
117 // m_input will be the item itself.
118 QObject *layer = findLayer(item: m_input);
119 if (!layer && shaderSource) {
120 // Alternatively, the effect is applied via layer.effect, and the
121 // input to the effect will be the layer's internal ShaderEffectSource
122 // item. In this case, we need to backtrack and find the item that has
123 // the layer and configure it accordingly.
124 layer = findLayer(item: shaderSource->sourceItem());
125 }
126
127 // A bit crude test, but we're only using source rect for
128 // blurring+transparent edge, so this is good enough.
129 bool padded = m_sourceRect.x() < 0 || m_sourceRect.y() < 0;
130
131 bool direct = false;
132
133 if (layer) {
134 // Auto-configure the layer so interpolation and padding works as
135 // expected without allocating additional FBOs. In edgecases, where
136 // this feature is undesiered, the user can simply use
137 // ShaderEffectSource rather than layer.
138 layer->setProperty(name: "sourceRect", value: m_sourceRect);
139 layer->setProperty(name: "smooth", value: m_interpolation != NearestInterpolation);
140 direct = true;
141
142 } else if (childless && interpOk) {
143
144 if (shaderSource) {
145 if (shaderSource->sourceRect() == m_sourceRect || m_sourceRect.isEmpty())
146 direct = true;
147
148 } else if (!padded && ((image && image->fillMode() == QQuickImage::Stretch && !image->sourceSize().isNull())
149 || (!image && m_input->isTextureProvider())
150 )
151 ) {
152 direct = true;
153 }
154 }
155
156 if (direct) {
157 setOutput(m_input);
158 } else {
159 useProxy();
160 }
161
162 // Remove the proxy if it is not in use..
163 if (m_proxy && m_output == m_input) {
164 delete m_proxy;
165 m_proxy = 0;
166 }
167}
168
169QT_END_NAMESPACE
170
171#include "moc_qgfxsourceproxy_p.cpp"
172

source code of qt5compat/src/imports/graphicaleffects5/private/qgfxsourceproxy.cpp