1/****************************************************************************
2**
3** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the Qt Graphical Effects module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qgfxsourceproxy_p.h"
41
42#include <private/qquickshadereffectsource_p.h>
43#include <private/qquickitem_p.h>
44#include <private/qquickimage_p.h>
45
46QT_BEGIN_NAMESPACE
47
48QGfxSourceProxy::QGfxSourceProxy(QQuickItem *parentItem)
49 : QQuickItem(parentItem)
50 , m_input(0)
51 , m_output(0)
52 , m_proxy(0)
53 , m_interpolation(AnyInterpolation)
54{
55}
56
57QGfxSourceProxy::~QGfxSourceProxy()
58{
59 delete m_proxy;
60}
61
62void QGfxSourceProxy::setInput(QQuickItem *input)
63{
64 if (m_input == input)
65 return;
66
67 if (m_input != nullptr)
68 disconnect(sender: m_input, signal: nullptr, receiver: this, member: nullptr);
69 m_input = input;
70 polish();
71 if (m_input != nullptr) {
72 if (QQuickImage *image = qobject_cast<QQuickImage *>(object: m_input)) {
73 connect(sender: image, signal: &QQuickImage::sourceSizeChanged, receiver: this, slot: &QGfxSourceProxy::repolish);
74 connect(sender: image, signal: &QQuickImage::fillModeChanged, receiver: this, slot: &QGfxSourceProxy::repolish);
75 }
76 connect(sender: m_input, signal: &QQuickItem::childrenChanged, receiver: this, slot: &QGfxSourceProxy::repolish);
77 }
78 emit inputChanged();
79}
80
81void QGfxSourceProxy::setOutput(QQuickItem *output)
82{
83 if (m_output == output)
84 return;
85 m_output = output;
86 emit activeChanged();
87 emit outputChanged();
88}
89
90void QGfxSourceProxy::setSourceRect(const QRectF &sourceRect)
91{
92 if (m_sourceRect == sourceRect)
93 return;
94 m_sourceRect = sourceRect;
95 polish();
96 emit sourceRectChanged();
97}
98
99void QGfxSourceProxy::setInterpolation(Interpolation i)
100{
101 if (m_interpolation == i)
102 return;
103 m_interpolation = i;
104 polish();
105 emit interpolationChanged();
106}
107
108
109void QGfxSourceProxy::useProxy()
110{
111 if (!m_proxy)
112 m_proxy = new QQuickShaderEffectSource(this);
113 m_proxy->setSourceRect(m_sourceRect);
114 m_proxy->setSourceItem(m_input);
115 m_proxy->setSmooth(m_interpolation != NearestInterpolation);
116 setOutput(m_proxy);
117}
118
119void QGfxSourceProxy::repolish()
120{
121 polish();
122}
123
124QObject *QGfxSourceProxy::findLayer(QQuickItem *item)
125{
126 if (!item)
127 return 0;
128 QQuickItemPrivate *d = QQuickItemPrivate::get(item);
129 if (d->extra.isAllocated() && d->extra->layer) {
130 QObject *layer = qvariant_cast<QObject *>(v: item->property(name: "layer"));
131 if (layer && layer->property(name: "enabled").toBool())
132 return layer;
133 }
134 return 0;
135}
136
137void QGfxSourceProxy::updatePolish()
138{
139 if (m_input == 0) {
140 setOutput(0);
141 return;
142 }
143
144 QQuickImage *image = qobject_cast<QQuickImage *>(object: m_input);
145 QQuickShaderEffectSource *shaderSource = qobject_cast<QQuickShaderEffectSource *>(object: m_input);
146 bool childless = m_input->childItems().size() == 0;
147 bool interpOk = m_interpolation == AnyInterpolation
148 || (m_interpolation == LinearInterpolation && m_input->smooth() == true)
149 || (m_interpolation == NearestInterpolation && m_input->smooth() == false);
150
151 // Layers can be used in two different ways. Option 1 is when the item is
152 // used as input to a separate ShaderEffect component. In this case,
153 // m_input will be the item itself.
154 QObject *layer = findLayer(item: m_input);
155 if (!layer && shaderSource) {
156 // Alternatively, the effect is applied via layer.effect, and the
157 // input to the effect will be the layer's internal ShaderEffectSource
158 // item. In this case, we need to backtrack and find the item that has
159 // the layer and configure it accordingly.
160 layer = findLayer(item: shaderSource->sourceItem());
161 }
162
163 // A bit crude test, but we're only using source rect for
164 // blurring+transparent edge, so this is good enough.
165 bool padded = m_sourceRect.x() < 0 || m_sourceRect.y() < 0;
166
167 bool direct = false;
168
169 if (layer) {
170 // Auto-configure the layer so interpolation and padding works as
171 // expected without allocating additional FBOs. In edgecases, where
172 // this feature is undesiered, the user can simply use
173 // ShaderEffectSource rather than layer.
174 layer->setProperty(name: "sourceRect", value: m_sourceRect);
175 layer->setProperty(name: "smooth", value: m_interpolation != NearestInterpolation);
176 direct = true;
177
178 } else if (childless && interpOk) {
179
180 if (shaderSource) {
181 if (shaderSource->sourceRect() == m_sourceRect || m_sourceRect.isEmpty())
182 direct = true;
183
184 } else if (!padded && ((image && image->fillMode() == QQuickImage::Stretch && !image->sourceSize().isNull())
185 || (!image && m_input->isTextureProvider())
186 )
187 ) {
188 direct = true;
189 }
190 }
191
192 if (direct) {
193 setOutput(m_input);
194 } else {
195 useProxy();
196 }
197
198 // Remove the proxy if it is not in use..
199 if (m_proxy && m_output == m_input) {
200 delete m_proxy;
201 m_proxy = 0;
202 }
203}
204
205QT_END_NAMESPACE
206

source code of qtgraphicaleffects/src/effects/private/qgfxsourceproxy.cpp