aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp75
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp55
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp6
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp17
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h18
-rw-r--r--src/quick/items/context2d/qquickcontext2dtile.cpp13
-rw-r--r--src/quick/items/context2d/qquickcontext2dtile_p.h9
-rw-r--r--src/quick/items/items.pri83
-rw-r--r--src/quick/items/qquickanimatedimage.cpp11
-rw-r--r--src/quick/items/qquickanimatedimage_p_p.h12
-rw-r--r--src/quick/items/qquickborderimage.cpp98
-rw-r--r--src/quick/items/qquickborderimage_p.h2
-rw-r--r--src/quick/items/qquickborderimage_p_p.h30
-rw-r--r--src/quick/items/qquickdrag.cpp46
-rw-r--r--src/quick/items/qquickdrag_p.h6
-rw-r--r--src/quick/items/qquickevents.cpp22
-rw-r--r--src/quick/items/qquickevents_p_p.h67
-rw-r--r--src/quick/items/qquickflickable_p_p.h1
-rw-r--r--src/quick/items/qquickframebufferobject.cpp2
-rw-r--r--src/quick/items/qquickgenericshadereffect.cpp609
-rw-r--r--src/quick/items/qquickgenericshadereffect_p.h146
-rw-r--r--src/quick/items/qquickgraphicsinfo.cpp306
-rw-r--r--src/quick/items/qquickgraphicsinfo_p.h166
-rw-r--r--src/quick/items/qquickitem.cpp46
-rw-r--r--src/quick/items/qquickitem_p.h5
-rw-r--r--src/quick/items/qquickitemgrabresult.cpp3
-rw-r--r--src/quick/items/qquickitemsmodule.cpp30
-rw-r--r--src/quick/items/qquickmousearea.cpp32
-rw-r--r--src/quick/items/qquickmousearea_p_p.h3
-rw-r--r--src/quick/items/qquickopenglinfo.cpp4
-rw-r--r--src/quick/items/qquickopenglshadereffect.cpp862
-rw-r--r--src/quick/items/qquickopenglshadereffect_p.h176
-rw-r--r--src/quick/items/qquickopenglshadereffectnode.cpp (renamed from src/quick/items/qquickshadereffectnode.cpp)97
-rw-r--r--src/quick/items/qquickopenglshadereffectnode_p.h (renamed from src/quick/items/qquickshadereffectnode_p.h)44
-rw-r--r--src/quick/items/qquickpainteditem.cpp29
-rw-r--r--src/quick/items/qquickpathview_p_p.h1
-rw-r--r--src/quick/items/qquickrectangle.cpp1
-rw-r--r--src/quick/items/qquickrendercontrol.cpp31
-rw-r--r--src/quick/items/qquickshadereffect.cpp1170
-rw-r--r--src/quick/items/qquickshadereffect_p.h120
-rw-r--r--src/quick/items/qquickshadereffectmesh.cpp287
-rw-r--r--src/quick/items/qquickshadereffectmesh_p.h59
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp3
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h8
-rw-r--r--src/quick/items/qquickspriteengine.cpp7
-rw-r--r--src/quick/items/qquicktext.cpp35
-rw-r--r--src/quick/items/qquicktextcontrol.cpp33
-rw-r--r--src/quick/items/qquicktextcontrol_p.h3
-rw-r--r--src/quick/items/qquicktextedit.cpp60
-rw-r--r--src/quick/items/qquicktextedit_p.h5
-rw-r--r--src/quick/items/qquicktextinput.cpp90
-rw-r--r--src/quick/items/qquicktextinput_p.h5
-rw-r--r--src/quick/items/qquicktextinput_p_p.h2
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp4
-rw-r--r--src/quick/items/qquickview.cpp3
-rw-r--r--src/quick/items/qquickwindow.cpp349
-rw-r--r--src/quick/items/qquickwindow.h14
-rw-r--r--src/quick/items/qquickwindow_p.h7
58 files changed, 4098 insertions, 1330 deletions
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index b3b5144eb3..b340d9bf94 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -43,7 +43,7 @@
#include <private/qquickcanvascontext_p.h>
#include <private/qquickcontext2d_p.h>
#include <private/qquickcontext2dtexture_p.h>
-#include <qsgsimpletexturenode.h>
+#include <private/qsgadaptationlayer_p.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
#include <QtGui/QGuiApplication>
@@ -59,24 +59,11 @@
QT_BEGIN_NAMESPACE
-class QQuickCanvasNode : public QSGSimpleTextureNode
-{
-public:
- QQuickCanvasNode() {
- qsgnode_set_description(this, QStringLiteral("canvasnode"));
- setOwnsTexture(false);
- }
-
- ~QQuickCanvasNode() {
- delete texture();
- }
-};
-
class QQuickCanvasTextureProvider : public QSGTextureProvider
{
public:
- QQuickCanvasNode *node;
- QSGTexture *texture() const Q_DECL_OVERRIDE { return node ? node->texture() : 0; }
+ QSGTexture *tex;
+ QSGTexture *texture() const Q_DECL_OVERRIDE { return tex; }
void fireTextureChanged() { emit textureChanged(); }
};
@@ -187,7 +174,8 @@ public:
QUrl baseUrl;
QMap<int, QV4::PersistentValue> animationCallbacks;
mutable QQuickCanvasTextureProvider *textureProvider;
- QQuickCanvasNode *node;
+ QSGImageNode *node;
+ QSGTexture *nodeTexture;
};
QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
@@ -203,6 +191,7 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
, renderStrategy(QQuickCanvasItem::Immediate)
, textureProvider(0)
, node(0)
+ , nodeTexture(0)
{
implicitAntialiasing = true;
}
@@ -256,17 +245,18 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
The Canvas item supports two render targets: \c Canvas.Image and
\c Canvas.FramebufferObject.
- The \c Canvas.Image render target is a \a QImage object. This render
- target supports background thread rendering, allowing complex or long
- running painting to be executed without blocking the UI.
+ The \c Canvas.Image render target is a \a QImage object. This render target
+ supports background thread rendering, allowing complex or long running
+ painting to be executed without blocking the UI. This is the only render
+ target that is supported by all Qt Quick backends.
The Canvas.FramebufferObject render target utilizes OpenGL hardware
acceleration rather than rendering into system memory, which in many cases
- results in faster rendering. Canvas.FramebufferObject relies on the
- OpenGL extensions \c GL_EXT_framebuffer_multisample and
- \c GL_EXT_framebuffer_blit for antialiasing. It will also use more
- graphics memory when rendering strategy is anything other than
- Canvas.Cooperative.
+ results in faster rendering. Canvas.FramebufferObject relies on the OpenGL
+ extensions \c GL_EXT_framebuffer_multisample and \c GL_EXT_framebuffer_blit
+ for antialiasing. It will also use more graphics memory when rendering
+ strategy is anything other than Canvas.Cooperative. Framebuffer objects may
+ not be available with Qt Quick backends other than OpenGL.
The default render target is Canvas.Image and the default renderStrategy is
Canvas.Immediate.
@@ -301,7 +291,14 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
and can be used directly in \l {ShaderEffect}{ShaderEffects} and other
classes that consume texture providers.
- \sa Context2D
+ \note In general large canvases, frequent updates, and animation should be
+ avoided with the Canvas.Image render target. This is because with
+ accelerated graphics APIs each update will lead to a texture upload. Also,
+ if possible, prefer QQuickPaintedItem and implement drawing in C++ via
+ QPainter instead of the more expensive and likely less performing
+ JavaScript and Context2D approach.
+
+ \sa Context2D QQuickPaintedItem
*/
QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent)
@@ -739,16 +736,16 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
if (!d->context || d->canvasWindow.size().isEmpty()) {
if (d->textureProvider) {
- d->textureProvider->node = 0;
+ d->textureProvider->tex = 0;
d->textureProvider->fireTextureChanged();
}
delete oldNode;
return 0;
}
- QQuickCanvasNode *node = static_cast<QQuickCanvasNode*>(oldNode);
+ QSGImageNode *node = static_cast<QSGImageNode *>(oldNode);
if (!node) {
- node = new QQuickCanvasNode();
+ node = QQuickWindowPrivate::get(window())->context->sceneGraphContext()->createImageNode();
d->node = node;
}
@@ -765,22 +762,27 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context);
QQuickContext2DTexture *factory = ctx->texture();
- QSGTexture *texture = factory->textureForNextFrame(node->texture(), window());
+ QSGTexture *texture = factory->textureForNextFrame(d->nodeTexture, window());
if (!texture) {
delete node;
d->node = 0;
+ delete d->nodeTexture;
+ d->nodeTexture = 0;
if (d->textureProvider) {
- d->textureProvider->node = 0;
+ d->textureProvider->tex = 0;
d->textureProvider->fireTextureChanged();
}
return 0;
}
+ d->nodeTexture = texture;
node->setTexture(texture);
- node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
+ node->setTargetRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
+ node->setInnerTargetRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
+ node->update();
if (d->textureProvider) {
- d->textureProvider->node = node;
+ d->textureProvider->tex = d->nodeTexture;
d->textureProvider->fireTextureChanged();
}
return node;
@@ -800,14 +802,17 @@ QSGTextureProvider *QQuickCanvasItem::textureProvider() const
return QQuickItem::textureProvider();
Q_D(const QQuickCanvasItem);
+#ifndef QT_NO_OPENGL
QQuickWindow *w = window();
- if (!w || !w->openglContext() || QThread::currentThread() != w->openglContext()->thread()) {
+ if (!w || !w->isSceneGraphInitialized()
+ || QThread::currentThread() != QQuickWindowPrivate::get(w)->context->thread()) {
qWarning("QQuickCanvasItem::textureProvider: can only be queried on the rendering thread of an exposed window");
return 0;
}
+#endif
if (!d->textureProvider)
d->textureProvider = new QQuickCanvasTextureProvider;
- d->textureProvider->node = d->node;
+ d->textureProvider->tex = d->nodeTexture;
return d->textureProvider;
}
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index b2117d3eb9..b924701f2b 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -43,6 +43,7 @@
#include <private/qquickcontext2dtexture_p.h>
#include <private/qquickitem_p.h>
#include <QtQuick/private/qquickshadereffectsource_p.h>
+#include <qsgrendererinterface.h>
#include <QtQuick/private/qsgcontext_p.h>
#include <private/qquicksvgparser_p.h>
@@ -74,6 +75,10 @@
#include <private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
+#ifndef QT_NO_OPENGL
+# include <private/qsgdefaultrendercontext_p.h>
+#endif
+
#include <cmath>
#if defined(Q_OS_QNX) || defined(Q_OS_ANDROID)
#include <ctype.h>
@@ -2669,15 +2674,15 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx
QString textAlign = s->toQString();
QQuickContext2D::TextAlignType ta;
- if (textAlign == QStringLiteral("start"))
+ if (textAlign == QLatin1String("start"))
ta = QQuickContext2D::Start;
- else if (textAlign == QStringLiteral("end"))
+ else if (textAlign == QLatin1String("end"))
ta = QQuickContext2D::End;
- else if (textAlign == QStringLiteral("left"))
+ else if (textAlign == QLatin1String("left"))
ta = QQuickContext2D::Left;
- else if (textAlign == QStringLiteral("right"))
+ else if (textAlign == QLatin1String("right"))
ta = QQuickContext2D::Right;
- else if (textAlign == QStringLiteral("center"))
+ else if (textAlign == QLatin1String("center"))
ta = QQuickContext2D::Center;
else
return QV4::Encode::undefined();
@@ -3980,10 +3985,12 @@ public:
~QQuickContext2DThreadCleanup()
{
+#ifndef QT_NO_OPENGL
context->makeCurrent(surface);
delete texture;
context->doneCurrent();
delete context;
+#endif
surface->deleteLater();
}
@@ -4019,6 +4026,7 @@ QQuickContext2D::~QQuickContext2D()
delete m_buffer;
if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
+#ifndef QT_NO_OPENGL
if (m_renderStrategy == QQuickCanvasItem::Immediate && m_glContext) {
Q_ASSERT(QThread::currentThread() == m_glContext->thread());
m_glContext->makeCurrent(m_surface.data());
@@ -4039,6 +4047,7 @@ QQuickContext2D::~QQuickContext2D()
m_texture->deleteLater();
}
}
+#endif
} else {
// Image based does not have GL resources, but must still be deleted
// on its designated thread after it has completed whatever it might
@@ -4064,8 +4073,6 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_canvas = canvasItem;
m_renderTarget = canvasItem->renderTarget();
-
- QQuickWindow *window = canvasItem->window();
m_renderStrategy = canvasItem->renderStrategy();
#ifdef Q_OS_WIN
@@ -4084,12 +4091,24 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_renderTarget = QQuickCanvasItem::Image;
}
+ // Disable Framebuffer Object based rendering when not running with OpenGL
+ if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
+ QSGRendererInterface *rif = canvasItem->window()->rendererInterface();
+ if (rif && rif->graphicsApi() != QSGRendererInterface::OpenGL)
+ m_renderTarget = QQuickCanvasItem::Image;
+ }
+
switch (m_renderTarget) {
case QQuickCanvasItem::Image:
m_texture = new QQuickContext2DImageTexture;
break;
case QQuickCanvasItem::FramebufferObject:
+#ifndef QT_NO_OPENGL
m_texture = new QQuickContext2DFBOTexture;
+#else
+ // It shouldn't be possible to use a FramebufferObject without OpenGL
+ m_texture = nullptr;
+#endif
break;
}
@@ -4103,18 +4122,27 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_thread = QThread::currentThread();
QThread *renderThread = m_thread;
- QThread *sceneGraphThread = window->openglContext() ? window->openglContext()->thread() : 0;
+#ifndef QT_NO_OPENGL
+ QQuickWindow *window = canvasItem->window();
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
+ QThread *sceneGraphThread = wd->context->thread();
if (m_renderStrategy == QQuickCanvasItem::Threaded)
renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem));
else if (m_renderStrategy == QQuickCanvasItem::Cooperative)
renderThread = sceneGraphThread;
+#else
+ if (m_renderStrategy == QQuickCanvasItem::Threaded)
+ renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem));
+#endif
+
if (renderThread && renderThread != QThread::currentThread())
m_texture->moveToThread(renderThread);
-
+#ifndef QT_NO_OPENGL
if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) {
- QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->openglContext();
+ auto openglRenderContext = static_cast<const QSGDefaultRenderContext *>(QQuickWindowPrivate::get(window)->context);
+ QOpenGLContext *cc = openglRenderContext->openglContext();
m_surface.reset(new QOffscreenSurface);
m_surface->setFormat(window->format());
m_surface->create();
@@ -4125,7 +4153,7 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_glContext->moveToThread(renderThread);
m_texture->initializeOpenGL(m_glContext, m_surface.data());
}
-
+#endif
connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
reset();
@@ -4172,6 +4200,7 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
flush();
m_texture->grabImage(bounds);
} else {
+#ifndef QT_NO_OPENGL
QQuickWindow *window = m_canvas->window();
QOpenGLContext *ctx = window ? window->openglContext() : 0;
if (ctx && ctx->isValid()) {
@@ -4187,6 +4216,10 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
qWarning() << "Cannot read pixels from canvas before opengl context is valid";
return QImage();
}
+#else
+ flush();
+ m_texture->grabImage(bounds);
+#endif
}
} else if (m_renderStrategy == QQuickCanvasItem::Cooperative) {
qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode";
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index 58b374e696..8d659040b3 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -42,9 +42,11 @@
#include <qqml.h>
#include <QtCore/QMutex>
#include <QtQuick/qsgtexture.h>
-#include <QtGui/QOpenGLContext>
#include <QtGui/QPaintEngine>
-#include <QtGui/private/qopenglpaintengine_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/QOpenGLContext>
+# include <QtGui/private/qopenglpaintengine_p.h>
+#endif
#define HAS_SHADOW(offsetX, offsetY, blur, color) (color.isValid() && color.alpha() && (blur || offsetX || offsetY))
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index f3513f447a..ddecf7c3d4 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -44,14 +44,16 @@
#include <QtQuick/private/qsgtexture_p.h>
#include "qquickcontext2dcommandbuffer_p.h"
#include <QOpenGLPaintDevice>
-
+#ifndef QT_NO_OPENGL
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
+#include <QOpenGLFunctions>
+#endif
#include <QtCore/QThread>
#include <QtGui/QGuiApplication>
QT_BEGIN_NAMESPACE
-
+#ifndef QT_NO_OPENGL
#define QT_MINIMUM_FBO_SIZE 64
static inline int qt_next_power_of_two(int v)
@@ -85,10 +87,12 @@ struct GLAcquireContext {
}
QOpenGLContext *ctx;
};
-
+#endif
QQuickContext2DTexture::QQuickContext2DTexture()
: m_context(0)
+#ifndef QT_NO_OPENGL
, m_gl(0)
+#endif
, m_surface(0)
, m_item(0)
, m_canvasWindowChanged(false)
@@ -250,9 +254,9 @@ void QQuickContext2DTexture::paint(QQuickContext2DCommandBuffer *ccb)
return;
}
QQuickContext2D::mutex.unlock();
-
+#ifndef QT_NO_OPENGL
GLAcquireContext currentContext(m_gl, m_surface);
-
+#endif
if (!m_tiledCanvas) {
paintWithoutTiles(ccb);
delete ccb;
@@ -379,7 +383,7 @@ bool QQuickContext2DTexture::event(QEvent *e)
}
return QObject::event(e);
}
-
+#ifndef QT_NO_OPENGL
static inline QSize npotAdjustedSize(const QSize &size)
{
static bool checked = false;
@@ -646,6 +650,7 @@ void QQuickContext2DFBOTexture::endPainting()
m_fbo->bindDefault();
}
+#endif
QQuickContext2DImageTexture::QQuickContext2DImageTexture()
: QQuickContext2DTexture()
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index edc7283283..ed38382892 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -54,10 +54,10 @@
#include <QtQuick/qsgtexture.h>
#include "qquickcanvasitem_p.h"
#include "qquickcontext2d_p.h"
-
-#include <QOpenGLContext>
-#include <QOpenGLFramebufferObject>
-
+#ifndef QT_NO_OPENGL
+# include <QOpenGLContext>
+# include <QOpenGLFramebufferObject>
+#endif
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#include <QtCore/QThread>
@@ -121,11 +121,12 @@ public:
// Called during sync() on the scene graph thread while GUI is blocked.
virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window) = 0;
bool event(QEvent *e);
-
+#ifndef QT_NO_OPENGL
void initializeOpenGL(QOpenGLContext *gl, QOffscreenSurface *s) {
m_gl = gl;
m_surface = s;
}
+#endif
Q_SIGNALS:
void textureChanged();
@@ -152,8 +153,9 @@ protected:
QList<QQuickContext2DTile*> m_tiles;
QQuickContext2D *m_context;
-
+#ifndef QT_NO_OPENGL
QOpenGLContext *m_gl;
+#endif
QSurface *m_surface;
QQuickContext2D::State m_state;
@@ -174,7 +176,7 @@ protected:
uint m_painting : 1;
uint m_onCustomThread : 1; // Not GUI and not SGRender
};
-
+#ifndef QT_NO_OPENGL
class QQuickContext2DFBOTexture : public QQuickContext2DTexture
{
Q_OBJECT
@@ -209,7 +211,7 @@ private:
GLuint m_displayTextures[2];
int m_displayTexture;
};
-
+#endif
class QSGPlainTexture;
class QQuickContext2DImageTexture : public QQuickContext2DTexture
{
diff --git a/src/quick/items/context2d/qquickcontext2dtile.cpp b/src/quick/items/context2d/qquickcontext2dtile.cpp
index a1503762de..95b6c9d961 100644
--- a/src/quick/items/context2d/qquickcontext2dtile.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtile.cpp
@@ -38,10 +38,11 @@
****************************************************************************/
#include "qquickcontext2dtile_p.h"
-
-#include <QOpenGLFramebufferObject>
-#include <QOpenGLFramebufferObjectFormat>
-#include <QOpenGLPaintDevice>
+#ifndef QT_NO_OPENGL
+# include <QOpenGLFramebufferObject>
+# include <QOpenGLFramebufferObjectFormat>
+# include <QOpenGLPaintDevice>
+#endif
QT_BEGIN_NAMESPACE
@@ -96,7 +97,7 @@ QPainter* QQuickContext2DTile::createPainter(bool smooth, bool antialiasing)
return 0;
}
-
+#ifndef QT_NO_OPENGL
QQuickContext2DFBOTile::QQuickContext2DFBOTile()
: QQuickContext2DTile()
, m_fbo(0)
@@ -146,7 +147,7 @@ void QQuickContext2DFBOTile::setRect(const QRect& r)
m_fbo = new QOpenGLFramebufferObject(r.size(), format);
}
}
-
+#endif
QQuickContext2DImageTile::QQuickContext2DImageTile()
: QQuickContext2DTile()
diff --git a/src/quick/items/context2d/qquickcontext2dtile_p.h b/src/quick/items/context2d/qquickcontext2dtile_p.h
index d9be2023c4..a87202daae 100644
--- a/src/quick/items/context2d/qquickcontext2dtile_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtile_p.h
@@ -52,8 +52,9 @@
//
#include "qquickcontext2d_p.h"
-#include <QOpenGLFramebufferObject>
-
+#ifndef QT_NO_OPENGL
+# include <QOpenGLFramebufferObject>
+#endif
QT_BEGIN_NAMESPACE
class QQuickContext2DTexture;
@@ -82,7 +83,7 @@ protected:
QPainter m_painter;
};
-
+#ifndef QT_NO_OPENGL
class QQuickContext2DFBOTile : public QQuickContext2DTile
{
public:
@@ -99,7 +100,7 @@ private:
QOpenGLFramebufferObject *m_fbo;
};
-
+#endif
class QQuickContext2DImageTile : public QQuickContext2DTile
{
public:
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index ab966b6ccc..0c7dc97a2c 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -63,10 +63,6 @@ HEADERS += \
$$PWD/qquickstateoperations_p.h \
$$PWD/qquickimplicitsizeitem_p.h \
$$PWD/qquickimplicitsizeitem_p_p.h \
- $$PWD/qquickspriteengine_p.h \
- $$PWD/qquicksprite_p.h \
- $$PWD/qquickspritesequence_p.h \
- $$PWD/qquickanimatedsprite_p.h \
$$PWD/qquickdrag_p.h \
$$PWD/qquickdroparea_p.h \
$$PWD/qquickmultipointtoucharea_p.h \
@@ -76,11 +72,14 @@ HEADERS += \
$$PWD/qquickscreen_p.h \
$$PWD/qquickwindowattached_p.h \
$$PWD/qquickwindowmodule_p.h \
- $$PWD/qquickframebufferobject.h \
- $$PWD/qquickitemgrabresult.h \
+ $$PWD/qquickshadereffectsource_p.h \
+ $$PWD/qquickshadereffectmesh_p.h \
+ $$PWD/qquickshadereffect_p.h \
+ $$PWD/qquickgenericshadereffect_p.h \
$$PWD/qquickrendercontrol.h \
$$PWD/qquickrendercontrol_p.h \
- $$PWD/qquickopenglinfo_p.h
+ $$PWD/qquickgraphicsinfo_p.h \
+ $$PWD/qquickitemgrabresult.h
SOURCES += \
$$PWD/qquickevents.cpp \
@@ -120,10 +119,6 @@ SOURCES += \
$$PWD/qquickitemanimation.cpp \
$$PWD/qquickstateoperations.cpp \
$$PWD/qquickimplicitsizeitem.cpp \
- $$PWD/qquickspriteengine.cpp \
- $$PWD/qquicksprite.cpp \
- $$PWD/qquickspritesequence.cpp \
- $$PWD/qquickanimatedsprite.cpp \
$$PWD/qquickaccessibleattached.cpp \
$$PWD/qquickdrag.cpp \
$$PWD/qquickdroparea.cpp \
@@ -133,36 +128,50 @@ SOURCES += \
$$PWD/qquickwindowmodule.cpp \
$$PWD/qquickscreen.cpp \
$$PWD/qquickwindowattached.cpp \
- $$PWD/qquickframebufferobject.cpp \
- $$PWD/qquickitemgrabresult.cpp \
+ $$PWD/qquickshadereffectsource.cpp \
+ $$PWD/qquickshadereffectmesh.cpp \
+ $$PWD/qquickshadereffect.cpp \
+ $$PWD/qquickgenericshadereffect.cpp \
$$PWD/qquickrendercontrol.cpp \
- $$PWD/qquickopenglinfo.cpp
+ $$PWD/qquickgraphicsinfo.cpp \
+ $$PWD/qquickitemgrabresult.cpp
-SOURCES += \
- $$PWD/qquickshadereffect.cpp \
- $$PWD/qquickshadereffectmesh.cpp \
- $$PWD/qquickshadereffectnode.cpp \
- $$PWD/qquickshadereffectsource.cpp \
+# Items that depend on OpenGL Renderer
+contains(QT_CONFIG, opengl(es1|es2)?) {
+ SOURCES += \
+ $$PWD/qquickopenglinfo.cpp \
+ $$PWD/qquickopenglshadereffect.cpp \
+ $$PWD/qquickopenglshadereffectnode.cpp \
+ $$PWD/qquickframebufferobject.cpp \
+ $$PWD/qquickspriteengine.cpp \
+ $$PWD/qquicksprite.cpp \
+ $$PWD/qquickspritesequence.cpp \
+ $$PWD/qquickanimatedsprite.cpp
-HEADERS += \
- $$PWD/qquickshadereffect_p.h \
- $$PWD/qquickshadereffectmesh_p.h \
- $$PWD/qquickshadereffectnode_p.h \
- $$PWD/qquickshadereffectsource_p.h \
+ HEADERS += \
+ $$PWD/qquickopenglinfo_p.h \
+ $$PWD/qquickspriteengine_p.h \
+ $$PWD/qquicksprite_p.h \
+ $$PWD/qquickspritesequence_p.h \
+ $$PWD/qquickanimatedsprite_p.h \
+ $$PWD/qquickopenglshadereffect_p.h \
+ $$PWD/qquickopenglshadereffectnode_p.h \
+ $$PWD/qquickframebufferobject.h
-OTHER_FILES += \
- $$PWD/shaders/sprite.vert \
- $$PWD/shaders/sprite.frag \
- $$PWD/shaders/shadereffect.vert \
- $$PWD/shaders/shadereffect.frag \
- $$PWD/shaders/shadereffectfallback.vert \
- $$PWD/shaders/shadereffectfallback.frag \
- $$PWD/shaders/sprite_core.vert \
- $$PWD/shaders/sprite_core.frag \
- $$PWD/shaders/shadereffect_core.vert \
- $$PWD/shaders/shadereffect_core.frag \
- $$PWD/shaders/shadereffectfallback_core.vert \
- $$PWD/shaders/shadereffectfallback_core.frag
+ OTHER_FILES += \
+ $$PWD/shaders/sprite.vert \
+ $$PWD/shaders/sprite.frag \
+ $$PWD/shaders/shadereffect.vert \
+ $$PWD/shaders/shadereffect.frag \
+ $$PWD/shaders/shadereffectfallback.vert \
+ $$PWD/shaders/shadereffectfallback.frag \
+ $$PWD/shaders/sprite_core.vert \
+ $$PWD/shaders/sprite_core.frag \
+ $$PWD/shaders/shadereffect_core.vert \
+ $$PWD/shaders/shadereffect_core.frag \
+ $$PWD/shaders/shadereffectfallback_core.vert \
+ $$PWD/shaders/shadereffectfallback_core.frag
+}
RESOURCES += \
$$PWD/items.qrc
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp
index ab5170cd65..6f14bf15fe 100644
--- a/src/quick/items/qquickanimatedimage.cpp
+++ b/src/quick/items/qquickanimatedimage.cpp
@@ -47,8 +47,10 @@
#include <QtQml/qqmlfile.h>
#include <QtQml/qqmlengine.h>
#include <QtGui/qmovie.h>
+#ifndef QT_NO_NETWORK
#include <QtNetwork/qnetworkrequest.h>
#include <QtNetwork/qnetworkreply.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -144,8 +146,10 @@ QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
QQuickAnimatedImage::~QQuickAnimatedImage()
{
Q_D(QQuickAnimatedImage);
+#ifndef QT_NO_NETWORK
if (d->reply)
d->reply->deleteLater();
+#endif
delete d->_movie;
qDeleteAll(d->frameMap);
d->frameMap.clear();
@@ -264,10 +268,12 @@ void QQuickAnimatedImage::setSource(const QUrl &url)
if (url == d->url)
return;
+#ifndef QT_NO_NETWORK
if (d->reply) {
d->reply->deleteLater();
d->reply = 0;
}
+#endif
d->setImage(QImage());
qDeleteAll(d->frameMap);
@@ -319,6 +325,7 @@ void QQuickAnimatedImage::load()
d->_movie = new QMovie(lf);
movieRequestFinished();
} else {
+#ifndef QT_NO_NETWORK
if (d->status != Loading) {
d->status = Loading;
emit statusChanged(d->status);
@@ -335,6 +342,7 @@ void QQuickAnimatedImage::load()
this, SLOT(movieRequestFinished()));
QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(requestProgress(qint64,qint64)));
+#endif
}
}
}
@@ -343,8 +351,10 @@ void QQuickAnimatedImage::load()
void QQuickAnimatedImage::movieRequestFinished()
{
+
Q_D(QQuickAnimatedImage);
+#ifndef QT_NO_NETWORK
if (d->reply) {
d->redirectCount++;
if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) {
@@ -360,6 +370,7 @@ void QQuickAnimatedImage::movieRequestFinished()
d->redirectCount=0;
d->_movie = new QMovie(d->reply);
}
+#endif
if (!d->_movie->isValid()) {
qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString();
diff --git a/src/quick/items/qquickanimatedimage_p_p.h b/src/quick/items/qquickanimatedimage_p_p.h
index 6d32f1071f..ed735d1c9c 100644
--- a/src/quick/items/qquickanimatedimage_p_p.h
+++ b/src/quick/items/qquickanimatedimage_p_p.h
@@ -58,7 +58,9 @@
QT_BEGIN_NAMESPACE
class QMovie;
+#ifndef QT_NO_NETWORK
class QNetworkReply;
+#endif
class QQuickAnimatedImagePrivate : public QQuickImagePrivate
{
@@ -66,7 +68,11 @@ class QQuickAnimatedImagePrivate : public QQuickImagePrivate
public:
QQuickAnimatedImagePrivate()
- : playing(true), paused(false), preset_currentframe(0), _movie(0), reply(0), redirectCount(0), oldPlaying(false), currentSourceSize(0, 0)
+ : playing(true), paused(false), preset_currentframe(0), _movie(0), oldPlaying(false)
+#ifndef QT_NO_NETWORK
+ , reply(0), redirectCount(0)
+#endif
+ , currentSourceSize(0, 0)
{
}
@@ -76,9 +82,11 @@ public:
bool paused;
int preset_currentframe;
QMovie *_movie;
+ bool oldPlaying;
+#ifndef QT_NO_NETWORK
QNetworkReply *reply;
int redirectCount;
- bool oldPlaying;
+#endif
QMap<int, QQuickPixmap *> frameMap;
QSize currentSourceSize;
};
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index 66f414d816..b3a35e6219 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -43,7 +43,9 @@
#include <QtQml/qqmlinfo.h>
#include <QtQml/qqmlfile.h>
#include <QtQml/qqmlengine.h>
+#ifndef QT_NO_NETWORK
#include <QtNetwork/qnetworkreply.h>
+#endif
#include <QtCore/qfile.h>
#include <QtCore/qmath.h>
#include <QtGui/qguiapplication.h>
@@ -169,9 +171,11 @@ QQuickBorderImage::QQuickBorderImage(QQuickItem *parent)
QQuickBorderImage::~QQuickBorderImage()
{
+#ifndef QT_NO_NETWORK
Q_D(QQuickBorderImage);
if (d->sciReply)
d->sciReply->deleteLater();
+#endif
}
/*!
@@ -270,10 +274,12 @@ void QQuickBorderImage::setSource(const QUrl &url)
if (url == d->url)
return;
+#ifndef QT_NO_NETWORK
if (d->sciReply) {
d->sciReply->deleteLater();
d->sciReply = 0;
}
+#endif
d->url = url;
d->sciurl = QUrl();
@@ -311,6 +317,7 @@ void QQuickBorderImage::load()
setGridScaledImage(QQuickGridScaledImage(&file));
return;
} else {
+#ifndef QT_NO_NETWORK
if (d->progress != 0.0) {
d->progress = 0.0;
emit progressChanged(d->progress);
@@ -320,6 +327,7 @@ void QQuickBorderImage::load()
d->sciReply = qmlEngine(this)->networkAccessManager()->get(req);
qmlobject_connect(d->sciReply, QNetworkReply, SIGNAL(finished()),
this, QQuickBorderImage, SLOT(sciRequestFinished()))
+#endif
}
} else {
QQuickPixmap::Options options;
@@ -529,6 +537,7 @@ void QQuickBorderImage::requestFinished()
pixmapChange();
}
+#ifndef QT_NO_NETWORK
#define BORDERIMAGE_MAX_REDIRECT 16
void QQuickBorderImage::sciRequestFinished()
@@ -558,12 +567,59 @@ void QQuickBorderImage::sciRequestFinished()
setGridScaledImage(sci);
}
}
+#endif // QT_NO_NETWORK
void QQuickBorderImage::doUpdate()
{
update();
}
+void QQuickBorderImagePrivate::calculateRects(const QQuickScaleGrid *border,
+ const QSize &sourceSize,
+ const QSizeF &targetSize,
+ int horizontalTileMode,
+ int verticalTileMode,
+ qreal devicePixelRatio,
+ QRectF *targetRect,
+ QRectF *innerTargetRect,
+ QRectF *innerSourceRect,
+ QRectF *subSourceRect)
+{
+ *innerSourceRect = QRectF(0, 0, 1, 1);
+ *targetRect = QRectF(0, 0, targetSize.width(), targetSize.height());
+ *innerTargetRect = *targetRect;
+
+ if (border) {
+ *innerSourceRect = QRectF(border->left() * devicePixelRatio / qreal(sourceSize.width()),
+ border->top() * devicePixelRatio / qreal(sourceSize.height()),
+ qMax<qreal>(0, sourceSize.width() - (border->right() + border->left()) * devicePixelRatio) / sourceSize.width(),
+ qMax<qreal>(0, sourceSize.height() - (border->bottom() + border->top()) * devicePixelRatio) / sourceSize.height());
+ *innerTargetRect = QRectF(border->left(),
+ border->top(),
+ qMax<qreal>(0, targetSize.width() - (border->right() + border->left())),
+ qMax<qreal>(0, targetSize.height() - (border->bottom() + border->top())));
+ }
+
+ qreal hTiles = 1;
+ qreal vTiles = 1;
+ const QSizeF innerTargetSize = innerTargetRect->size() * devicePixelRatio;
+ if (innerSourceRect->width() != 0
+ && horizontalTileMode != QQuickBorderImage::Stretch) {
+ hTiles = innerTargetSize.width() / qreal(innerSourceRect->width() * sourceSize.width());
+ if (horizontalTileMode == QQuickBorderImage::Round)
+ hTiles = qCeil(hTiles);
+ }
+ if (innerSourceRect->height() != 0
+ && verticalTileMode != QQuickBorderImage::Stretch) {
+ vTiles = innerTargetSize.height() / qreal(innerSourceRect->height() * sourceSize.height());
+ if (verticalTileMode == QQuickBorderImage::Round)
+ vTiles = qCeil(vTiles);
+ }
+
+ *subSourceRect = QRectF(0, 0, hTiles, vTiles);
+}
+
+
QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
Q_D(QQuickBorderImage);
@@ -588,45 +644,25 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
node->setTexture(texture);
// Don't implicitly create the scalegrid in the rendering thread...
- QRectF innerSourceRect(0, 0, 1, 1);
- QRectF targetRect(0, 0, width(), height());
- QRectF innerTargetRect = targetRect;
- if (d->border) {
- const QQuickScaleGrid *border = d->getScaleGrid();
- innerSourceRect = QRectF(border->left() * d->devicePixelRatio / qreal(d->pix.width()),
- border->top() * d->devicePixelRatio / qreal(d->pix.height()),
- qMax<qreal>(0, d->pix.width() - (border->right() + border->left()) * d->devicePixelRatio) / d->pix.width(),
- qMax<qreal>(0, d->pix.height() - (border->bottom() + border->top()) * d->devicePixelRatio) / d->pix.height());
- innerTargetRect = QRectF(border->left(),
- border->top(),
- qMax<qreal>(0, width() - (border->right() + border->left())),
- qMax<qreal>(0, height() - (border->bottom() + border->top())));
- }
- qreal hTiles = 1;
- qreal vTiles = 1;
- const QSizeF innerTargetSize = innerTargetRect.size() * d->devicePixelRatio;
- if (innerSourceRect.width() != 0
- && d->horizontalTileMode != QQuickBorderImage::Stretch) {
- hTiles = innerTargetSize.width() / qreal(innerSourceRect.width() * d->pix.width());
- if (d->horizontalTileMode == QQuickBorderImage::Round)
- hTiles = qCeil(hTiles);
- }
- if (innerSourceRect.height() != 0
- && d->verticalTileMode != QQuickBorderImage::Stretch) {
- vTiles = innerTargetSize.height() / qreal(innerSourceRect.height() * d->pix.height());
- if (d->verticalTileMode == QQuickBorderImage::Round)
- vTiles = qCeil(vTiles);
- }
+ QRectF targetRect;
+ QRectF innerTargetRect;
+ QRectF innerSourceRect;
+ QRectF subSourceRect;
+ d->calculateRects(d->border,
+ QSize(d->pix.width(), d->pix.height()), QSizeF(width(), height()),
+ d->horizontalTileMode, d->verticalTileMode, d->devicePixelRatio,
+ &targetRect, &innerTargetRect,
+ &innerSourceRect, &subSourceRect);
node->setTargetRect(targetRect);
node->setInnerSourceRect(innerSourceRect);
node->setInnerTargetRect(innerTargetRect);
- node->setSubSourceRect(QRectF(0, 0, hTiles, vTiles));
+ node->setSubSourceRect(subSourceRect);
node->setMirror(d->mirror);
node->setMipmapFiltering(QSGTexture::None);
node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
- if (innerSourceRect == QRectF(0, 0, 1, 1) && (vTiles > 1 || hTiles > 1)) {
+ if (innerSourceRect == QRectF(0, 0, 1, 1) && (subSourceRect.width() > 1 || subSourceRect.height() > 1)) {
node->setHorizontalWrapMode(QSGTexture::Repeat);
node->setVerticalWrapMode(QSGTexture::Repeat);
} else {
diff --git a/src/quick/items/qquickborderimage_p.h b/src/quick/items/qquickborderimage_p.h
index 7f8b172a21..f2764660f6 100644
--- a/src/quick/items/qquickborderimage_p.h
+++ b/src/quick/items/qquickborderimage_p.h
@@ -101,7 +101,9 @@ private:
private Q_SLOTS:
void doUpdate();
void requestFinished() Q_DECL_OVERRIDE;
+#ifndef QT_NO_NETWORK
void sciRequestFinished();
+#endif
private:
Q_DISABLE_COPY(QQuickBorderImage)
diff --git a/src/quick/items/qquickborderimage_p_p.h b/src/quick/items/qquickborderimage_p_p.h
index 478de88a52..56fbbab049 100644
--- a/src/quick/items/qquickborderimage_p_p.h
+++ b/src/quick/items/qquickborderimage_p_p.h
@@ -58,17 +58,20 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_NETWORK
class QNetworkReply;
+#endif
class QQuickBorderImagePrivate : public QQuickImageBasePrivate
{
Q_DECLARE_PUBLIC(QQuickBorderImage)
public:
QQuickBorderImagePrivate()
- : border(0), sciReply(0),
- horizontalTileMode(QQuickBorderImage::Stretch),
- verticalTileMode(QQuickBorderImage::Stretch),
- redirectCount(0), pixmapChanged(false)
+ : border(0), horizontalTileMode(QQuickBorderImage::Stretch),
+ verticalTileMode(QQuickBorderImage::Stretch), pixmapChanged(false)
+#ifndef QT_NO_NETWORK
+ , sciReply(0), redirectCount(0)
+#endif
{
}
@@ -88,14 +91,27 @@ public:
return border;
}
+ static void calculateRects(const QQuickScaleGrid *border,
+ const QSize &sourceSize,
+ const QSizeF &targetSize,
+ int horizontalTileMode,
+ int verticalTileMode,
+ qreal devicePixelRatio,
+ QRectF *targetRect,
+ QRectF *innerTargetRect,
+ QRectF *innerSourceRect,
+ QRectF *subSourceRect);
+
QQuickScaleGrid *border;
QUrl sciurl;
- QNetworkReply *sciReply;
QQuickBorderImage::TileMode horizontalTileMode;
QQuickBorderImage::TileMode verticalTileMode;
- int redirectCount;
-
bool pixmapChanged : 1;
+
+#ifndef QT_NO_NETWORK
+ QNetworkReply *sciReply;
+ int redirectCount;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index 9a24d7a8a0..cc30199253 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -45,6 +45,7 @@
#include <private/qquickitem_p.h>
#include <QtQuick/private/qquickevents_p_p.h>
#include <private/qquickitemchangelistener_p.h>
+#include <private/qquickpixmapcache_p.h>
#include <private/qv8engine_p.h>
#include <private/qv4scopedvalue_p.h>
#include <QtCore/qmimedata.h>
@@ -110,6 +111,8 @@ public:
bool eventQueued : 1;
bool overrideActions : 1;
QPointF hotSpot;
+ QUrl imageSource;
+ QQuickPixmap pixmapLoader;
QStringList keys;
QVariantMap externalMimeData;
QQuickDrag::DragType dragType;
@@ -409,6 +412,43 @@ void QQuickDragAttached::setHotSpot(const QPointF &hotSpot)
}
/*!
+ \qmlattachedproperty QUrl QtQuick::Drag::imageSource
+ \since 5.8
+
+ This property holds the URL of the image which will be used to represent
+ the data during the drag and drop operation. Changing this property after
+ the drag operation has started will have no effect.
+
+ The example below uses an item's contents as a drag image:
+
+ \snippet qml/externaldrag.qml 0
+
+ \sa Item::grabToImage()
+*/
+
+QUrl QQuickDragAttached::imageSource() const
+{
+ Q_D(const QQuickDragAttached);
+ return d->imageSource;
+}
+
+void QQuickDragAttached::setImageSource(const QUrl &url)
+{
+ Q_D(QQuickDragAttached);
+ if (d->imageSource != url) {
+ d->imageSource = url;
+
+ if (url.isEmpty()) {
+ d->pixmapLoader.clear();
+ } else {
+ d->pixmapLoader.load(qmlEngine(this), url);
+ }
+
+ Q_EMIT imageSourceChanged();
+ }
+}
+
+/*!
\qmlattachedproperty stringlist QtQuick::Drag::keys
This property holds a list of keys that can be used by a DropArea to filter drag events.
@@ -727,9 +767,9 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct
mimeData->setData(it.key(), it.value().toString().toUtf8());
drag->setMimeData(mimeData);
-
- // TODO: how to handle drag image?
- // drag->setPixmap(iconPixmap);
+ if (pixmapLoader.isReady()) {
+ drag->setPixmap(QPixmap::fromImage(pixmapLoader.image()));
+ }
emit q->dragStarted();
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index c1695e49f0..17721251d9 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -58,6 +58,7 @@
#include <QtCore/qmimedata.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qurl.h>
#ifndef QT_NO_DRAGANDDROP
@@ -247,6 +248,7 @@ class QQuickDragAttached : public QObject
Q_PROPERTY(QObject *source READ source WRITE setSource NOTIFY sourceChanged RESET resetSource)
Q_PROPERTY(QObject *target READ target NOTIFY targetChanged)
Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot NOTIFY hotSpotChanged)
+ Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged REVISION 8)
Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged)
Q_PROPERTY(QVariantMap mimeData READ mimeData WRITE setMimeData NOTIFY mimeDataChanged)
Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged)
@@ -268,6 +270,9 @@ public:
QPointF hotSpot() const;
void setHotSpot(const QPointF &hotSpot);
+ QUrl imageSource() const;
+ void setImageSource(const QUrl &url);
+
QStringList keys() const;
void setKeys(const QStringList &keys);
@@ -300,6 +305,7 @@ Q_SIGNALS:
void sourceChanged();
void targetChanged();
void hotSpotChanged();
+ void imageSourceChanged();
void keysChanged();
void mimeDataChanged();
void supportedActionsChanged();
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 5061c19f1e..14c0adf393 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -415,4 +415,26 @@ Item {
\endqml
*/
+/*!
+ \qmlproperty int QtQuick::WheelEvent::inverted
+
+ Returns whether the delta values delivered with the event are inverted.
+
+ Normally, a vertical wheel will produce a WheelEvent with positive delta
+ values if the top of the wheel is rotating away from the hand operating it.
+ Similarly, a horizontal wheel movement will produce a QWheelEvent with
+ positive delta values if the top of the wheel is moved to the left.
+
+ However, on some platforms this is configurable, so that the same
+ operations described above will produce negative delta values (but with the
+ same magnitude). For instance, in a QML component (such as a tumbler or a
+ slider) where it is appropriate to synchronize the movement or rotation of
+ an item with the direction of the wheel, regardless of the system settings,
+ the wheel event handler can use the inverted property to decide whether to
+ negate the angleDelta or pixelDelta values.
+
+ \note Many platforms provide no such information. On such platforms
+ \l inverted always returns false.
+*/
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index b28ab555b0..6d4b49b3cd 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -73,10 +73,22 @@ class QQuickKeyEvent : public QObject
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public:
- QQuickKeyEvent(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, const QString &text=QString(), bool autorep=false, ushort count=1)
- : event(type, key, modifiers, text, autorep, count) { event.setAccepted(false); }
- QQuickKeyEvent(const QKeyEvent &ke)
- : event(ke) { event.setAccepted(false); }
+ QQuickKeyEvent()
+ : event(QEvent::None, 0, 0)
+ {}
+
+ void reset(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
+ const QString &text = QString(), bool autorep = false, ushort count = 1)
+ {
+ event = QKeyEvent(type, key, modifiers, text, autorep, count);
+ event.setAccepted(false);
+ }
+
+ void reset(const QKeyEvent &ke)
+ {
+ event = ke;
+ event.setAccepted(false);
+ }
int key() const { return event.key(); }
QString text() const { return event.text(); }
@@ -109,10 +121,21 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public:
- QQuickMouseEvent(qreal x, qreal y, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers
- , bool isClick=false, bool wasHeld=false)
- : _x(x), _y(y), _button(button), _buttons(buttons), _modifiers(modifiers)
- , _source(Qt::MouseEventNotSynthesized), _wasHeld(wasHeld), _isClick(isClick), _accepted(true) {}
+ QQuickMouseEvent() {}
+
+ void reset(qreal x, qreal y, Qt::MouseButton button, Qt::MouseButtons buttons,
+ Qt::KeyboardModifiers modifiers, bool isClick = false, bool wasHeld = false)
+ {
+ _x = x;
+ _y = y;
+ _button = button;
+ _buttons = buttons;
+ _modifiers = modifiers;
+ _source = Qt::MouseEventNotSynthesized;
+ _wasHeld = wasHeld;
+ _isClick = isClick;
+ _accepted = true;
+ }
qreal x() const { return _x; }
qreal y() const { return _y; }
@@ -139,9 +162,9 @@ private:
Qt::MouseButtons _buttons;
Qt::KeyboardModifiers _modifiers;
Qt::MouseEventSource _source;
- bool _wasHeld;
- bool _isClick;
- bool _accepted;
+ bool _wasHeld : 1;
+ bool _isClick : 1;
+ bool _accepted : 1;
};
class QQuickWheelEvent : public QObject
@@ -153,13 +176,24 @@ class QQuickWheelEvent : public QObject
Q_PROPERTY(QPoint pixelDelta READ pixelDelta)
Q_PROPERTY(int buttons READ buttons)
Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool inverted READ inverted)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
public:
- QQuickWheelEvent(qreal x, qreal y, const QPoint& angleDelta, const QPoint& pixelDelta,
- Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
- : _x(x), _y(y), _angleDelta(angleDelta), _pixelDelta(pixelDelta), _buttons(buttons),
- _modifiers(modifiers), _accepted(true) {}
+ QQuickWheelEvent() {}
+
+ void reset(qreal x, qreal y, const QPoint &angleDelta, const QPoint &pixelDelta,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, bool inverted)
+ {
+ _x = x;
+ _y = y;
+ _angleDelta = angleDelta;
+ _pixelDelta = pixelDelta;
+ _buttons = buttons;
+ _modifiers = modifiers;
+ _accepted = true;
+ _inverted = inverted;
+ }
qreal x() const { return _x; }
qreal y() const { return _y; }
@@ -167,7 +201,7 @@ public:
QPoint pixelDelta() const { return _pixelDelta; }
int buttons() const { return _buttons; }
int modifiers() const { return _modifiers; }
-
+ bool inverted() const { return _inverted; }
bool isAccepted() { return _accepted; }
void setAccepted(bool accepted) { _accepted = accepted; }
@@ -178,6 +212,7 @@ private:
QPoint _pixelDelta;
Qt::MouseButtons _buttons;
Qt::KeyboardModifiers _modifiers;
+ bool _inverted;
bool _accepted;
};
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 3c59b19ec2..3d2b32286f 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -62,6 +62,7 @@
#include <private/qquicktimeline_p_p.h>
#include <private/qquickanimation_p_p.h>
#include <private/qquicktransitionmanager_p_p.h>
+#include <private/qpodvector_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index 0356b72e1d..d8147a48a5 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -40,7 +40,7 @@
#include "qquickframebufferobject.h"
#include <QtGui/QOpenGLFramebufferObject>
-
+#include <QtGui/QOpenGLFunctions>
#include <private/qquickitem_p.h>
#include <QSGSimpleTextureNode>
diff --git a/src/quick/items/qquickgenericshadereffect.cpp b/src/quick/items/qquickgenericshadereffect.cpp
new file mode 100644
index 0000000000..47272a2eac
--- /dev/null
+++ b/src/quick/items/qquickgenericshadereffect.cpp
@@ -0,0 +1,609 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qquickgenericshadereffect_p.h>
+#include <private/qquickwindow_p.h>
+#include <private/qquickitem_p.h>
+#include <QSignalMapper>
+
+QT_BEGIN_NAMESPACE
+
+// The generic shader effect is used when the scenegraph backend indicates
+// SupportsShaderEffectNode. This, unlike the monolithic and interconnected (e.g.
+// with particles) OpenGL variant, passes most of the work to a scenegraph node
+// created via the adaptation layer, thus allowing different implementation in
+// the backends.
+
+QQuickGenericShaderEffect::QQuickGenericShaderEffect(QQuickShaderEffect *item, QObject *parent)
+ : QObject(parent)
+ , m_item(item)
+ , m_meshResolution(1, 1)
+ , m_mesh(nullptr)
+ , m_cullMode(QQuickShaderEffect::NoCulling)
+ , m_blending(true)
+ , m_supportsAtlasTextures(false)
+ , m_mgr(nullptr)
+ , m_dirty(0)
+{
+ connect(m_item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(itemWindowChanged(QQuickWindow*)));
+}
+
+QQuickGenericShaderEffect::~QQuickGenericShaderEffect()
+{
+ for (int i = 0; i < NShader; ++i) {
+ disconnectSignals(Shader(i));
+ for (const auto &sm : qAsConst(m_signalMappers[i]))
+ delete sm.mapper;
+ }
+
+ delete m_mgr;
+}
+
+void QQuickGenericShaderEffect::setFragmentShader(const QByteArray &src)
+{
+ // Compare the actual values since they are often just filenames.
+ // Optimizing by comparing constData() is a bad idea since seemingly static
+ // strings in QML may in fact have different addresses when a binding
+ // triggers assigning the "same" value to the property.
+ if (m_fragShader == src)
+ return;
+
+ m_fragShader = src;
+ m_dirty |= QSGShaderEffectNode::DirtyShaders;
+
+ if (m_item->isComponentComplete())
+ updateShader(Fragment, src);
+
+ m_item->update();
+ emit m_item->fragmentShaderChanged();
+}
+
+void QQuickGenericShaderEffect::setVertexShader(const QByteArray &src)
+{
+ if (m_vertShader == src)
+ return;
+
+ m_vertShader = src;
+ m_dirty |= QSGShaderEffectNode::DirtyShaders;
+
+ if (m_item->isComponentComplete())
+ updateShader(Vertex, src);
+
+ m_item->update();
+ emit m_item->vertexShaderChanged();
+}
+
+void QQuickGenericShaderEffect::setBlending(bool enable)
+{
+ if (m_blending == enable)
+ return;
+
+ m_blending = enable;
+ m_item->update();
+ emit m_item->blendingChanged();
+}
+
+QVariant QQuickGenericShaderEffect::mesh() const
+{
+ return m_mesh ? qVariantFromValue(static_cast<QObject *>(m_mesh))
+ : qVariantFromValue(m_meshResolution);
+}
+
+void QQuickGenericShaderEffect::setMesh(const QVariant &mesh)
+{
+ QQuickShaderEffectMesh *newMesh = qobject_cast<QQuickShaderEffectMesh *>(qvariant_cast<QObject *>(mesh));
+ if (newMesh && newMesh == m_mesh)
+ return;
+
+ if (m_mesh)
+ disconnect(m_mesh, SIGNAL(geometryChanged()), this, 0);
+
+ m_mesh = newMesh;
+
+ if (m_mesh) {
+ connect(m_mesh, SIGNAL(geometryChanged()), this, SLOT(markGeometryDirtyAndUpdate()));
+ } else {
+ if (mesh.canConvert<QSize>()) {
+ m_meshResolution = mesh.toSize();
+ } else {
+ QList<QByteArray> res = mesh.toByteArray().split('x');
+ bool ok = res.size() == 2;
+ if (ok) {
+ int w = res.at(0).toInt(&ok);
+ if (ok) {
+ int h = res.at(1).toInt(&ok);
+ if (ok)
+ m_meshResolution = QSize(w, h);
+ }
+ }
+ if (!ok)
+ qWarning("ShaderEffect: mesh property must be a size or an object deriving from QQuickShaderEffectMesh");
+ }
+ m_defaultMesh.setResolution(m_meshResolution);
+ }
+
+ m_dirty |= QSGShaderEffectNode::DirtyShaderMesh;
+ m_item->update();
+
+ emit m_item->meshChanged();
+}
+
+void QQuickGenericShaderEffect::setCullMode(QQuickShaderEffect::CullMode face)
+{
+ if (m_cullMode == face)
+ return;
+
+ m_cullMode = face;
+ m_item->update();
+ emit m_item->cullModeChanged();
+}
+
+void QQuickGenericShaderEffect::setSupportsAtlasTextures(bool supports)
+{
+ if (m_supportsAtlasTextures == supports)
+ return;
+
+ m_supportsAtlasTextures = supports;
+ markGeometryDirtyAndUpdate();
+ emit m_item->supportsAtlasTexturesChanged();
+}
+
+QString QQuickGenericShaderEffect::log() const
+{
+ QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
+ if (!mgr)
+ return QString();
+
+ return mgr->log();
+}
+
+QQuickShaderEffect::Status QQuickGenericShaderEffect::status() const
+{
+ QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
+ if (!mgr)
+ return QQuickShaderEffect::Uncompiled;
+
+ return QQuickShaderEffect::Status(mgr->status());
+}
+
+void QQuickGenericShaderEffect::handleEvent(QEvent *event)
+{
+ if (event->type() == QEvent::DynamicPropertyChange) {
+ QDynamicPropertyChangeEvent *e = static_cast<QDynamicPropertyChangeEvent *>(event);
+ for (int shaderType = 0; shaderType < NShader; ++shaderType) {
+ const auto &vars(m_shaders[shaderType].shaderInfo.variables);
+ for (int idx = 0; idx < vars.count(); ++idx) {
+ if (vars[idx].name == e->propertyName()) {
+ propertyChanged((shaderType << 16) | idx);
+ break;
+ }
+ }
+ }
+ }
+}
+
+void QQuickGenericShaderEffect::handleGeometryChanged(const QRectF &, const QRectF &)
+{
+ m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
+}
+
+QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+{
+ QSGShaderEffectNode *node = static_cast<QSGShaderEffectNode *>(oldNode);
+
+ if (m_item->width() <= 0 || m_item->height() <= 0) {
+ delete node;
+ return nullptr;
+ }
+
+ // The manager should be already created on the gui thread. Just take that instance.
+ QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
+ if (!mgr) {
+ delete node;
+ return nullptr;
+ }
+
+ if (!node) {
+ QSGRenderContext *rc = QQuickWindowPrivate::get(m_item->window())->context;
+ node = rc->sceneGraphContext()->createShaderEffectNode(rc, mgr);
+ m_dirty = QSGShaderEffectNode::DirtyShaderAll;
+ }
+
+ QSGShaderEffectNode::SyncData sd;
+ sd.dirty = m_dirty;
+ sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode);
+ sd.blending = m_blending;
+ sd.vertex.shader = &m_shaders[Vertex];
+ sd.vertex.dirtyConstants = &m_dirtyConstants[Vertex];
+ sd.vertex.dirtyTextures = &m_dirtyTextures[Vertex];
+ sd.fragment.shader = &m_shaders[Fragment];
+ sd.fragment.dirtyConstants = &m_dirtyConstants[Fragment];
+ sd.fragment.dirtyTextures = &m_dirtyTextures[Fragment];
+ node->syncMaterial(&sd);
+
+ if (m_dirty & QSGShaderEffectNode::DirtyShaderMesh) {
+ node->setGeometry(nullptr);
+ m_dirty &= ~QSGShaderEffectNode::DirtyShaderMesh;
+ m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
+ }
+
+ if (m_dirty & QSGShaderEffectNode::DirtyShaderGeometry) {
+ const QRectF rect(0, 0, m_item->width(), m_item->height());
+ QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
+ QSGGeometry *geometry = node->geometry();
+
+ const QRectF srcRect = node->updateNormalizedTextureSubRect(m_supportsAtlasTextures);
+ geometry = mesh->updateGeometry(geometry, 2, 0, srcRect, rect);
+
+ node->setFlag(QSGNode::OwnsGeometry, false);
+ node->setGeometry(geometry);
+ node->setFlag(QSGNode::OwnsGeometry, true);
+
+ m_dirty &= ~QSGShaderEffectNode::DirtyShaderGeometry;
+ }
+
+ m_dirty = 0;
+ for (int i = 0; i < NShader; ++i) {
+ m_dirtyConstants[i].clear();
+ m_dirtyTextures[i].clear();
+ }
+
+ return node;
+}
+
+void QQuickGenericShaderEffect::handleComponentComplete()
+{
+ updateShader(Vertex, m_vertShader);
+ updateShader(Fragment, m_fragShader);
+}
+
+void QQuickGenericShaderEffect::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
+{
+ // Move the window ref.
+ if (change == QQuickItem::ItemSceneChange) {
+ for (int shaderType = 0; shaderType < NShader; ++shaderType) {
+ for (const auto &vd : qAsConst(m_shaders[shaderType].varData)) {
+ if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
+ if (source) {
+ if (value.window)
+ QQuickItemPrivate::get(source)->refWindow(value.window);
+ else
+ QQuickItemPrivate::get(source)->derefWindow();
+ }
+ }
+ }
+ }
+ }
+}
+
+QSGGuiThreadShaderEffectManager *QQuickGenericShaderEffect::shaderEffectManager() const
+{
+ if (!m_mgr) {
+ // return null if this is not the gui thread and not already created
+ if (QThread::currentThread() != m_item->thread())
+ return m_mgr;
+ // need a window and a rendercontext (i.e. the scenegraph backend is ready)
+ QQuickWindow *w = m_item->window();
+ if (w && w->isSceneGraphInitialized()) {
+ m_mgr = QQuickWindowPrivate::get(w)->context->sceneGraphContext()->createGuiThreadShaderEffectManager();
+ if (m_mgr) {
+ connect(m_mgr, SIGNAL(logAndStatusChanged()), m_item, SIGNAL(logChanged()));
+ connect(m_mgr, SIGNAL(logAndStatusChanged()), m_item, SIGNAL(statusChanged()));
+ connect(m_mgr, SIGNAL(textureChanged()), this, SLOT(markGeometryDirtyAndUpdateIfSupportsAtlas()));
+ }
+ } else if (!w) {
+ // Wait until itemWindowChanged() gets called. Return null for now.
+ } else {
+ // Have window, but no scenegraph -> ensure the signal is connected. Return null for now.
+ const_cast<QQuickGenericShaderEffect *>(this)->itemWindowChanged(w);
+ }
+ }
+
+ return m_mgr;
+}
+
+void QQuickGenericShaderEffect::itemWindowChanged(QQuickWindow *w)
+{
+ if (w) {
+ if (w->isSceneGraphInitialized())
+ backendChanged();
+ else
+ connect(w, SIGNAL(sceneGraphInitialized()), this, SLOT(backendChanged()), Qt::UniqueConnection);
+ }
+}
+
+void QQuickGenericShaderEffect::backendChanged()
+{
+ disconnect(m_item->window(), SIGNAL(sceneGraphInitialized()), this, SLOT(backendChanged()));
+ emit m_item->logChanged();
+ emit m_item->statusChanged();
+}
+
+void QQuickGenericShaderEffect::disconnectSignals(Shader shaderType)
+{
+ for (auto &sm : m_signalMappers[shaderType]) {
+ if (sm.active) {
+ sm.active = false;
+ QObject::disconnect(m_item, nullptr, sm.mapper, SLOT(map()));
+ QObject::disconnect(sm.mapper, SIGNAL(mapped(int)), this, SLOT(propertyChanged(int)));
+ }
+ }
+ for (const auto &vd : qAsConst(m_shaders[shaderType].varData)) {
+ if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
+ if (source) {
+ if (m_item->window())
+ QQuickItemPrivate::get(source)->derefWindow();
+ QObject::disconnect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
+ }
+ }
+ }
+}
+
+struct ReflectCache
+{
+ bool contains(const QByteArray &key) const
+ {
+ return m_reflectCache.contains(key);
+ }
+
+ QSGGuiThreadShaderEffectManager::ShaderInfo value(const QByteArray &key) const
+ {
+ return m_reflectCache.value(key);
+ }
+
+ void insert(const QByteArray &key, const QSGGuiThreadShaderEffectManager::ShaderInfo &value)
+ {
+ m_reflectCache.insert(key, value);
+ }
+
+ QHash<QByteArray, QSGGuiThreadShaderEffectManager::ShaderInfo> m_reflectCache;
+};
+
+Q_GLOBAL_STATIC(ReflectCache, reflectCache)
+
+void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray &src)
+{
+ QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
+ if (!mgr)
+ return;
+
+ const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
+
+ disconnectSignals(shaderType);
+
+ m_shaders[shaderType].shaderInfo = QSGGuiThreadShaderEffectManager::ShaderInfo();
+ m_shaders[shaderType].varData.clear();
+
+ if (!src.isEmpty()) {
+ // Figure out what input parameters and variables are used in the shader.
+ // For file-based shader source/bytecode this is where the data is pulled
+ // in from the file.
+ if (reflectCache()->contains(src)) {
+ m_shaders[shaderType].shaderInfo = reflectCache()->value(src);
+ } else {
+ QSGGuiThreadShaderEffectManager::ShaderInfo shaderInfo;
+ if (!mgr->reflect(src, &shaderInfo)) {
+ qWarning("ShaderEffect: shader reflection failed for %s", src.constData());
+ m_shaders[shaderType].hasShaderCode = false;
+ return;
+ }
+ m_shaders[shaderType].shaderInfo = shaderInfo;
+ reflectCache()->insert(src, shaderInfo);
+ }
+ m_shaders[shaderType].hasShaderCode = true;
+ } else {
+ m_shaders[shaderType].hasShaderCode = false;
+ if (shaderType == Fragment) {
+ // With built-in shaders hasShaderCode is set to false and all
+ // metadata is empty, as it is left up to the node to provide a
+ // built-in default shader and its metadata. However, in case of
+ // the built-in fragment shader the value for 'source' has to be
+ // provided and monitored like with an application-provided shader.
+ QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
+ v.name = QByteArrayLiteral("source");
+ v.bindPoint = 0;
+ v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
+ : QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
+ m_shaders[shaderType].shaderInfo.variables.append(v);
+ }
+ }
+
+ const int varCount = m_shaders[shaderType].shaderInfo.variables.count();
+ m_shaders[shaderType].varData.resize(varCount);
+
+ // Reuse signal mappers as much as possible since the mapping is based on
+ // the index and shader type which are both constant.
+ if (m_signalMappers[shaderType].count() < varCount)
+ m_signalMappers[shaderType].resize(varCount);
+
+ // Hook up the signals to get notified about changes for properties that
+ // correspond to variables in the shader. Store also the values.
+ for (int i = 0; i < varCount; ++i) {
+ const auto &v(m_shaders[shaderType].shaderInfo.variables.at(i));
+ QSGShaderEffectNode::VariableData &vd(m_shaders[shaderType].varData[i]);
+ const bool isSpecial = v.name.startsWith("qt_"); // special names not mapped to properties
+ if (isSpecial) {
+ if (v.name == QByteArrayLiteral("qt_Opacity"))
+ vd.specialType = QSGShaderEffectNode::VariableData::Opacity;
+ else if (v.name == QByteArrayLiteral("qt_Matrix"))
+ vd.specialType = QSGShaderEffectNode::VariableData::Matrix;
+ else if (v.name.startsWith("qt_SubRect_"))
+ vd.specialType = QSGShaderEffectNode::VariableData::SubRect;
+ continue;
+ }
+
+ // The value of a property corresponding to a sampler is the source
+ // item ref, unless there are separate texture objects in which case
+ // the sampler is ignored (here).
+ if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
+ if (texturesSeparate) {
+ vd.specialType = QSGShaderEffectNode::VariableData::Unused;
+ continue;
+ } else {
+ vd.specialType = QSGShaderEffectNode::VariableData::Source;
+ }
+ } else if (v.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Texture) {
+ Q_ASSERT(texturesSeparate);
+ vd.specialType = QSGShaderEffectNode::VariableData::Source;
+ } else {
+ vd.specialType = QSGShaderEffectNode::VariableData::None;
+ }
+
+ // Find the property on the ShaderEffect item.
+ const int propIdx = m_item->metaObject()->indexOfProperty(v.name.constData());
+ if (propIdx >= 0) {
+ QMetaProperty mp = m_item->metaObject()->property(propIdx);
+ if (!mp.hasNotifySignal())
+ qWarning("ShaderEffect: property '%s' does not have notification method", v.name.constData());
+
+ // Have a QSignalMapper that emits mapped() with an index+type on each property change notify signal.
+ auto &sm(m_signalMappers[shaderType][i]);
+ if (!sm.mapper) {
+ sm.mapper = new QSignalMapper;
+ sm.mapper->setMapping(m_item, i | (shaderType << 16));
+ }
+ sm.active = true;
+ const QByteArray signalName = '2' + mp.notifySignal().methodSignature();
+ QObject::connect(m_item, signalName, sm.mapper, SLOT(map()));
+ QObject::connect(sm.mapper, SIGNAL(mapped(int)), this, SLOT(propertyChanged(int)));
+ } else {
+ // Do not warn for dynamic properties.
+ if (!m_item->property(v.name.constData()).isValid())
+ qWarning("ShaderEffect: '%s' does not have a matching property!", v.name.constData());
+ }
+
+ vd.value = m_item->property(v.name.constData());
+
+ if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
+ if (source) {
+ if (m_item->window())
+ QQuickItemPrivate::get(source)->refWindow(m_item->window());
+ QObject::connect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
+ }
+ }
+ }
+}
+
+bool QQuickGenericShaderEffect::sourceIsUnique(QQuickItem *source, Shader typeToSkip, int indexToSkip) const
+{
+ for (int shaderType = 0; shaderType < NShader; ++shaderType) {
+ for (int idx = 0; idx < m_shaders[shaderType].varData.count(); ++idx) {
+ if (shaderType != typeToSkip || idx != indexToSkip) {
+ const auto &vd(m_shaders[shaderType].varData[idx]);
+ if (vd.specialType == QSGShaderEffectNode::VariableData::Source && qvariant_cast<QObject *>(vd.value) == source)
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void QQuickGenericShaderEffect::propertyChanged(int mappedId)
+{
+ const Shader type = Shader(mappedId >> 16);
+ const int idx = mappedId & 0xFFFF;
+ const auto &v(m_shaders[type].shaderInfo.variables[idx]);
+ auto &vd(m_shaders[type].varData[idx]);
+
+ if (vd.specialType == QSGShaderEffectNode::VariableData::Source) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
+ if (source) {
+ if (m_item->window())
+ QQuickItemPrivate::get(source)->derefWindow();
+ // QObject::disconnect() will disconnect all matching connections.
+ // If the same source has been attached to two separate
+ // textures/samplers, then changing one of them would trigger both
+ // to be disconnected. So check first.
+ if (sourceIsUnique(source, type, idx))
+ QObject::disconnect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
+ }
+
+ vd.value = m_item->property(v.name.constData());
+
+ source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(vd.value));
+ if (source) {
+ // 'source' needs a window to get a scene graph node. It usually gets one through its
+ // parent, but if the source item is "inline" rather than a reference -- i.e.
+ // "property variant source: Image { }" instead of "property variant source: foo" -- it
+ // will not get a parent. In those cases, 'source' should get the window from 'item'.
+ if (m_item->window())
+ QQuickItemPrivate::get(source)->refWindow(m_item->window());
+ QObject::connect(source, SIGNAL(destroyed(QObject*)), this, SLOT(sourceDestroyed(QObject*)));
+ }
+
+ m_dirty |= QSGShaderEffectNode::DirtyShaderTexture;
+ m_dirtyTextures[type].insert(idx);
+
+ } else {
+ vd.value = m_item->property(v.name.constData());
+ m_dirty |= QSGShaderEffectNode::DirtyShaderConstant;
+ m_dirtyConstants[type].insert(idx);
+ }
+
+ m_item->update();
+}
+
+void QQuickGenericShaderEffect::sourceDestroyed(QObject *object)
+{
+ for (int shaderType = 0; shaderType < NShader; ++shaderType) {
+ for (auto &vd : m_shaders[shaderType].varData) {
+ if (vd.specialType == QSGShaderEffectNode::VariableData::Source && vd.value.canConvert<QObject *>()) {
+ if (qvariant_cast<QObject *>(vd.value) == object)
+ vd.value = QVariant();
+ }
+ }
+ }
+}
+
+void QQuickGenericShaderEffect::markGeometryDirtyAndUpdate()
+{
+ m_dirty |= QSGShaderEffectNode::DirtyShaderGeometry;
+ m_item->update();
+}
+
+void QQuickGenericShaderEffect::markGeometryDirtyAndUpdateIfSupportsAtlas()
+{
+ if (m_supportsAtlasTextures)
+ markGeometryDirtyAndUpdate();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickgenericshadereffect_p.h b/src/quick/items/qquickgenericshadereffect_p.h
new file mode 100644
index 0000000000..ab17a7fb87
--- /dev/null
+++ b/src/quick/items/qquickgenericshadereffect_p.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKGENERICSHADEREFFECT_P_H
+#define QQUICKGENERICSHADEREFFECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/qquickitem.h>
+#include <private/qtquickglobal_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include "qquickshadereffect_p.h"
+#include "qquickshadereffectmesh_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSignalMapper;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickGenericShaderEffect : public QObject
+{
+ Q_OBJECT
+
+public:
+ QQuickGenericShaderEffect(QQuickShaderEffect *item, QObject *parent = 0);
+ ~QQuickGenericShaderEffect();
+
+ QByteArray fragmentShader() const { return m_fragShader; }
+ void setFragmentShader(const QByteArray &src);
+
+ QByteArray vertexShader() const { return m_vertShader; }
+ void setVertexShader(const QByteArray &src);
+
+ bool blending() const { return m_blending; }
+ void setBlending(bool enable);
+
+ QVariant mesh() const;
+ void setMesh(const QVariant &mesh);
+
+ QQuickShaderEffect::CullMode cullMode() const { return m_cullMode; }
+ void setCullMode(QQuickShaderEffect::CullMode face);
+
+ QString log() const;
+ QQuickShaderEffect::Status status() const;
+
+ bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
+ void setSupportsAtlasTextures(bool supports);
+
+ void handleEvent(QEvent *);
+ void handleGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ QSGNode *handleUpdatePaintNode(QSGNode *, QQuickItem::UpdatePaintNodeData *);
+ void handleComponentComplete();
+ void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value);
+
+private slots:
+ void propertyChanged(int mappedId);
+ void sourceDestroyed(QObject *object);
+ void markGeometryDirtyAndUpdate();
+ void markGeometryDirtyAndUpdateIfSupportsAtlas();
+ void itemWindowChanged(QQuickWindow *w);
+ void backendChanged();
+
+private:
+ QSGGuiThreadShaderEffectManager *shaderEffectManager() const;
+
+ enum Shader {
+ Vertex,
+ Fragment,
+
+ NShader
+ };
+ void updateShader(Shader which, const QByteArray &src);
+ void disconnectSignals(Shader which);
+ bool sourceIsUnique(QQuickItem *source, Shader typeToSkip, int indexToSkip) const;
+
+ QQuickShaderEffect *m_item;
+ QSize m_meshResolution;
+ QQuickShaderEffectMesh *m_mesh;
+ QQuickGridMesh m_defaultMesh;
+ QQuickShaderEffect::CullMode m_cullMode;
+ bool m_blending;
+ bool m_supportsAtlasTextures;
+ mutable QSGGuiThreadShaderEffectManager *m_mgr;
+ QByteArray m_fragShader;
+ QByteArray m_vertShader;
+
+ QSGShaderEffectNode::ShaderData m_shaders[NShader];
+ QSGShaderEffectNode::DirtyShaderFlags m_dirty;
+ QSet<int> m_dirtyConstants[NShader];
+ QSet<int> m_dirtyTextures[NShader];
+
+ struct SignalMapper {
+ SignalMapper() : mapper(nullptr), active(false) { }
+ QSignalMapper *mapper;
+ bool active;
+ };
+ QVector<SignalMapper> m_signalMappers[NShader];
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKGENERICSHADEREFFECT_P_H
diff --git a/src/quick/items/qquickgraphicsinfo.cpp b/src/quick/items/qquickgraphicsinfo.cpp
new file mode 100644
index 0000000000..79b0edf031
--- /dev/null
+++ b/src/quick/items/qquickgraphicsinfo.cpp
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickgraphicsinfo_p.h"
+#include "qquickwindow.h"
+#include "qquickitem.h"
+#include <QtGui/qopenglcontext.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype GraphicsInfo
+ \instantiates QQuickGraphicsInfo
+ \inqmlmodule QtQuick
+ \ingroup qtquick-visual
+ \since 5.8
+ \since QtQuick 2.8
+ \brief Provides information about the used Qt Quick backend
+
+ The GraphicsInfo attached type provides information about the scenegraph
+ backend used to render the contents of the associated window.
+
+ If the item to which the properties are attached is not currently
+ associated with any window, the properties are set to default values. When
+ the associated window changes, the properties will update.
+ */
+
+QQuickGraphicsInfo::QQuickGraphicsInfo(QQuickItem *item)
+ : QObject(item)
+ , m_window(0)
+ , m_api(Unknown)
+ , m_shaderType(UnknownShadingLanguage)
+ , m_shaderCompilationType(ShaderCompilationType(0))
+ , m_shaderSourceType(ShaderSourceType(0))
+ , m_majorVersion(2)
+ , m_minorVersion(0)
+ , m_profile(OpenGLNoProfile)
+ , m_renderableType(SurfaceFormatUnspecified)
+{
+ connect(item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(setWindow(QQuickWindow*)));
+ setWindow(item->window());
+}
+
+QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
+{
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(object))
+ return new QQuickGraphicsInfo(item);
+
+ return nullptr;
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::GraphicsInfo::api
+
+ This property describes the graphics API that is currently in use.
+
+ The possible values are:
+ \list
+ \li GraphicsInfo.Unknown - the default value when no active scenegraph is associated with the item
+ \li GraphicsInfo.Software - Qt Quick's software renderer based on QPainter with the raster paint engine
+ \li GraphicsInfo.OpenGL - OpenGL or OpenGL ES
+ \li GraphicsInfo.Direct3D12 - Direct3D 12
+ \endlist
+ */
+
+/*!
+ \qmlproperty enumeration QtQuick::GraphicsInfo::shaderType
+
+ This property contains the shading language supported by the Qt Quick
+ backend the application is using.
+
+ \list
+ \li GraphicsInfo.UnknownShadingLanguage - Not yet known due to no window and scenegraph associated
+ \li GraphicsInfo.GLSL - GLSL or GLSL ES
+ \li GraphicsInfo.HLSL - HLSL
+ \endlist
+
+ \note The value is only up-to-date once the item is associated with a
+ window and the window's scenegraph has initialized. Bindings relying on the
+ value have to keep this in mind since the value may change from
+ GraphicsInfo.UnknownShadingLanguage to the actual value after component
+ initialization is complete. This is particularly relevant for ShaderEffect
+ items inside ShaderEffectSource items set as property values.
+
+ \since 5.8
+ \since QtQuick 2.8
+
+ \sa shaderCompilationType, shaderSourceType
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick::GraphicsInfo::shaderCompilationType
+
+ This property contains a bitmask of the shader compilation approaches
+ supported by the Qt Quick backend the application is using.
+
+ \list
+ \li GraphicsInfo.RuntimeCompilation
+ \li GraphicsInfo.OfflineCompilation
+ \endlist
+
+ With OpenGL the value is GraphicsInfo.RuntimeCompilation, which corresponds
+ to the traditional way of using ShaderEffect. Non-OpenGL backends are
+ expected to focus more on GraphicsInfo.OfflineCompilation, however.
+
+ \note The value is only up-to-date once the item is associated with a
+ window and the window's scenegraph has initialized. Bindings relying on the
+ value have to keep this in mind since the value may change from \c 0 to the
+ actual bitmask after component initialization is complete. This is
+ particularly relevant for ShaderEffect items inside ShaderEffectSource
+ items set as property values.
+
+ \since 5.8
+ \since QtQuick 2.8
+
+ \sa shaderType, shaderSourceType
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick::GraphicsInfo::shaderSourceType
+
+ This property contains a bitmask of the supported ways of providing shader
+ sources.
+
+ \list
+ \li GraphicsInfo.ShaderSourceString
+ \li GraphicsInfo.ShaderSourceFile
+ \li GraphicsInfo.ShaderByteCode
+ \endlist
+
+ With OpenGL the value is GraphicsInfo.ShaderSourceString, which corresponds
+ to the traditional way of inlining GLSL source code into QML. Other,
+ non-OpenGL Qt Quick backends may however decide not to support inlined
+ shader sources, or even shader sources at all. In this case shaders are
+ expected to be pre-compiled into formats like SPIR-V or D3D shader
+ bytecode.
+
+ \note The value is only up-to-date once the item is associated with a
+ window and the window's scenegraph has initialized. Bindings relying on the
+ value have to keep this in mind since the value may change from \c 0 to the
+ actual bitmask after component initialization is complete. This is
+ particularly relevant for ShaderEffect items inside ShaderEffectSource
+ items set as property values.
+
+ \since 5.8
+ \since QtQuick 2.8
+
+ \sa shaderType, shaderCompilationType
+*/
+
+/*!
+ \qmlproperty int QtQuick::GraphicsInfo::majorVersion
+
+ This property holds the major version of the graphics API in use.
+
+ With OpenGL the default version is \c 2.0.
+
+ \sa minorVersion, profile
+ */
+
+/*!
+ \qmlproperty int QtQuick::GraphicsInfo::minorVersion
+
+ This property holds the minor version of the graphics API in use.
+
+ With OpenGL the default version is \c 2.0.
+
+ \sa majorVersion, profile
+ */
+
+/*!
+ \qmlproperty enumeration QtQuick::GraphicsInfo::profile
+
+ This property holds the configured OpenGL context profile.
+
+ The possible values are:
+ \list
+ \li GraphicsInfo.OpenGLNoProfile (default) - OpenGL version is lower than 3.2 or OpenGL is not in use.
+ \li GraphicsInfo.OpenGLCoreProfile - Functionality deprecated in OpenGL version 3.0 is not available.
+ \li GraphicsInfo.OpenGLCompatibilityProfile - Functionality from earlier OpenGL versions is available.
+ \endlist
+
+ Reusable QML components will typically use this property in bindings in order to
+ choose between core and non core profile compatible shader sources.
+
+ \sa majorVersion, minorVersion, QSurfaceFormat
+ */
+
+/*!
+ \qmlproperty enumeration QtQuick::GraphicsInfo::renderableType
+
+ This property holds the renderable type. The value has no meaning for APIs
+ other than OpenGL.
+
+ The possible values are:
+ \list
+ \li GraphicsInfo.SurfaceFormatUnspecified (default) - Unspecified rendering method
+ \li GraphicsInfo.SurfaceFormatOpenGL - Desktop OpenGL or other graphics API
+ \li GraphicsInfo.SurfaceFormatOpenGLES - OpenGL ES
+ \endlist
+
+ \sa QSurfaceFormat
+ */
+
+void QQuickGraphicsInfo::updateInfo()
+{
+ const bool sgReady = m_window && m_window->isSceneGraphInitialized();
+
+ if (sgReady) {
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ if (rif) {
+ GraphicsApi newAPI = GraphicsApi(rif->graphicsApi());
+ if (m_api != newAPI) {
+ m_api = newAPI;
+ emit apiChanged();
+ m_shaderType = ShaderType(rif->shaderType());
+ emit shaderTypeChanged();
+ m_shaderCompilationType = ShaderCompilationType(int(rif->shaderCompilationType()));
+ emit shaderCompilationTypeChanged();
+ m_shaderSourceType = ShaderSourceType(int(rif->shaderSourceType()));
+ emit shaderSourceTypeChanged();
+ }
+ }
+ }
+
+ QSurfaceFormat format = QSurfaceFormat::defaultFormat();
+#ifndef QT_NO_OPENGL
+ if (sgReady) {
+ QOpenGLContext *context = m_window->openglContext();
+ if (context)
+ format = context->format();
+ }
+#endif
+ if (m_majorVersion != format.majorVersion()) {
+ m_majorVersion = format.majorVersion();
+ emit majorVersionChanged();
+ }
+ if (m_minorVersion != format.minorVersion()) {
+ m_minorVersion = format.minorVersion();
+ emit minorVersionChanged();
+ }
+ OpenGLContextProfile profile = static_cast<OpenGLContextProfile>(format.profile());
+ if (m_profile != profile) {
+ m_profile = profile;
+ emit profileChanged();
+ }
+ RenderableType renderableType = static_cast<RenderableType>(format.renderableType());
+ if (m_renderableType != renderableType) {
+ m_renderableType = renderableType;
+ emit renderableTypeChanged();
+ }
+}
+
+void QQuickGraphicsInfo::setWindow(QQuickWindow *window)
+{
+ if (m_window != window) {
+ if (m_window) {
+ disconnect(m_window, SIGNAL(sceneGraphInitialized()), this, SLOT(updateInfo()));
+ disconnect(m_window, SIGNAL(sceneGraphInvalidated()), this, SLOT(updateInfo()));
+ }
+ if (window) {
+ connect(window, SIGNAL(sceneGraphInitialized()), this, SLOT(updateInfo()));
+ connect(window, SIGNAL(sceneGraphInvalidated()), this, SLOT(updateInfo()));
+ }
+ m_window = window;
+ }
+ updateInfo();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickgraphicsinfo_p.h b/src/quick/items/qquickgraphicsinfo_p.h
new file mode 100644
index 0000000000..9ef7bacb3e
--- /dev/null
+++ b/src/quick/items/qquickgraphicsinfo_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKGRAPHICSINFO_P_H
+#define QQUICKGRAPHICSINFO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qobject.h>
+#include <QtCore/qpointer.h>
+#include <QtQml/qqml.h>
+#include <QtGui/qsurfaceformat.h>
+#include <QtQuick/qsgrendererinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+class QQuickWindow;
+
+class QQuickGraphicsInfo : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(GraphicsApi api READ api NOTIFY apiChanged FINAL)
+ Q_PROPERTY(ShaderType shaderType READ shaderType NOTIFY shaderTypeChanged FINAL)
+ Q_PROPERTY(ShaderCompilationType shaderCompilationType READ shaderCompilationType NOTIFY shaderCompilationTypeChanged FINAL)
+ Q_PROPERTY(ShaderSourceType shaderSourceType READ shaderSourceType NOTIFY shaderSourceTypeChanged FINAL)
+
+ Q_PROPERTY(int majorVersion READ majorVersion NOTIFY majorVersionChanged FINAL)
+ Q_PROPERTY(int minorVersion READ minorVersion NOTIFY minorVersionChanged FINAL)
+ Q_PROPERTY(OpenGLContextProfile profile READ profile NOTIFY profileChanged FINAL)
+ Q_PROPERTY(RenderableType renderableType READ renderableType NOTIFY renderableTypeChanged FINAL)
+
+public:
+ enum GraphicsApi {
+ Unknown = QSGRendererInterface::Unknown,
+ Software = QSGRendererInterface::Software,
+ OpenGL = QSGRendererInterface::OpenGL,
+ Direct3D12 = QSGRendererInterface::Direct3D12
+ };
+ Q_ENUM(GraphicsApi)
+
+ enum ShaderType {
+ UnknownShadingLanguage = QSGRendererInterface::UnknownShadingLanguage,
+ GLSL = QSGRendererInterface::GLSL,
+ HLSL = QSGRendererInterface::HLSL
+ };
+ Q_ENUM(ShaderType)
+
+ enum ShaderCompilationType {
+ RuntimeCompilation = QSGRendererInterface::RuntimeCompilation,
+ OfflineCompilation = QSGRendererInterface::OfflineCompilation
+ };
+ Q_ENUM(ShaderCompilationType)
+
+ enum ShaderSourceType {
+ ShaderSourceString = QSGRendererInterface::ShaderSourceString,
+ ShaderSourceFile = QSGRendererInterface::ShaderSourceFile,
+ ShaderByteCode = QSGRendererInterface::ShaderByteCode
+ };
+ Q_ENUM(ShaderSourceType)
+
+ enum OpenGLContextProfile {
+ OpenGLNoProfile = QSurfaceFormat::NoProfile,
+ OpenGLCoreProfile = QSurfaceFormat::CoreProfile,
+ OpenGLCompatibilityProfile = QSurfaceFormat::CompatibilityProfile
+ };
+ Q_ENUM(OpenGLContextProfile)
+
+ enum RenderableType {
+ SurfaceFormatUnspecified = QSurfaceFormat::DefaultRenderableType,
+ SurfaceFormatOpenGL = QSurfaceFormat::OpenGL,
+ SurfaceFormatOpenGLES = QSurfaceFormat::OpenGLES
+ };
+ Q_ENUM(RenderableType)
+
+ QQuickGraphicsInfo(QQuickItem *item = 0);
+
+ static QQuickGraphicsInfo *qmlAttachedProperties(QObject *object);
+
+ GraphicsApi api() const { return m_api; }
+ ShaderType shaderType() const { return m_shaderType; }
+ ShaderCompilationType shaderCompilationType() const { return m_shaderCompilationType; }
+ ShaderSourceType shaderSourceType() const { return m_shaderSourceType; }
+
+ int majorVersion() const { return m_majorVersion; }
+ int minorVersion() const { return m_minorVersion; }
+ OpenGLContextProfile profile() const { return m_profile; }
+ RenderableType renderableType() const { return m_renderableType; }
+
+Q_SIGNALS:
+ void apiChanged();
+ void shaderTypeChanged();
+ void shaderCompilationTypeChanged();
+ void shaderSourceTypeChanged();
+
+ void majorVersionChanged();
+ void minorVersionChanged();
+ void profileChanged();
+ void renderableTypeChanged();
+
+private Q_SLOTS:
+ void updateInfo();
+ void setWindow(QQuickWindow *window);
+
+private:
+ QPointer<QQuickWindow> m_window;
+ GraphicsApi m_api;
+ ShaderType m_shaderType;
+ ShaderCompilationType m_shaderCompilationType;
+ ShaderSourceType m_shaderSourceType;
+ int m_majorVersion;
+ int m_minorVersion;
+ OpenGLContextProfile m_profile;
+ RenderableType m_renderableType;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(QQuickGraphicsInfo, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKGRAPHICSINFO_P_H
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 0ff04ce71c..04d48d0384 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -85,6 +85,9 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE_TARGET)
+Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
+
#ifndef QT_NO_DEBUG
static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
#endif
@@ -1376,7 +1379,8 @@ void QQuickKeysAttached::keyPressed(QKeyEvent *event, bool post)
d->inPress = false;
}
- QQuickKeyEvent ke(*event);
+ QQuickKeyEvent &ke = d->theKeyEvent;
+ ke.reset(*event);
QByteArray keySignal = keyToSignal(event->key());
if (!keySignal.isEmpty()) {
keySignal += "(QQuickKeyEvent*)";
@@ -1419,7 +1423,8 @@ void QQuickKeysAttached::keyReleased(QKeyEvent *event, bool post)
d->inRelease = false;
}
- QQuickKeyEvent ke(*event);
+ QQuickKeyEvent &ke = d->theKeyEvent;
+ ke.reset(*event);
emit released(&ke);
event->setAccepted(ke.isAccepted());
@@ -2913,6 +2918,8 @@ void QQuickItemPrivate::addChild(QQuickItem *child)
if (childPrivate->hasCursorInChild && !hasCursorInChild)
setHasCursorInChild(true);
#endif
+ if (childPrivate->subtreeHoverEnabled && !subtreeHoverEnabled)
+ setHasHoverInChild(true);
markSortedChildrenDirty(child);
dirty(QQuickItemPrivate::ChildrenChanged);
@@ -2938,6 +2945,8 @@ void QQuickItemPrivate::removeChild(QQuickItem *child)
if (childPrivate->hasCursorInChild && hasCursorInChild)
setHasCursorInChild(false);
#endif
+ if (childPrivate->subtreeHoverEnabled && subtreeHoverEnabled)
+ setHasHoverInChild(false);
markSortedChildrenDirty(child);
dirty(QQuickItemPrivate::ChildrenChanged);
@@ -3160,6 +3169,7 @@ QQuickItemPrivate::QQuickItemPrivate()
, culled(false)
, hasCursor(false)
, hasCursorInChild(false)
+ , subtreeHoverEnabled(false)
, activeFocusOnTab(false)
, implicitAntialiasing(false)
, antialiasingValid(false)
@@ -6970,7 +6980,7 @@ void QQuickItem::setAcceptedMouseButtons(Qt::MouseButtons buttons)
}
/*!
- Returns whether mouse events of this item's children should be filtered
+ Returns whether mouse and touch events of this item's children should be filtered
through this item.
\sa setFiltersChildMouseEvents(), childMouseEventFilter()
@@ -6982,7 +6992,7 @@ bool QQuickItem::filtersChildMouseEvents() const
}
/*!
- Sets whether mouse events of this item's children should be filtered
+ Sets whether mouse and touch events of this item's children should be filtered
through this item.
If \a filter is true, childMouseEventFilter() will be called when
@@ -7033,6 +7043,7 @@ void QQuickItem::setAcceptHoverEvents(bool enabled)
{
Q_D(QQuickItem);
d->hoverEnabled = enabled;
+ d->setHasHoverInChild(enabled);
}
void QQuickItemPrivate::setHasCursorInChild(bool hasCursor)
@@ -7060,6 +7071,31 @@ void QQuickItemPrivate::setHasCursorInChild(bool hasCursor)
#endif
}
+void QQuickItemPrivate::setHasHoverInChild(bool hasHover)
+{
+ Q_Q(QQuickItem);
+
+ // if we're asked to turn it off (because of a setAcceptHoverEvents call, or a node
+ // removal) then we should make sure it's really ok to turn it off.
+ if (!hasHover && subtreeHoverEnabled) {
+ if (hoverEnabled)
+ return; // nope! sorry, I need hover myself
+ foreach (QQuickItem *otherChild, childItems) {
+ QQuickItemPrivate *otherChildPrivate = QQuickItemPrivate::get(otherChild);
+ if (otherChildPrivate->subtreeHoverEnabled || otherChildPrivate->hoverEnabled)
+ return; // nope! sorry, something else wants it kept on.
+ }
+ }
+
+ qCDebug(DBG_HOVER_TRACE) << q << subtreeHoverEnabled << "->" << hasHover;
+ subtreeHoverEnabled = hasHover;
+ QQuickItem *parent = q->parentItem();
+ if (parent) {
+ QQuickItemPrivate *parentPrivate = QQuickItemPrivate::get(parent);
+ parentPrivate->setHasHoverInChild(hasHover);
+ }
+}
+
void QQuickItemPrivate::markObjects(QV4::ExecutionEngine *e)
{
Q_Q(QQuickItem);
@@ -7185,6 +7221,7 @@ void QQuickItem::ungrabMouse()
return;
}
+ qCDebug(DBG_MOUSE_TARGET) << "ungrabMouse" << windowPriv->mouseGrabberItem << "-> null";
windowPriv->mouseGrabberItem = 0;
QEvent ev(QEvent::UngrabMouse);
@@ -7254,6 +7291,7 @@ void QQuickItem::grabTouchPoints(const QVector<int> &ids)
QQuickItem *mouseGrabber = windowPriv->mouseGrabberItem;
if (windowPriv->touchMouseId == ids.at(i) && mouseGrabber && mouseGrabber != this) {
+ qCDebug(DBG_MOUSE_TARGET) << "grabTouchPoints: grabber" << windowPriv->mouseGrabberItem << "-> null";
windowPriv->mouseGrabberItem = 0;
QEvent ev(QEvent::UngrabMouse);
d->window->sendEvent(mouseGrabber, &ev);
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index fed3e88b68..3468172484 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -56,6 +56,7 @@
#include "qquickanchors_p.h"
#include "qquickanchors_p_p.h"
#include "qquickitemchangelistener_p.h"
+#include "qquickevents_p_p.h"
#include "qquickwindow_p.h"
@@ -76,7 +77,6 @@
#include <QtCore/qelapsedtimer.h>
#include <QtQuick/private/qquickshadereffectsource_p.h>
-#include <QtQuick/private/qquickshadereffect_p.h>
QT_BEGIN_NAMESPACE
@@ -428,6 +428,7 @@ public:
bool hasCursor:1;
bool hasCursorInChild:1;
// Bit 32
+ bool subtreeHoverEnabled:1;
bool activeFocusOnTab:1;
bool implicitAntialiasing:1;
bool antialiasingValid:1;
@@ -605,6 +606,7 @@ public:
virtual void mirrorChange() {}
void setHasCursorInChild(bool hasCursor);
+ void setHasHoverInChild(bool hasHover);
// recursive helper to let a visual parent mark its visual children
void markObjects(QV4::ExecutionEngine *e);
@@ -775,6 +777,7 @@ public:
QQuickItem *imeItem;
QList<QQuickItem *> targets;
QQuickItem *item;
+ QQuickKeyEvent theKeyEvent;
};
class QQuickKeysAttached : public QObject, public QQuickItemKeyFilter
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
index f8327a1c6e..0db5323863 100644
--- a/src/quick/items/qquickitemgrabresult.cpp
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -240,8 +240,7 @@ void QQuickItemGrabResult::render()
return;
d->texture->setRect(QRectF(0, d->itemSize.height(), d->itemSize.width(), -d->itemSize.height()));
- QSGContext *sg = QSGRenderContext::from(QOpenGLContext::currentContext())->sceneGraphContext();
- const QSize minSize = sg->minimumFBOSize();
+ const QSize minSize = QQuickWindowPrivate::get(d->window.data())->context->sceneGraphContext()->minimumFBOSize();
d->texture->setSize(QSize(qMax(minSize.width(), d->textureSize.width()),
qMax(minSize.height(), d->textureSize.height())));
d->texture->scheduleUpdate();
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 08d95119d7..8ed7f2bb05 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -41,7 +41,6 @@
#include "qquickitem.h"
#include "qquickitem_p.h"
-#include "qquickitemgrabresult.h"
#include "qquickevents_p_p.h"
#include "qquickrectangle_p.h"
#include "qquickfocusscope_p.h"
@@ -70,18 +69,23 @@
#include "qquicktranslate_p.h"
#include "qquickstateoperations_p.h"
#include "qquickitemanimation_p.h"
-#include <private/qquickshadereffect_p.h>
#include <QtQuick/private/qquickshadereffectsource_p.h>
//#include <private/qquickpincharea_p.h>
#include <QtQuick/private/qquickcanvasitem_p.h>
#include <QtQuick/private/qquickcontext2d_p.h>
-#include "qquicksprite_p.h"
-#include "qquickspritesequence_p.h"
-#include "qquickanimatedsprite_p.h"
+# include "qquickitemgrabresult.h"
+#ifndef QT_NO_OPENGL
+# include "qquicksprite_p.h"
+# include "qquickspritesequence_p.h"
+# include "qquickanimatedsprite_p.h"
+# include "qquickopenglinfo_p.h"
+#endif
+#include "qquickgraphicsinfo_p.h"
+#include "qquickshadereffect_p.h"
+#include "qquickshadereffectmesh_p.h"
#include "qquickdrag_p.h"
#include "qquickdroparea_p.h"
#include "qquickmultipointtoucharea_p.h"
-#include "qquickopenglinfo_p.h"
#include <private/qqmlmetatype_p.h>
#include <QtQuick/private/qquickaccessibleattached_p.h>
@@ -178,7 +182,6 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickTextInput,2>(uri,2,2,"TextInput");
qmlRegisterType<QQuickTextInput,3>(uri,2,4,"TextInput");
qmlRegisterType<QQuickViewSection>(uri,major,minor,"ViewSection");
-
qmlRegisterType<QQuickItemGrabResult>();
qmlRegisterType<QQuickItemLayer>();
qmlRegisterType<QQuickAnchors>();
@@ -207,19 +210,19 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPinch>(uri,major,minor,"Pinch");
qmlRegisterType<QQuickPinchEvent>();
- qmlRegisterType<QQuickShaderEffect>("QtQuick", 2, 0, "ShaderEffect");
qmlRegisterType<QQuickShaderEffectSource>("QtQuick", 2, 0, "ShaderEffectSource");
qmlRegisterUncreatableType<QQuickShaderEffectMesh>("QtQuick", 2, 0, "ShaderEffectMesh", QQuickShaderEffectMesh::tr("Cannot create instance of abstract class ShaderEffectMesh."));
qmlRegisterType<QQuickGridMesh>("QtQuick", 2, 0, "GridMesh");
+ qmlRegisterType<QQuickShaderEffect>("QtQuick", 2, 0, "ShaderEffect");
qmlRegisterUncreatableType<QQuickPaintedItem>("QtQuick", 2, 0, "PaintedItem", QQuickPaintedItem::tr("Cannot create instance of abstract class PaintedItem"));
qmlRegisterType<QQuickCanvasItem>("QtQuick", 2, 0, "Canvas");
-
+#ifndef QT_NO_OPENGL
qmlRegisterType<QQuickSprite>("QtQuick", 2, 0, "Sprite");
qmlRegisterType<QQuickAnimatedSprite>("QtQuick", 2, 0, "AnimatedSprite");
qmlRegisterType<QQuickSpriteSequence>("QtQuick", 2, 0, "SpriteSequence");
-
+#endif
qmlRegisterType<QQuickParentChange>(uri, major, minor,"ParentChange");
qmlRegisterType<QQuickAnchorChanges>(uri, major, minor,"AnchorChanges");
qmlRegisterType<QQuickAnchorSet>();
@@ -262,8 +265,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickListView, 2>(uri, 2, 4, "ListView");
qmlRegisterType<QQuickMouseArea, 1>(uri, 2, 4, "MouseArea");
qmlRegisterType<QQuickShaderEffect, 1>(uri, 2, 4, "ShaderEffect");
- qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties"));
+#ifndef QT_NO_OPENGL
+ qmlRegisterUncreatableType<QQuickOpenGLInfo>(uri, 2, 4,"OpenGLInfo", QQuickOpenGLInfo::tr("OpenGLInfo is only available via attached properties"));
+#endif
qmlRegisterType<QQuickPinchArea, 1>(uri, 2, 5,"PinchArea");
qmlRegisterType<QQuickImage, 2>(uri, 2, 5,"Image");
qmlRegisterType<QQuickMouseArea, 2>(uri, 2, 5, "MouseArea");
@@ -288,6 +293,9 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
qmlRegisterType<QQuickPathView, 7>(uri, 2, 7, "PathView");
qmlRegisterUncreatableType<QQuickMouseEvent, 7>(uri, 2, 7, nullptr, QQuickMouseEvent::tr("MouseEvent is only available within handlers in MouseArea"));
+
+ qmlRegisterUncreatableType<QQuickGraphicsInfo>(uri, 2, 8,"GraphicsInfo", QQuickGraphicsInfo::tr("GraphicsInfo is only available via attached properties"));
+ qmlRegisterType<QQuickBorderImageMesh>("QtQuick", 2, 8, "BorderImageMesh");
}
static void initResources()
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 234105986a..297a57e672 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -40,7 +40,6 @@
#include "qquickmousearea_p.h"
#include "qquickmousearea_p_p.h"
#include "qquickwindow.h"
-#include "qquickevents_p_p.h"
#include "qquickdrag_p.h"
#include <private/qqmldata_p.h>
@@ -55,6 +54,8 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
+Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
+
QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
: enabled(true), scrollGestureEnabled(true), hovered(false), longPress(false),
moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
@@ -764,7 +765,8 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
}
#endif
- QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ QQuickMouseEvent &me = d->quickMouseEvent;
+ me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
me.setSource(event->source());
emit mouseXChanged(&me);
me.setPosition(d->lastPos);
@@ -806,7 +808,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
Q_D(QQuickMouseArea);
if (d->enabled) {
d->saveEvent(event);
- QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
+ QQuickMouseEvent &me = d->quickMouseEvent;
+ me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
me.setSource(event->source());
me.setAccepted(d->isDoubleClickConnected());
emit this->doubleClicked(&me);
@@ -826,7 +829,8 @@ void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
d->lastPos = event->posF();
d->lastModifiers = event->modifiers();
setHovered(true);
- QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
+ QQuickMouseEvent &me = d->quickMouseEvent;
+ me.reset(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
emit mouseXChanged(&me);
me.setPosition(d->lastPos);
emit mouseYChanged(&me);
@@ -839,10 +843,11 @@ void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
Q_D(QQuickMouseArea);
if (!d->enabled && !d->pressed) {
QQuickItem::hoverMoveEvent(event);
- } else {
+ } else if (d->lastPos != event->posF()) {
d->lastPos = event->posF();
d->lastModifiers = event->modifiers();
- QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
+ QQuickMouseEvent &me = d->quickMouseEvent;
+ me.reset(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
emit mouseXChanged(&me);
me.setPosition(d->lastPos);
emit mouseYChanged(&me);
@@ -869,8 +874,9 @@ void QQuickMouseArea::wheelEvent(QWheelEvent *event)
return;
}
- QQuickWheelEvent we(event->posF().x(), event->posF().y(), event->angleDelta(),
- event->pixelDelta(), event->buttons(), event->modifiers());
+ QQuickWheelEvent &we = d->quickWheelEvent;
+ we.reset(event->posF().x(), event->posF().y(), event->angleDelta(), event->pixelDelta(),
+ event->buttons(), event->modifiers(), event->inverted());
we.setAccepted(d->isWheelConnected());
emit wheel(&we);
if (!we.isAccepted())
@@ -1002,7 +1008,8 @@ void QQuickMouseArea::timerEvent(QTimerEvent *event)
#endif
if (d->pressed && dragged == false && d->hovered == true) {
d->longPress = true;
- QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ QQuickMouseEvent &me = d->quickMouseEvent;
+ me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
me.setSource(Qt::MouseEventSynthesizedByQt);
me.setAccepted(d->isPressAndHoldConnected());
emit pressAndHold(&me);
@@ -1083,8 +1090,7 @@ void QQuickMouseArea::setHoverEnabled(bool h)
\qmlproperty bool QtQuick::MouseArea::containsMouse
This property holds whether the mouse is currently inside the mouse area.
- \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
- In addition, if hoverEnabled is false, containsMouse will only be valid
+ \warning If hoverEnabled is false, containsMouse will only be valid
when the mouse is pressed while the mouse cursor is inside the MouseArea.
*/
bool QQuickMouseArea::hovered() const
@@ -1125,6 +1131,7 @@ void QQuickMouseArea::setHovered(bool h)
{
Q_D(QQuickMouseArea);
if (d->hovered != h) {
+ qCDebug(DBG_HOVER_TRACE) << this << d->hovered << "->" << h;
d->hovered = h;
emit hoveredChanged();
d->hovered ? emit entered() : emit exited();
@@ -1180,7 +1187,8 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS
Qt::MouseButtons oldPressed = d->pressed;
if (wasPressed != p) {
- QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
+ QQuickMouseEvent &me = d->quickMouseEvent;
+ me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
me.setSource(source);
if (p) {
d->pressed |= button;
diff --git a/src/quick/items/qquickmousearea_p_p.h b/src/quick/items/qquickmousearea_p_p.h
index dc00ffe52c..b59e02910f 100644
--- a/src/quick/items/qquickmousearea_p_p.h
+++ b/src/quick/items/qquickmousearea_p_p.h
@@ -52,6 +52,7 @@
//
#include "qquickitem_p.h"
+#include "qquickevents_p_p.h"
#include <QtGui/qevent.h>
#include <QtCore/qbasictimer.h>
@@ -108,6 +109,8 @@ public:
#ifndef QT_NO_CURSOR
QCursor *cursor;
#endif
+ QQuickMouseEvent quickMouseEvent;
+ QQuickWheelEvent quickWheelEvent;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickopenglinfo.cpp b/src/quick/items/qquickopenglinfo.cpp
index b380a93e76..4bb13b84aa 100644
--- a/src/quick/items/qquickopenglinfo.cpp
+++ b/src/quick/items/qquickopenglinfo.cpp
@@ -61,6 +61,10 @@ QT_BEGIN_NAMESPACE
format. When it becomes associated with a surface, all properties
will update.
+ \deprecated
+
+ \warning This type is deprecated. Use GraphicsInfo instead.
+
\sa ShaderEffect
*/
QQuickOpenGLInfo::QQuickOpenGLInfo(QQuickItem *item)
diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp
new file mode 100644
index 0000000000..312721ed04
--- /dev/null
+++ b/src/quick/items/qquickopenglshadereffect.cpp
@@ -0,0 +1,862 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qquickopenglshadereffect_p.h>
+
+#include <QtQuick/qsgmaterial.h>
+#include <QtQuick/private/qsgshadersourcebuilder_p.h>
+#include "qquickitem_p.h"
+
+#include <QtQuick/private/qsgcontext_p.h>
+#include <QtQuick/qsgtextureprovider.h>
+#include "qquickwindow.h"
+
+#include "qquickimage_p.h"
+#include "qquickshadereffectsource_p.h"
+#include "qquickshadereffectmesh_p.h"
+
+#include <QtCore/qsignalmapper.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+ enum VariableQualifier {
+ AttributeQualifier,
+ UniformQualifier
+ };
+
+ inline bool qt_isalpha(char c)
+ {
+ char ch = c | 0x20;
+ return (ch >= 'a' && ch <= 'z') || c == '_';
+ }
+
+ inline bool qt_isalnum(char c)
+ {
+ return qt_isalpha(c) || (c >= '0' && c <= '9');
+ }
+
+ inline bool qt_isspace(char c)
+ {
+ return c == ' ' || (c >= 0x09 && c <= 0x0d);
+ }
+
+ // Returns -1 if not found, returns index to first character after the name if found.
+ int qt_search_for_variable(const char *s, int length, int index, VariableQualifier &decl,
+ int &typeIndex, int &typeLength,
+ int &nameIndex, int &nameLength,
+ QQuickOpenGLShaderEffectCommon::Key::ShaderType shaderType)
+ {
+ enum Identifier {
+ QualifierIdentifier, // Base state
+ PrecisionIdentifier,
+ TypeIdentifier,
+ NameIdentifier
+ };
+ Identifier expected = QualifierIdentifier;
+ bool compilerDirectiveExpected = index == 0;
+
+ while (index < length) {
+ // Skip whitespace.
+ while (qt_isspace(s[index])) {
+ compilerDirectiveExpected |= s[index] == '\n';
+ ++index;
+ }
+
+ if (qt_isalpha(s[index])) {
+ // Read identifier.
+ int idIndex = index;
+ ++index;
+ while (qt_isalnum(s[index]))
+ ++index;
+ int idLength = index - idIndex;
+
+ const int attrLen = sizeof("attribute") - 1;
+ const int inLen = sizeof("in") - 1;
+ const int uniLen = sizeof("uniform") - 1;
+ const int loLen = sizeof("lowp") - 1;
+ const int medLen = sizeof("mediump") - 1;
+ const int hiLen = sizeof("highp") - 1;
+
+ switch (expected) {
+ case QualifierIdentifier:
+ if (idLength == attrLen && qstrncmp("attribute", s + idIndex, attrLen) == 0) {
+ decl = AttributeQualifier;
+ expected = PrecisionIdentifier;
+ } else if (shaderType == QQuickOpenGLShaderEffectCommon::Key::VertexShader
+ && idLength == inLen && qstrncmp("in", s + idIndex, inLen) == 0) {
+ decl = AttributeQualifier;
+ expected = PrecisionIdentifier;
+ } else if (idLength == uniLen && qstrncmp("uniform", s + idIndex, uniLen) == 0) {
+ decl = UniformQualifier;
+ expected = PrecisionIdentifier;
+ }
+ break;
+ case PrecisionIdentifier:
+ if ((idLength == loLen && qstrncmp("lowp", s + idIndex, loLen) == 0)
+ || (idLength == medLen && qstrncmp("mediump", s + idIndex, medLen) == 0)
+ || (idLength == hiLen && qstrncmp("highp", s + idIndex, hiLen) == 0))
+ {
+ expected = TypeIdentifier;
+ break;
+ }
+ // Fall through.
+ case TypeIdentifier:
+ typeIndex = idIndex;
+ typeLength = idLength;
+ expected = NameIdentifier;
+ break;
+ case NameIdentifier:
+ nameIndex = idIndex;
+ nameLength = idLength;
+ return index; // Attribute or uniform declaration found. Return result.
+ default:
+ break;
+ }
+ } else if (s[index] == '#' && compilerDirectiveExpected) {
+ // Skip compiler directives.
+ ++index;
+ while (index < length && (s[index] != '\n' || s[index - 1] == '\\'))
+ ++index;
+ } else if (s[index] == '/' && s[index + 1] == '/') {
+ // Skip comments.
+ index += 2;
+ while (index < length && s[index] != '\n')
+ ++index;
+ } else if (s[index] == '/' && s[index + 1] == '*') {
+ // Skip comments.
+ index += 2;
+ while (index < length && (s[index] != '*' || s[index + 1] != '/'))
+ ++index;
+ if (index < length)
+ index += 2; // Skip star-slash.
+ } else {
+ expected = QualifierIdentifier;
+ ++index;
+ }
+ compilerDirectiveExpected = false;
+ }
+ return -1;
+ }
+}
+
+
+
+QQuickOpenGLShaderEffectCommon::~QQuickOpenGLShaderEffectCommon()
+{
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
+ qDeleteAll(signalMappers[shaderType]);
+}
+
+void QQuickOpenGLShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
+{
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ if (signalMappers[shaderType].at(i) == 0)
+ continue;
+ const UniformData &d = uniformData[shaderType].at(i);
+ QSignalMapper *mapper = signalMappers[shaderType].at(i);
+ QObject::disconnect(item, 0, mapper, SLOT(map()));
+ QObject::disconnect(mapper, SIGNAL(mapped(int)), host, SLOT(propertyChanged(int)));
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
+ if (source) {
+ if (item->window())
+ QQuickItemPrivate::get(source)->derefWindow();
+ QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
+ }
+ }
+ }
+}
+
+void QQuickOpenGLShaderEffectCommon::connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
+{
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ if (signalMappers[shaderType].at(i) == 0)
+ continue;
+ const UniformData &d = uniformData[shaderType].at(i);
+ int pi = item->metaObject()->indexOfProperty(d.name.constData());
+ if (pi >= 0) {
+ QMetaProperty mp = item->metaObject()->property(pi);
+ if (!mp.hasNotifySignal())
+ qWarning("QQuickOpenGLShaderEffect: property '%s' does not have notification method!", d.name.constData());
+ const QByteArray signalName = '2' + mp.notifySignal().methodSignature();
+ QSignalMapper *mapper = signalMappers[shaderType].at(i);
+ QObject::connect(item, signalName, mapper, SLOT(map()));
+ QObject::connect(mapper, SIGNAL(mapped(int)), host, SLOT(propertyChanged(int)));
+ } else {
+ // If the source is set via a dynamic property, like the layer is, then we need this
+ // check to disable the warning.
+ if (!item->property(d.name.constData()).isValid())
+ qWarning("QQuickOpenGLShaderEffect: '%s' does not have a matching property!", d.name.constData());
+ }
+
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
+ if (source) {
+ if (item->window())
+ QQuickItemPrivate::get(source)->refWindow(item->window());
+ QObject::connect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
+ }
+ }
+ }
+}
+
+void QQuickOpenGLShaderEffectCommon::updateParseLog(bool ignoreAttributes)
+{
+ parseLog.clear();
+ if (!ignoreAttributes) {
+ if (!attributes.contains(qtPositionAttributeName())) {
+ parseLog += QLatin1String("Warning: Missing reference to \'");
+ parseLog += QLatin1String(qtPositionAttributeName());
+ parseLog += QLatin1String("\'.\n");
+ }
+ if (!attributes.contains(qtTexCoordAttributeName())) {
+ parseLog += QLatin1String("Warning: Missing reference to \'");
+ parseLog += QLatin1String(qtTexCoordAttributeName());
+ parseLog += QLatin1String("\'.\n");
+ }
+ }
+ bool respectsMatrix = false;
+ bool respectsOpacity = false;
+ for (int i = 0; i < uniformData[Key::VertexShader].size(); ++i)
+ respectsMatrix |= uniformData[Key::VertexShader].at(i).specialType == UniformData::Matrix;
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i)
+ respectsOpacity |= uniformData[shaderType].at(i).specialType == UniformData::Opacity;
+ }
+ if (!respectsMatrix)
+ parseLog += QLatin1String("Warning: Vertex shader is missing reference to \'qt_Matrix\'.\n");
+ if (!respectsOpacity)
+ parseLog += QLatin1String("Warning: Shaders are missing reference to \'qt_Opacity\'.\n");
+}
+
+void QQuickOpenGLShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code)
+{
+ int index = 0;
+ int typeIndex = -1;
+ int typeLength = 0;
+ int nameIndex = -1;
+ int nameLength = 0;
+ const char *s = code.constData();
+ VariableQualifier decl = AttributeQualifier;
+ while ((index = qt_search_for_variable(s, code.size(), index, decl, typeIndex, typeLength,
+ nameIndex, nameLength, shaderType)) != -1)
+ {
+ if (decl == AttributeQualifier) {
+ if (shaderType == Key::VertexShader)
+ attributes.append(QByteArray(s + nameIndex, nameLength));
+ } else {
+ Q_ASSERT(decl == UniformQualifier);
+
+ const int sampLen = sizeof("sampler2D") - 1;
+ const int opLen = sizeof("qt_Opacity") - 1;
+ const int matLen = sizeof("qt_Matrix") - 1;
+ const int srLen = sizeof("qt_SubRect_") - 1;
+
+ UniformData d;
+ QSignalMapper *mapper = 0;
+ d.name = QByteArray(s + nameIndex, nameLength);
+ if (nameLength == opLen && qstrncmp("qt_Opacity", s + nameIndex, opLen) == 0) {
+ d.specialType = UniformData::Opacity;
+ } else if (nameLength == matLen && qstrncmp("qt_Matrix", s + nameIndex, matLen) == 0) {
+ d.specialType = UniformData::Matrix;
+ } else if (nameLength > srLen && qstrncmp("qt_SubRect_", s + nameIndex, srLen) == 0) {
+ d.specialType = UniformData::SubRect;
+ } else {
+ mapper = new QSignalMapper;
+ mapper->setMapping(item, uniformData[shaderType].size() | (shaderType << 16));
+ d.value = item->property(d.name.constData());
+ bool sampler = typeLength == sampLen && qstrncmp("sampler2D", s + typeIndex, sampLen) == 0;
+ d.specialType = sampler ? UniformData::Sampler : UniformData::None;
+ }
+ uniformData[shaderType].append(d);
+ signalMappers[shaderType].append(mapper);
+ }
+ }
+}
+
+void QQuickOpenGLShaderEffectCommon::updateShader(QQuickItem *item, Key::ShaderType shaderType)
+{
+ disconnectPropertySignals(item, shaderType);
+ qDeleteAll(signalMappers[shaderType]);
+ uniformData[shaderType].clear();
+ signalMappers[shaderType].clear();
+ if (shaderType == Key::VertexShader)
+ attributes.clear();
+
+ const QByteArray &code = source.sourceCode[shaderType];
+ if (code.isEmpty()) {
+ // Optimize for default code.
+ if (shaderType == Key::VertexShader) {
+ attributes.append(QByteArray(qtPositionAttributeName()));
+ attributes.append(QByteArray(qtTexCoordAttributeName()));
+ UniformData d;
+ d.name = "qt_Matrix";
+ d.specialType = UniformData::Matrix;
+ uniformData[Key::VertexShader].append(d);
+ signalMappers[Key::VertexShader].append(0);
+ } else if (shaderType == Key::FragmentShader) {
+ UniformData d;
+ d.name = "qt_Opacity";
+ d.specialType = UniformData::Opacity;
+ uniformData[Key::FragmentShader].append(d);
+ signalMappers[Key::FragmentShader].append(0);
+ QSignalMapper *mapper = new QSignalMapper;
+ mapper->setMapping(item, 1 | (Key::FragmentShader << 16));
+ const char *sourceName = "source";
+ d.name = sourceName;
+ d.value = item->property(sourceName);
+ d.specialType = UniformData::Sampler;
+ uniformData[Key::FragmentShader].append(d);
+ signalMappers[Key::FragmentShader].append(mapper);
+ }
+ } else {
+ lookThroughShaderCode(item, shaderType, code);
+ }
+
+ connectPropertySignals(item, shaderType);
+}
+
+void QQuickOpenGLShaderEffectCommon::updateMaterial(QQuickOpenGLShaderEffectNode *node,
+ QQuickOpenGLShaderEffectMaterial *material,
+ bool updateUniforms, bool updateUniformValues,
+ bool updateTextureProviders)
+{
+ if (updateUniforms) {
+ for (int i = 0; i < material->textureProviders.size(); ++i) {
+ QSGTextureProvider *t = material->textureProviders.at(i);
+ if (t) {
+ QObject::disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ QObject::disconnect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ }
+ }
+
+ // First make room in the textureProviders array. Set to proper value further down.
+ int textureProviderCount = 0;
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ if (uniformData[shaderType].at(i).specialType == UniformData::Sampler)
+ ++textureProviderCount;
+ }
+ material->uniforms[shaderType] = uniformData[shaderType];
+ }
+ material->textureProviders.fill(0, textureProviderCount);
+ updateUniformValues = false;
+ updateTextureProviders = true;
+ }
+
+ if (updateUniformValues) {
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ Q_ASSERT(uniformData[shaderType].size() == material->uniforms[shaderType].size());
+ for (int i = 0; i < uniformData[shaderType].size(); ++i)
+ material->uniforms[shaderType][i].value = uniformData[shaderType].at(i).value;
+ }
+ }
+
+ if (updateTextureProviders) {
+ int index = 0;
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ const UniformData &d = uniformData[shaderType].at(i);
+ if (d.specialType != UniformData::Sampler)
+ continue;
+ QSGTextureProvider *oldProvider = material->textureProviders.at(index);
+ QSGTextureProvider *newProvider = 0;
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
+ if (source && source->isTextureProvider())
+ newProvider = source->textureProvider();
+ if (newProvider != oldProvider) {
+ if (oldProvider) {
+ QObject::disconnect(oldProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ QObject::disconnect(oldProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ }
+ if (newProvider) {
+ Q_ASSERT_X(newProvider->thread() == QThread::currentThread(),
+ "QQuickOpenGLShaderEffect::updatePaintNode",
+ "Texture provider must belong to the rendering thread");
+ QObject::connect(newProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
+ QObject::connect(newProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
+ } else {
+ const char *typeName = source ? source->metaObject()->className() : d.value.typeName();
+ qWarning("ShaderEffect: Property '%s' is not assigned a valid texture provider (%s).",
+ d.name.constData(), typeName);
+ }
+ material->textureProviders[index] = newProvider;
+ }
+ ++index;
+ }
+ }
+ Q_ASSERT(index == material->textureProviders.size());
+ }
+}
+
+void QQuickOpenGLShaderEffectCommon::updateWindow(QQuickWindow *window)
+{
+ // See comment in QQuickOpenGLShaderEffectCommon::propertyChanged().
+ if (window) {
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ const UniformData &d = uniformData[shaderType].at(i);
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
+ if (source)
+ QQuickItemPrivate::get(source)->refWindow(window);
+ }
+ }
+ }
+ } else {
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ const UniformData &d = uniformData[shaderType].at(i);
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
+ if (source)
+ QQuickItemPrivate::get(source)->derefWindow();
+ }
+ }
+ }
+ }
+}
+
+void QQuickOpenGLShaderEffectCommon::sourceDestroyed(QObject *object)
+{
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < uniformData[shaderType].size(); ++i) {
+ UniformData &d = uniformData[shaderType][i];
+ if (d.specialType == UniformData::Sampler && d.value.canConvert<QObject *>()) {
+ if (qvariant_cast<QObject *>(d.value) == object)
+ d.value = QVariant();
+ }
+ }
+ }
+}
+
+static bool qquick_uniqueInUniformData(QQuickItem *source, const QVector<QQuickOpenGLShaderEffectMaterial::UniformData> *uniformData, int typeToSkip, int indexToSkip)
+{
+ for (int s=0; s<QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++s) {
+ for (int i=0; i<uniformData[s].size(); ++i) {
+ if (s == typeToSkip && i == indexToSkip)
+ continue;
+ const QQuickOpenGLShaderEffectMaterial::UniformData &d = uniformData[s][i];
+ if (d.specialType == QQuickOpenGLShaderEffectMaterial::UniformData::Sampler && qvariant_cast<QObject *>(d.value) == source)
+ return false;
+ }
+ }
+ return true;
+}
+
+void QQuickOpenGLShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
+ bool *textureProviderChanged)
+{
+ Key::ShaderType shaderType = Key::ShaderType(mappedId >> 16);
+ int index = mappedId & 0xffff;
+ UniformData &d = uniformData[shaderType][index];
+ if (d.specialType == UniformData::Sampler) {
+ QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
+ if (source) {
+ if (item->window())
+ QQuickItemPrivate::get(source)->derefWindow();
+
+ // QObject::disconnect() will disconnect all matching connections. If the same
+ // source has been attached to two separate samplers, then changing one of them
+ // would trigger both to be disconnected. Without the connection we'll end up
+ // with a dangling pointer in the uniformData.
+ if (qquick_uniqueInUniformData(source, uniformData, shaderType, index))
+ QObject::disconnect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
+ }
+
+ d.value = item->property(d.name.constData());
+
+ source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
+ if (source) {
+ // 'source' needs a window to get a scene graph node. It usually gets one through its
+ // parent, but if the source item is "inline" rather than a reference -- i.e.
+ // "property variant source: Image { }" instead of "property variant source: foo" -- it
+ // will not get a parent. In those cases, 'source' should get the window from 'item'.
+ if (item->window())
+ QQuickItemPrivate::get(source)->refWindow(item->window());
+ QObject::connect(source, SIGNAL(destroyed(QObject*)), host, SLOT(sourceDestroyed(QObject*)));
+ }
+ if (textureProviderChanged)
+ *textureProviderChanged = true;
+ } else {
+ d.value = item->property(d.name.constData());
+ if (textureProviderChanged)
+ *textureProviderChanged = false;
+ }
+}
+
+QQuickOpenGLShaderEffect::QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QObject *parent)
+ : QObject(parent)
+ , m_item(item)
+ , m_meshResolution(1, 1)
+ , m_mesh(0)
+ , m_cullMode(QQuickShaderEffect::NoCulling)
+ , m_status(QQuickShaderEffect::Uncompiled)
+ , m_common(this)
+ , m_blending(true)
+ , m_dirtyUniforms(true)
+ , m_dirtyUniformValues(true)
+ , m_dirtyTextureProviders(true)
+ , m_dirtyProgram(true)
+ , m_dirtyParseLog(true)
+ , m_dirtyMesh(true)
+ , m_dirtyGeometry(true)
+ , m_customVertexShader(false)
+ , m_supportsAtlasTextures(false)
+{
+}
+
+QQuickOpenGLShaderEffect::~QQuickOpenGLShaderEffect()
+{
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
+ m_common.disconnectPropertySignals(m_item, Key::ShaderType(shaderType));
+}
+
+void QQuickOpenGLShaderEffect::setFragmentShader(const QByteArray &code)
+{
+ if (m_common.source.sourceCode[Key::FragmentShader].constData() == code.constData())
+ return;
+ m_common.source.sourceCode[Key::FragmentShader] = code;
+ m_dirtyProgram = true;
+ m_dirtyParseLog = true;
+
+ if (m_item->isComponentComplete())
+ m_common.updateShader(m_item, Key::FragmentShader);
+
+ m_item->update();
+ if (m_status != QQuickShaderEffect::Uncompiled) {
+ m_status = QQuickShaderEffect::Uncompiled;
+ emit m_item->statusChanged();
+ }
+ emit m_item->fragmentShaderChanged();
+}
+
+void QQuickOpenGLShaderEffect::setVertexShader(const QByteArray &code)
+{
+ if (m_common.source.sourceCode[Key::VertexShader].constData() == code.constData())
+ return;
+ m_common.source.sourceCode[Key::VertexShader] = code;
+ m_dirtyProgram = true;
+ m_dirtyParseLog = true;
+ m_customVertexShader = true;
+
+ if (m_item->isComponentComplete())
+ m_common.updateShader(m_item, Key::VertexShader);
+
+ m_item->update();
+ if (m_status != QQuickShaderEffect::Uncompiled) {
+ m_status = QQuickShaderEffect::Uncompiled;
+ emit m_item->statusChanged();
+ }
+ emit m_item->vertexShaderChanged();
+}
+
+void QQuickOpenGLShaderEffect::setBlending(bool enable)
+{
+ if (blending() == enable)
+ return;
+
+ m_blending = enable;
+ m_item->update();
+
+ emit m_item->blendingChanged();
+}
+
+QVariant QQuickOpenGLShaderEffect::mesh() const
+{
+ return m_mesh ? qVariantFromValue(static_cast<QObject *>(m_mesh))
+ : qVariantFromValue(m_meshResolution);
+}
+
+void QQuickOpenGLShaderEffect::setMesh(const QVariant &mesh)
+{
+ QQuickShaderEffectMesh *newMesh = qobject_cast<QQuickShaderEffectMesh *>(qvariant_cast<QObject *>(mesh));
+ if (newMesh && newMesh == m_mesh)
+ return;
+ if (m_mesh)
+ disconnect(m_mesh, SIGNAL(geometryChanged()), this, 0);
+ m_mesh = newMesh;
+ if (m_mesh) {
+ connect(m_mesh, SIGNAL(geometryChanged()), this, SLOT(updateGeometry()));
+ } else {
+ if (mesh.canConvert<QSize>()) {
+ m_meshResolution = mesh.toSize();
+ } else {
+ QList<QByteArray> res = mesh.toByteArray().split('x');
+ bool ok = res.size() == 2;
+ if (ok) {
+ int w = res.at(0).toInt(&ok);
+ if (ok) {
+ int h = res.at(1).toInt(&ok);
+ if (ok)
+ m_meshResolution = QSize(w, h);
+ }
+ }
+ if (!ok)
+ qWarning("ShaderEffect: mesh property must be size or object deriving from QQuickShaderEffectMesh.");
+ }
+ m_defaultMesh.setResolution(m_meshResolution);
+ }
+
+ m_dirtyMesh = true;
+ m_dirtyParseLog = true;
+ m_item->update();
+ emit m_item->meshChanged();
+}
+
+void QQuickOpenGLShaderEffect::setCullMode(QQuickShaderEffect::CullMode face)
+{
+ if (face == m_cullMode)
+ return;
+ m_cullMode = face;
+ m_item->update();
+ emit m_item->cullModeChanged();
+}
+
+void QQuickOpenGLShaderEffect::setSupportsAtlasTextures(bool supports)
+{
+ if (supports == m_supportsAtlasTextures)
+ return;
+ m_supportsAtlasTextures = supports;
+ updateGeometry();
+ emit m_item->supportsAtlasTexturesChanged();
+}
+
+QString QQuickOpenGLShaderEffect::parseLog()
+{
+ if (m_dirtyParseLog) {
+ m_common.updateParseLog(m_mesh != 0);
+ m_dirtyParseLog = false;
+ }
+ return m_common.parseLog;
+}
+
+void QQuickOpenGLShaderEffect::handleEvent(QEvent *event)
+{
+ if (event->type() == QEvent::DynamicPropertyChange) {
+ QDynamicPropertyChangeEvent *e = static_cast<QDynamicPropertyChangeEvent *>(event);
+ for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
+ for (int i = 0; i < m_common.uniformData[shaderType].size(); ++i) {
+ if (m_common.uniformData[shaderType].at(i).name == e->propertyName()) {
+ bool textureProviderChanged;
+ m_common.propertyChanged(m_item, (shaderType << 16) | i, &textureProviderChanged);
+ m_dirtyTextureProviders |= textureProviderChanged;
+ m_dirtyUniformValues = true;
+ m_item->update();
+ }
+ }
+ }
+ }
+}
+
+void QQuickOpenGLShaderEffect::updateGeometry()
+{
+ m_dirtyGeometry = true;
+ m_item->update();
+}
+
+void QQuickOpenGLShaderEffect::updateGeometryIfAtlased()
+{
+ if (m_supportsAtlasTextures)
+ updateGeometry();
+}
+
+void QQuickOpenGLShaderEffect::updateLogAndStatus(const QString &log, int status)
+{
+ m_log = parseLog() + log;
+ m_status = QQuickShaderEffect::Status(status);
+ emit m_item->logChanged();
+ emit m_item->statusChanged();
+}
+
+void QQuickOpenGLShaderEffect::sourceDestroyed(QObject *object)
+{
+ m_common.sourceDestroyed(object);
+}
+
+void QQuickOpenGLShaderEffect::propertyChanged(int mappedId)
+{
+ bool textureProviderChanged;
+ m_common.propertyChanged(m_item, mappedId, &textureProviderChanged);
+ m_dirtyTextureProviders |= textureProviderChanged;
+ m_dirtyUniformValues = true;
+ m_item->update();
+}
+
+void QQuickOpenGLShaderEffect::handleGeometryChanged(const QRectF &, const QRectF &)
+{
+ m_dirtyGeometry = true;
+}
+
+QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+{
+ QQuickOpenGLShaderEffectNode *node = static_cast<QQuickOpenGLShaderEffectNode *>(oldNode);
+
+ // In the case of zero-size or a bad vertex shader, don't try to create a node...
+ if (m_common.attributes.isEmpty() || m_item->width() <= 0 || m_item->height() <= 0) {
+ if (node)
+ delete node;
+ return 0;
+ }
+
+ if (!node) {
+ node = new QQuickOpenGLShaderEffectNode;
+ node->setMaterial(new QQuickOpenGLShaderEffectMaterial(node));
+ node->setFlag(QSGNode::OwnsMaterial, true);
+ m_dirtyProgram = true;
+ m_dirtyUniforms = true;
+ m_dirtyGeometry = true;
+ connect(node, SIGNAL(logAndStatusChanged(QString,int)), this, SLOT(updateLogAndStatus(QString,int)));
+ connect(node, &QQuickOpenGLShaderEffectNode::dirtyTexture,
+ this, &QQuickOpenGLShaderEffect::updateGeometryIfAtlased);
+ }
+
+ QQuickOpenGLShaderEffectMaterial *material = static_cast<QQuickOpenGLShaderEffectMaterial *>(node->material());
+
+ // Update blending
+ if (bool(material->flags() & QSGMaterial::Blending) != m_blending) {
+ material->setFlag(QSGMaterial::Blending, m_blending);
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (int(material->cullMode) != int(m_cullMode)) {
+ material->cullMode = QQuickShaderEffect::CullMode(m_cullMode);
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (m_dirtyProgram) {
+ Key s = m_common.source;
+ QSGShaderSourceBuilder builder;
+ if (s.sourceCode[Key::FragmentShader].isEmpty()) {
+ builder.appendSourceFile(QStringLiteral(":/qt-project.org/items/shaders/shadereffect.frag"));
+ s.sourceCode[Key::FragmentShader] = builder.source();
+ builder.clear();
+ }
+ if (s.sourceCode[Key::VertexShader].isEmpty()) {
+ builder.appendSourceFile(QStringLiteral(":/qt-project.org/items/shaders/shadereffect.vert"));
+ s.sourceCode[Key::VertexShader] = builder.source();
+ }
+
+ material->setProgramSource(s);
+ material->attributes = m_common.attributes;
+ node->markDirty(QSGNode::DirtyMaterial);
+ m_dirtyProgram = false;
+ m_dirtyUniforms = true;
+ }
+
+ if (m_dirtyUniforms || m_dirtyUniformValues || m_dirtyTextureProviders) {
+ m_common.updateMaterial(node, material, m_dirtyUniforms, m_dirtyUniformValues,
+ m_dirtyTextureProviders);
+ node->markDirty(QSGNode::DirtyMaterial);
+ m_dirtyUniforms = m_dirtyUniformValues = m_dirtyTextureProviders = false;
+ }
+
+ QRectF srcRect(0, 0, 1, 1);
+ bool geometryUsesTextureSubRect = false;
+ if (m_supportsAtlasTextures && material->textureProviders.size() == 1) {
+ QSGTextureProvider *provider = material->textureProviders.at(0);
+ if (provider->texture()) {
+ srcRect = provider->texture()->normalizedTextureSubRect();
+ geometryUsesTextureSubRect = true;
+ }
+ }
+
+ if (bool(material->flags() & QSGMaterial::RequiresFullMatrix) != m_customVertexShader) {
+ material->setFlag(QSGMaterial::RequiresFullMatrix, m_customVertexShader);
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (material->geometryUsesTextureSubRect != geometryUsesTextureSubRect) {
+ material->geometryUsesTextureSubRect = geometryUsesTextureSubRect;
+ node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ if (m_dirtyMesh) {
+ node->setGeometry(0);
+ m_dirtyMesh = false;
+ m_dirtyGeometry = true;
+ }
+
+ if (m_dirtyGeometry) {
+ node->setFlag(QSGNode::OwnsGeometry, false);
+ QSGGeometry *geometry = node->geometry();
+ QRectF rect(0, 0, m_item->width(), m_item->height());
+ QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
+
+ int posIndex = 0;
+ if (!mesh->validateAttributes(m_common.attributes, &posIndex)) {
+ QString log = mesh->log();
+ if (!log.isNull()) {
+ m_log = parseLog();
+ m_log += QLatin1String("*** Mesh ***\n");
+ m_log += log;
+ m_status = QQuickShaderEffect::Error;
+ emit m_item->logChanged();
+ emit m_item->statusChanged();
+ }
+ delete node;
+ return 0;
+ }
+
+ geometry = mesh->updateGeometry(geometry, m_common.attributes.count(), posIndex, srcRect, rect);
+
+ node->setGeometry(geometry);
+ node->setFlag(QSGNode::OwnsGeometry, true);
+
+ m_dirtyGeometry = false;
+ }
+
+ return node;
+}
+
+void QQuickOpenGLShaderEffect::handleComponentComplete()
+{
+ m_common.updateShader(m_item, Key::VertexShader);
+ m_common.updateShader(m_item, Key::FragmentShader);
+}
+
+void QQuickOpenGLShaderEffect::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
+{
+ if (change == QQuickItem::ItemSceneChange)
+ m_common.updateWindow(value.window);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickopenglshadereffect_p.h b/src/quick/items/qquickopenglshadereffect_p.h
new file mode 100644
index 0000000000..0e54813443
--- /dev/null
+++ b/src/quick/items/qquickopenglshadereffect_p.h
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKOPENGLSHADEREFFECT_P_H
+#define QQUICKOPENGLSHADEREFFECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/qquickitem.h>
+
+#include <QtQuick/qsgmaterial.h>
+#include <private/qtquickglobal_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qquickopenglshadereffectnode_p.h>
+#include "qquickshadereffect_p.h"
+#include "qquickshadereffectmesh_p.h"
+
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGContext;
+class QSignalMapper;
+class QQuickOpenGLCustomMaterialShader;
+
+// Common class for QQuickOpenGLShaderEffect and QQuickCustomParticle.
+struct Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectCommon
+{
+ typedef QQuickOpenGLShaderEffectMaterialKey Key;
+ typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
+
+ QQuickOpenGLShaderEffectCommon(QObject *host) : host(host) { }
+ ~QQuickOpenGLShaderEffectCommon();
+ void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
+ void connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
+ void updateParseLog(bool ignoreAttributes);
+ void lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code);
+ void updateShader(QQuickItem *item, Key::ShaderType shaderType);
+ void updateMaterial(QQuickOpenGLShaderEffectNode *node, QQuickOpenGLShaderEffectMaterial *material,
+ bool updateUniforms, bool updateUniformValues, bool updateTextureProviders);
+ void updateWindow(QQuickWindow *window);
+
+ // Called by slots in QQuickOpenGLShaderEffect:
+ void sourceDestroyed(QObject *object);
+ void propertyChanged(QQuickItem *item, int mappedId, bool *textureProviderChanged);
+
+ QObject *host;
+ Key source;
+ QVector<QByteArray> attributes;
+ QVector<UniformData> uniformData[Key::ShaderTypeCount];
+ QVector<QSignalMapper *> signalMappers[Key::ShaderTypeCount];
+ QString parseLog;
+};
+
+
+class Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffect : public QObject
+{
+ Q_OBJECT
+
+public:
+ QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QObject *parent = 0);
+ ~QQuickOpenGLShaderEffect();
+
+ QByteArray fragmentShader() const { return m_common.source.sourceCode[Key::FragmentShader]; }
+ void setFragmentShader(const QByteArray &code);
+
+ QByteArray vertexShader() const { return m_common.source.sourceCode[Key::VertexShader]; }
+ void setVertexShader(const QByteArray &code);
+
+ bool blending() const { return m_blending; }
+ void setBlending(bool enable);
+
+ QVariant mesh() const;
+ void setMesh(const QVariant &mesh);
+
+ QQuickShaderEffect::CullMode cullMode() const { return m_cullMode; }
+ void setCullMode(QQuickShaderEffect::CullMode face);
+
+ QString log() const { return m_log; }
+ QQuickShaderEffect::Status status() const { return m_status; }
+
+ bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
+ void setSupportsAtlasTextures(bool supports);
+
+ QString parseLog();
+
+ void handleEvent(QEvent *);
+ void handleGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
+ QSGNode *handleUpdatePaintNode(QSGNode *, QQuickItem::UpdatePaintNodeData *);
+ void handleComponentComplete();
+ void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value);
+
+private Q_SLOTS:
+ void updateGeometry();
+ void updateGeometryIfAtlased();
+ void updateLogAndStatus(const QString &log, int status);
+ void sourceDestroyed(QObject *object);
+ void propertyChanged(int mappedId);
+
+private:
+ friend class QQuickCustomMaterialShader;
+ friend class QQuickOpenGLShaderEffectNode;
+
+ typedef QQuickOpenGLShaderEffectMaterialKey Key;
+ typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
+
+ QQuickShaderEffect *m_item;
+ QSize m_meshResolution;
+ QQuickShaderEffectMesh *m_mesh;
+ QQuickGridMesh m_defaultMesh;
+ QQuickShaderEffect::CullMode m_cullMode;
+ QString m_log;
+ QQuickShaderEffect::Status m_status;
+
+ QQuickOpenGLShaderEffectCommon m_common;
+
+ uint m_blending : 1;
+ uint m_dirtyUniforms : 1;
+ uint m_dirtyUniformValues : 1;
+ uint m_dirtyTextureProviders : 1;
+ uint m_dirtyProgram : 1;
+ uint m_dirtyParseLog : 1;
+ uint m_dirtyMesh : 1;
+ uint m_dirtyGeometry : 1;
+ uint m_customVertexShader : 1;
+ uint m_supportsAtlasTextures : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKOPENGLSHADEREFFECT_P_H
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickopenglshadereffectnode.cpp
index 246a713dca..02b76b2dbc 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickopenglshadereffectnode.cpp
@@ -37,14 +37,15 @@
**
****************************************************************************/
-#include <private/qquickshadereffectnode_p.h>
+#include <private/qquickopenglshadereffectnode_p.h>
-#include "qquickshadereffect_p.h"
+#include "qquickopenglshadereffect_p.h"
#include <QtQuick/qsgtextureprovider.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgshadersourcebuilder_p.h>
#include <QtQuick/private/qsgtexture_p.h>
#include <QtCore/qmutex.h>
+#include <QtGui/qopenglfunctions.h>
QT_BEGIN_NAMESPACE
@@ -61,29 +62,29 @@ static bool hasAtlasTexture(const QVector<QSGTextureProvider *> &textureProvider
class QQuickCustomMaterialShader : public QSGMaterialShader
{
public:
- QQuickCustomMaterialShader(const QQuickShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes);
+ QQuickCustomMaterialShader(const QQuickOpenGLShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes);
void deactivate() Q_DECL_OVERRIDE;
void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) Q_DECL_OVERRIDE;
char const *const *attributeNames() const Q_DECL_OVERRIDE;
protected:
- friend class QQuickShaderEffectNode;
+ friend class QQuickOpenGLShaderEffectNode;
void compile() Q_DECL_OVERRIDE;
const char *vertexShader() const Q_DECL_OVERRIDE;
const char *fragmentShader() const Q_DECL_OVERRIDE;
- const QQuickShaderEffectMaterialKey m_key;
+ const QQuickOpenGLShaderEffectMaterialKey m_key;
QVector<QByteArray> m_attributes;
QVector<const char *> m_attributeNames;
QString m_log;
bool m_compiled;
- QVector<int> m_uniformLocs[QQuickShaderEffectMaterialKey::ShaderTypeCount];
+ QVector<int> m_uniformLocs[QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount];
uint m_initialized : 1;
};
-QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
+QQuickCustomMaterialShader::QQuickCustomMaterialShader(const QQuickOpenGLShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes)
: m_key(key)
, m_attributes(attributes)
, m_compiled(false)
@@ -104,11 +105,11 @@ void QQuickCustomMaterialShader::deactivate()
void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
- typedef QQuickShaderEffectMaterial::UniformData UniformData;
+ typedef QQuickOpenGLShaderEffectMaterial::UniformData UniformData;
Q_ASSERT(newEffect != 0);
- QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(newEffect);
+ QQuickOpenGLShaderEffectMaterial *material = static_cast<QQuickOpenGLShaderEffectMaterial *>(newEffect);
if (!material->m_emittedLogChanged && material->m_node) {
material->m_emittedLogChanged = true;
emit material->m_node->logAndStatusChanged(m_log, m_compiled ? QQuickShaderEffect::Compiled
@@ -117,7 +118,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
int textureProviderIndex = 0;
if (!m_initialized) {
- for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
+ for (int shaderType = 0; shaderType < QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
Q_ASSERT(m_uniformLocs[shaderType].isEmpty());
m_uniformLocs[shaderType].reserve(material->uniforms[shaderType].size());
for (int i = 0; i < material->uniforms[shaderType].size(); ++i) {
@@ -138,7 +139,7 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
}
QOpenGLFunctions *functions = state.context()->functions();
- for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
+ for (int shaderType = 0; shaderType < QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
for (int i = 0; i < material->uniforms[shaderType].size(); ++i) {
const UniformData &d = material->uniforms[shaderType].at(i);
int loc = m_uniformLocs[shaderType].at(i);
@@ -230,14 +231,14 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
}
functions->glActiveTexture(GL_TEXTURE0);
- const QQuickShaderEffectMaterial *oldMaterial = static_cast<const QQuickShaderEffectMaterial *>(oldEffect);
+ const QQuickOpenGLShaderEffectMaterial *oldMaterial = static_cast<const QQuickOpenGLShaderEffectMaterial *>(oldEffect);
if (oldEffect == 0 || material->cullMode != oldMaterial->cullMode) {
switch (material->cullMode) {
- case QQuickShaderEffectMaterial::FrontFaceCulling:
+ case QQuickShaderEffect::FrontFaceCulling:
functions->glEnable(GL_CULL_FACE);
functions->glCullFace(GL_FRONT);
break;
- case QQuickShaderEffectMaterial::BackFaceCulling:
+ case QQuickShaderEffect::BackFaceCulling:
functions->glEnable(GL_CULL_FACE);
functions->glCullFace(GL_BACK);
break;
@@ -322,16 +323,16 @@ void QQuickCustomMaterialShader::compile()
const char *QQuickCustomMaterialShader::vertexShader() const
{
- return m_key.sourceCode[QQuickShaderEffectMaterialKey::VertexShader].constData();
+ return m_key.sourceCode[QQuickOpenGLShaderEffectMaterialKey::VertexShader].constData();
}
const char *QQuickCustomMaterialShader::fragmentShader() const
{
- return m_key.sourceCode[QQuickShaderEffectMaterialKey::FragmentShader].constData();
+ return m_key.sourceCode[QQuickOpenGLShaderEffectMaterialKey::FragmentShader].constData();
}
-bool QQuickShaderEffectMaterialKey::operator == (const QQuickShaderEffectMaterialKey &other) const
+bool QQuickOpenGLShaderEffectMaterialKey::operator == (const QQuickOpenGLShaderEffectMaterialKey &other) const
{
for (int shaderType = 0; shaderType < ShaderTypeCount; ++shaderType) {
if (sourceCode[shaderType] != other.sourceCode[shaderType])
@@ -340,39 +341,39 @@ bool QQuickShaderEffectMaterialKey::operator == (const QQuickShaderEffectMateria
return true;
}
-bool QQuickShaderEffectMaterialKey::operator != (const QQuickShaderEffectMaterialKey &other) const
+bool QQuickOpenGLShaderEffectMaterialKey::operator != (const QQuickOpenGLShaderEffectMaterialKey &other) const
{
return !(*this == other);
}
-uint qHash(const QQuickShaderEffectMaterialKey &key)
+uint qHash(const QQuickOpenGLShaderEffectMaterialKey &key)
{
uint hash = 1;
- typedef QQuickShaderEffectMaterialKey Key;
+ typedef QQuickOpenGLShaderEffectMaterialKey Key;
for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
hash = hash * 31337 + qHash(key.sourceCode[shaderType]);
return hash;
}
-class QQuickShaderEffectMaterialCache : public QObject
+class QQuickOpenGLShaderEffectMaterialCache : public QObject
{
Q_OBJECT
public:
- static QQuickShaderEffectMaterialCache *get(bool create = true) {
+ static QQuickOpenGLShaderEffectMaterialCache *get(bool create = true) {
QOpenGLContext *ctx = QOpenGLContext::currentContext();
- QQuickShaderEffectMaterialCache *me = ctx->findChild<QQuickShaderEffectMaterialCache *>(QStringLiteral("__qt_ShaderEffectCache"), Qt::FindDirectChildrenOnly);
+ QQuickOpenGLShaderEffectMaterialCache *me = ctx->findChild<QQuickOpenGLShaderEffectMaterialCache *>(QStringLiteral("__qt_ShaderEffectCache"), Qt::FindDirectChildrenOnly);
if (!me && create) {
- me = new QQuickShaderEffectMaterialCache();
+ me = new QQuickOpenGLShaderEffectMaterialCache();
me->setObjectName(QStringLiteral("__qt_ShaderEffectCache"));
me->setParent(ctx);
}
return me;
}
- QHash<QQuickShaderEffectMaterialKey, QSGMaterialType *> cache;
+ QHash<QQuickOpenGLShaderEffectMaterialKey, QSGMaterialType *> cache;
};
-QQuickShaderEffectMaterial::QQuickShaderEffectMaterial(QQuickShaderEffectNode *node)
- : cullMode(NoCulling)
+QQuickOpenGLShaderEffectMaterial::QQuickOpenGLShaderEffectMaterial(QQuickOpenGLShaderEffectNode *node)
+ : cullMode(QQuickShaderEffect::NoCulling)
, geometryUsesTextureSubRect(false)
, m_node(node)
, m_emittedLogChanged(false)
@@ -380,17 +381,17 @@ QQuickShaderEffectMaterial::QQuickShaderEffectMaterial(QQuickShaderEffectNode *n
setFlag(Blending | RequiresFullMatrix, true);
}
-QSGMaterialType *QQuickShaderEffectMaterial::type() const
+QSGMaterialType *QQuickOpenGLShaderEffectMaterial::type() const
{
return m_type;
}
-QSGMaterialShader *QQuickShaderEffectMaterial::createShader() const
+QSGMaterialShader *QQuickOpenGLShaderEffectMaterial::createShader() const
{
return new QQuickCustomMaterialShader(m_source, attributes);
}
-bool QQuickShaderEffectMaterial::UniformData::operator == (const UniformData &other) const
+bool QQuickOpenGLShaderEffectMaterial::UniformData::operator == (const UniformData &other) const
{
if (specialType != other.specialType)
return false;
@@ -407,14 +408,14 @@ bool QQuickShaderEffectMaterial::UniformData::operator == (const UniformData &ot
}
}
-int QQuickShaderEffectMaterial::compare(const QSGMaterial *o) const
+int QQuickOpenGLShaderEffectMaterial::compare(const QSGMaterial *o) const
{
- const QQuickShaderEffectMaterial *other = static_cast<const QQuickShaderEffectMaterial *>(o);
+ const QQuickOpenGLShaderEffectMaterial *other = static_cast<const QQuickOpenGLShaderEffectMaterial *>(o);
if ((hasAtlasTexture(textureProviders) && !geometryUsesTextureSubRect) || (hasAtlasTexture(other->textureProviders) && !other->geometryUsesTextureSubRect))
return 1;
if (cullMode != other->cullMode)
return 1;
- for (int shaderType = 0; shaderType < QQuickShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
+ for (int shaderType = 0; shaderType < QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount; ++shaderType) {
if (uniforms[shaderType] != other->uniforms[shaderType])
return 1;
}
@@ -438,12 +439,12 @@ int QQuickShaderEffectMaterial::compare(const QSGMaterial *o) const
return 0;
}
-void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectMaterialKey &source)
+void QQuickOpenGLShaderEffectMaterial::setProgramSource(const QQuickOpenGLShaderEffectMaterialKey &source)
{
m_source = source;
m_emittedLogChanged = false;
- QQuickShaderEffectMaterialCache *cache = QQuickShaderEffectMaterialCache::get();
+ QQuickOpenGLShaderEffectMaterialCache *cache = QQuickOpenGLShaderEffectMaterialCache::get();
m_type = cache->cache.value(m_source);
if (!m_type) {
m_type = new QSGMaterialType();
@@ -451,16 +452,16 @@ void QQuickShaderEffectMaterial::setProgramSource(const QQuickShaderEffectMateri
}
}
-void QQuickShaderEffectMaterial::cleanupMaterialCache()
+void QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache()
{
- QQuickShaderEffectMaterialCache *cache = QQuickShaderEffectMaterialCache::get(false);
+ QQuickOpenGLShaderEffectMaterialCache *cache = QQuickOpenGLShaderEffectMaterialCache::get(false);
if (cache) {
- qDeleteAll(cache->cache.values());
+ qDeleteAll(cache->cache);
delete cache;
}
}
-void QQuickShaderEffectMaterial::updateTextures() const
+void QQuickOpenGLShaderEffectMaterial::updateTextures() const
{
for (int i = 0; i < textureProviders.size(); ++i) {
if (QSGTextureProvider *provider = textureProviders.at(i)) {
@@ -470,7 +471,7 @@ void QQuickShaderEffectMaterial::updateTextures() const
}
}
-void QQuickShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *provider)
+void QQuickOpenGLShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *provider)
{
for (int i = 0; i < textureProviders.size(); ++i) {
if (provider == textureProviders.at(i))
@@ -479,7 +480,7 @@ void QQuickShaderEffectMaterial::invalidateTextureProvider(QSGTextureProvider *p
}
-QQuickShaderEffectNode::QQuickShaderEffectNode()
+QQuickOpenGLShaderEffectNode::QQuickOpenGLShaderEffectNode()
{
QSGNode::setFlag(UsePreprocess, true);
@@ -488,28 +489,28 @@ QQuickShaderEffectNode::QQuickShaderEffectNode()
#endif
}
-QQuickShaderEffectNode::~QQuickShaderEffectNode()
+QQuickOpenGLShaderEffectNode::~QQuickOpenGLShaderEffectNode()
{
}
-void QQuickShaderEffectNode::markDirtyTexture()
+void QQuickOpenGLShaderEffectNode::markDirtyTexture()
{
markDirty(DirtyMaterial);
Q_EMIT dirtyTexture();
}
-void QQuickShaderEffectNode::textureProviderDestroyed(QObject *object)
+void QQuickOpenGLShaderEffectNode::textureProviderDestroyed(QObject *object)
{
Q_ASSERT(material());
- static_cast<QQuickShaderEffectMaterial *>(material())->invalidateTextureProvider(static_cast<QSGTextureProvider *>(object));
+ static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->invalidateTextureProvider(static_cast<QSGTextureProvider *>(object));
}
-void QQuickShaderEffectNode::preprocess()
+void QQuickOpenGLShaderEffectNode::preprocess()
{
Q_ASSERT(material());
- static_cast<QQuickShaderEffectMaterial *>(material())->updateTextures();
+ static_cast<QQuickOpenGLShaderEffectMaterial *>(material())->updateTextures();
}
-#include "qquickshadereffectnode.moc"
+#include "qquickopenglshadereffectnode.moc"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickopenglshadereffectnode_p.h
index ff32f4e290..adf5ef730b 100644
--- a/src/quick/items/qquickshadereffectnode_p.h
+++ b/src/quick/items/qquickopenglshadereffectnode_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QQUICKSHADEREFFECTNODE_P_H
-#define QQUICKSHADEREFFECTNODE_P_H
+#ifndef QQUICKOPENGLSHADEREFFECTNODE_P_H
+#define QQUICKOPENGLSHADEREFFECTNODE_P_H
//
// W A R N I N G
@@ -56,13 +56,14 @@
#include <QtQuick/qsgtextureprovider.h>
#include <QtQuick/qquickitem.h>
#include <private/qtquickglobal_p.h>
+#include <private/qquickshadereffect_p.h>
#include <QtCore/qsharedpointer.h>
#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
-struct QQuickShaderEffectMaterialKey {
+struct QQuickOpenGLShaderEffectMaterialKey {
enum ShaderType
{
VertexShader,
@@ -72,15 +73,15 @@ struct QQuickShaderEffectMaterialKey {
QByteArray sourceCode[ShaderTypeCount];
- bool operator == (const QQuickShaderEffectMaterialKey &other) const;
- bool operator != (const QQuickShaderEffectMaterialKey &other) const;
+ bool operator == (const QQuickOpenGLShaderEffectMaterialKey &other) const;
+ bool operator != (const QQuickOpenGLShaderEffectMaterialKey &other) const;
};
-uint qHash(const QQuickShaderEffectMaterialKey &key);
+uint qHash(const QQuickOpenGLShaderEffectMaterialKey &key);
class QQuickCustomMaterialShader;
-class QQuickShaderEffectNode;
-class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectMaterial : public QSGMaterial
+class QQuickOpenGLShaderEffectNode;
+class Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectMaterial : public QSGMaterial
{
public:
struct UniformData
@@ -94,25 +95,18 @@ public:
bool operator == (const UniformData &other) const;
};
- enum CullMode
- {
- NoCulling,
- BackFaceCulling,
- FrontFaceCulling
- };
-
- explicit QQuickShaderEffectMaterial(QQuickShaderEffectNode *node = 0);
+ explicit QQuickOpenGLShaderEffectMaterial(QQuickOpenGLShaderEffectNode *node = 0);
QSGMaterialType *type() const Q_DECL_OVERRIDE;
QSGMaterialShader *createShader() const Q_DECL_OVERRIDE;
int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE;
QVector<QByteArray> attributes;
- QVector<UniformData> uniforms[QQuickShaderEffectMaterialKey::ShaderTypeCount];
+ QVector<UniformData> uniforms[QQuickOpenGLShaderEffectMaterialKey::ShaderTypeCount];
QVector<QSGTextureProvider *> textureProviders;
- CullMode cullMode;
+ QQuickShaderEffect::CullMode cullMode;
bool geometryUsesTextureSubRect;
- void setProgramSource(const QQuickShaderEffectMaterialKey &source);
+ void setProgramSource(const QQuickOpenGLShaderEffectMaterialKey &source);
void updateTextures() const;
void invalidateTextureProvider(QSGTextureProvider *provider);
@@ -127,21 +121,21 @@ protected:
// type. The type is cleaned up in cleanupMaterialCache() which is called
// when the GL context is shut down.
QSGMaterialType *m_type;
- QQuickShaderEffectMaterialKey m_source;
+ QQuickOpenGLShaderEffectMaterialKey m_source;
- QQuickShaderEffectNode *m_node;
+ QQuickOpenGLShaderEffectNode *m_node;
bool m_emittedLogChanged;
};
class QSGShaderEffectMesh;
-class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectNode : public QObject, public QSGGeometryNode
+class Q_QUICK_PRIVATE_EXPORT QQuickOpenGLShaderEffectNode : public QObject, public QSGGeometryNode
{
Q_OBJECT
public:
- QQuickShaderEffectNode();
- virtual ~QQuickShaderEffectNode();
+ QQuickOpenGLShaderEffectNode();
+ virtual ~QQuickOpenGLShaderEffectNode();
void preprocess() Q_DECL_OVERRIDE;
@@ -156,4 +150,4 @@ private Q_SLOTS:
QT_END_NAMESPACE
-#endif // QQUICKSHADEREFFECTNODE_P_H
+#endif // QQUICKOPENGLSHADEREFFECTNODE_P_H
diff --git a/src/quick/items/qquickpainteditem.cpp b/src/quick/items/qquickpainteditem.cpp
index 75919d0791..d21eb93dbf 100644
--- a/src/quick/items/qquickpainteditem.cpp
+++ b/src/quick/items/qquickpainteditem.cpp
@@ -63,13 +63,14 @@ public:
\inmodule QtQuick
- The QQuickPaintedItem makes it possible to use the QPainter API with the QML Scene Graph.
- It sets up a textured rectangle in the Scene Graph and uses a QPainter to paint
- onto the texture. The render target can be either a QImage or a QOpenGLFramebufferObject.
- When the render target is a QImage, QPainter first renders into the image then
- the content is uploaded to the texture.
- When a QOpenGLFramebufferObject is used, QPainter paints directly onto the texture.
- Call update() to trigger a repaint.
+ The QQuickPaintedItem makes it possible to use the QPainter API with the
+ QML Scene Graph. It sets up a textured rectangle in the Scene Graph and
+ uses a QPainter to paint onto the texture. The render target can be either
+ a QImage or, when OpenGL is in use, a QOpenGLFramebufferObject. When the
+ render target is a QImage, QPainter first renders into the image then the
+ content is uploaded to the texture. When a QOpenGLFramebufferObject is
+ used, QPainter paints directly onto the texture. Call update() to trigger a
+ repaint.
To enable QPainter to do anti-aliased rendering, use setAntialiasing().
@@ -78,6 +79,10 @@ public:
public function: paint(), which implements the actual painting. The
painting will be inside the rectangle spanning from 0,0 to
width(),height().
+
+ \note It important to understand the performance implications such items
+ can incur. See QQuickPaintedItem::RenderTarget and
+ QQuickPaintedItem::renderTarget.
*/
/*!
@@ -172,8 +177,6 @@ QQuickPaintedItem::~QQuickPaintedItem()
is processed by the QML Scene Graph when the next frame is rendered. The item will only be
redrawn if it is visible.
- Note that calling this function will trigger a repaint of the whole scene.
-
\sa paint()
*/
void QQuickPaintedItem::update(const QRect &rect)
@@ -499,6 +502,12 @@ void QQuickPaintedItem::setFillColor(const QColor &c)
the QQuickPaintedItem::FramebufferObject render target if the item gets resized often.
By default, the render target is QQuickPaintedItem::Image.
+
+ \note Some Qt Quick backends may not support all render target options. For
+ example, it is likely that non-OpenGL backends will lack support for
+ QQuickPaintedItem::FramebufferObject and
+ QQuickPaintedItem::InvertedYFramebufferObject. Requesting these will then
+ be ignored.
*/
QQuickPaintedItem::RenderTarget QQuickPaintedItem::renderTarget() const
{
@@ -652,11 +661,13 @@ QSGTextureProvider *QQuickPaintedItem::textureProvider() const
return QQuickItem::textureProvider();
Q_D(const QQuickPaintedItem);
+#ifndef QT_NO_OPENGL
QQuickWindow *w = window();
if (!w || !w->openglContext() || QThread::currentThread() != w->openglContext()->thread()) {
qWarning("QQuickPaintedItem::textureProvider: can only be queried on the rendering thread of an exposed window");
return 0;
}
+#endif
if (!d->textureProvider)
d->textureProvider = new QQuickPaintedItemTextureProvider();
d->textureProvider->node = d->node;
diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h
index d9c4baf572..652af3487f 100644
--- a/src/quick/items/qquickpathview_p_p.h
+++ b/src/quick/items/qquickpathview_p_p.h
@@ -61,6 +61,7 @@
#include <private/qquickanimation_p_p.h>
#include <private/qqmldelegatemodel_p.h>
#include <private/qquicktimeline_p_p.h>
+#include <private/qpodvector_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index 74ca0f482a..b8c680433e 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -44,7 +44,6 @@
#include <private/qsgadaptationlayer_p.h>
#include <QtGui/qpixmapcache.h>
-#include <QtCore/qstringbuilder.h>
#include <QtCore/qmath.h>
#include <QtCore/qmetaobject.h>
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index e36df53d38..dbe1add345 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -44,7 +44,11 @@
#include <QtCore/QTime>
#include <QtQuick/private/qquickanimatorcontroller_p.h>
-#include <QtGui/QOpenGLContext>
+#ifndef QT_NO_OPENGL
+# include <QtGui/QOpenGLContext>
+# include <QtQuick/private/qsgdefaultrendercontext_p.h>
+# include <QtQuick/private/qquickopenglshadereffectnode_p.h>
+#endif
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
@@ -54,12 +58,11 @@
#include <QtQuick/private/qquickwindow_p.h>
#include <QtCore/private/qobject_p.h>
-#include <private/qquickshadereffectnode_p.h>
QT_BEGIN_NAMESPACE
-
+#ifndef QT_NO_OPENGL
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-
+#endif
/*!
\class QQuickRenderControl
@@ -134,7 +137,7 @@ QQuickRenderControlPrivate::QQuickRenderControlPrivate()
qAddPostRoutine(cleanup);
sg = QSGContext::createDefaultContext();
}
- rc = new QSGRenderContext(sg);
+ rc = sg->createRenderContext();
}
void QQuickRenderControlPrivate::cleanup()
@@ -183,7 +186,9 @@ void QQuickRenderControlPrivate::windowDestroyed()
delete QQuickWindowPrivate::get(window)->animationController;
QQuickWindowPrivate::get(window)->animationController = 0;
- QQuickShaderEffectMaterial::cleanupMaterialCache();
+#ifndef QT_NO_OPENGL
+ QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
+#endif
window = 0;
}
@@ -213,8 +218,9 @@ void QQuickRenderControl::prepareThread(QThread *targetThread)
*/
void QQuickRenderControl::initialize(QOpenGLContext *gl)
{
- Q_D(QQuickRenderControl);
+ Q_D(QQuickRenderControl);
+#ifndef QT_NO_OPENGL
if (!d->window) {
qWarning("QQuickRenderControl::initialize called with no associated window");
return;
@@ -229,9 +235,10 @@ void QQuickRenderControl::initialize(QOpenGLContext *gl)
// It cannot be done here since the surface to use may not be the
// surface belonging to window. In fact window may not have a native
// window/surface at all.
-
d->rc->initialize(gl);
-
+#else
+ Q_UNUSED(gl)
+#endif
d->initialized = true;
}
@@ -247,7 +254,7 @@ void QQuickRenderControl::polishItems()
return;
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
- cd->flushDelayedTouchEvent();
+ cd->flushFrameSynchronousEvents();
if (!d->window)
return;
cd->polishItems();
@@ -363,7 +370,11 @@ QImage QQuickRenderControl::grab()
return QImage();
render();
+#ifndef QT_NO_OPENGL
QImage grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false);
+#else
+ QImage grabContent = d->window->grabWindow();
+#endif
return grabContent;
}
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index d5c0cc8180..f7fc7880ed 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -38,506 +38,14 @@
****************************************************************************/
#include <private/qquickshadereffect_p.h>
-#include <private/qquickshadereffectnode_p.h>
-
-#include <QtQuick/qsgmaterial.h>
-#include <QtQuick/private/qsgshadersourcebuilder_p.h>
-#include "qquickitem_p.h"
-
-#include <QtQuick/private/qsgcontext_p.h>
-#include <QtQuick/qsgtextureprovider.h>
-#include "qquickwindow.h"
-
-#include "qquickimage_p.h"
-#include "qquickshadereffectsource_p.h"
-
-#include <QtCore/qsignalmapper.h>
-#include <QtGui/qopenglframebufferobject.h>
+#include <private/qsgcontextplugin_p.h>
+#ifndef QT_NO_OPENGL
+#include <private/qquickopenglshadereffect_p.h>
+#endif
+#include <private/qquickgenericshadereffect_p.h>
QT_BEGIN_NAMESPACE
-static const char qt_position_attribute_name[] = "qt_Vertex";
-static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0";
-
-const char *qtPositionAttributeName()
-{
- return qt_position_attribute_name;
-}
-
-const char *qtTexCoordAttributeName()
-{
- return qt_texcoord_attribute_name;
-}
-
-namespace {
-
- enum VariableQualifier {
- AttributeQualifier,
- UniformQualifier
- };
-
- inline bool qt_isalpha(char c)
- {
- char ch = c | 0x20;
- return (ch >= 'a' && ch <= 'z') || c == '_';
- }
-
- inline bool qt_isalnum(char c)
- {
- return qt_isalpha(c) || (c >= '0' && c <= '9');
- }
-
- inline bool qt_isspace(char c)
- {
- return c == ' ' || (c >= 0x09 && c <= 0x0d);
- }
-
- // Returns -1 if not found, returns index to first character after the name if found.
- int qt_search_for_variable(const char *s, int length, int index, VariableQualifier &decl,
- int &typeIndex, int &typeLength,
- int &nameIndex, int &nameLength,
- QQuickShaderEffectCommon::Key::ShaderType shaderType)
- {
- enum Identifier {
- QualifierIdentifier, // Base state
- PrecisionIdentifier,
- TypeIdentifier,
- NameIdentifier
- };
- Identifier expected = QualifierIdentifier;
- bool compilerDirectiveExpected = index == 0;
-
- while (index < length) {
- // Skip whitespace.
- while (qt_isspace(s[index])) {
- compilerDirectiveExpected |= s[index] == '\n';
- ++index;
- }
-
- if (qt_isalpha(s[index])) {
- // Read identifier.
- int idIndex = index;
- ++index;
- while (qt_isalnum(s[index]))
- ++index;
- int idLength = index - idIndex;
-
- const int attrLen = sizeof("attribute") - 1;
- const int inLen = sizeof("in") - 1;
- const int uniLen = sizeof("uniform") - 1;
- const int loLen = sizeof("lowp") - 1;
- const int medLen = sizeof("mediump") - 1;
- const int hiLen = sizeof("highp") - 1;
-
- switch (expected) {
- case QualifierIdentifier:
- if (idLength == attrLen && qstrncmp("attribute", s + idIndex, attrLen) == 0) {
- decl = AttributeQualifier;
- expected = PrecisionIdentifier;
- } else if (shaderType == QQuickShaderEffectCommon::Key::VertexShader
- && idLength == inLen && qstrncmp("in", s + idIndex, inLen) == 0) {
- decl = AttributeQualifier;
- expected = PrecisionIdentifier;
- } else if (idLength == uniLen && qstrncmp("uniform", s + idIndex, uniLen) == 0) {
- decl = UniformQualifier;
- expected = PrecisionIdentifier;
- }
- break;
- case PrecisionIdentifier:
- if ((idLength == loLen && qstrncmp("lowp", s + idIndex, loLen) == 0)
- || (idLength == medLen && qstrncmp("mediump", s + idIndex, medLen) == 0)
- || (idLength == hiLen && qstrncmp("highp", s + idIndex, hiLen) == 0))
- {
- expected = TypeIdentifier;
- break;
- }
- // Fall through.
- case TypeIdentifier:
- typeIndex = idIndex;
- typeLength = idLength;
- expected = NameIdentifier;
- break;
- case NameIdentifier:
- nameIndex = idIndex;
- nameLength = idLength;
- return index; // Attribute or uniform declaration found. Return result.
- default:
- break;
- }
- } else if (s[index] == '#' && compilerDirectiveExpected) {
- // Skip compiler directives.
- ++index;
- while (index < length && (s[index] != '\n' || s[index - 1] == '\\'))
- ++index;
- } else if (s[index] == '/' && s[index + 1] == '/') {
- // Skip comments.
- index += 2;
- while (index < length && s[index] != '\n')
- ++index;
- } else if (s[index] == '/' && s[index + 1] == '*') {
- // Skip comments.
- index += 2;
- while (index < length && (s[index] != '*' || s[index + 1] != '/'))
- ++index;
- if (index < length)
- index += 2; // Skip star-slash.
- } else {
- expected = QualifierIdentifier;
- ++index;
- }
- compilerDirectiveExpected = false;
- }
- return -1;
- }
-}
-
-
-
-QQuickShaderEffectCommon::~QQuickShaderEffectCommon()
-{
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
- qDeleteAll(signalMappers[shaderType]);
-}
-
-void QQuickShaderEffectCommon::disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
-{
- for (int i = 0; i < uniformData[shaderType].size(); ++i) {
- if (signalMappers[shaderType].at(i) == 0)
- continue;
- const UniformData &d = uniformData[shaderType].at(i);
- QSignalMapper *mapper = signalMappers[shaderType].at(i);
- QObject::disconnect(item, 0, mapper, SLOT(map()));
- QObject::disconnect(mapper, SIGNAL(mapped(int)), item, SLOT(propertyChanged(int)));
- if (d.specialType == UniformData::Sampler) {
- QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
- if (source) {
- if (item->window())
- QQuickItemPrivate::get(source)->derefWindow();
- QObject::disconnect(source, SIGNAL(destroyed(QObject*)), item, SLOT(sourceDestroyed(QObject*)));
- }
- }
- }
-}
-
-void QQuickShaderEffectCommon::connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType)
-{
- for (int i = 0; i < uniformData[shaderType].size(); ++i) {
- if (signalMappers[shaderType].at(i) == 0)
- continue;
- const UniformData &d = uniformData[shaderType].at(i);
- int pi = item->metaObject()->indexOfProperty(d.name.constData());
- if (pi >= 0) {
- QMetaProperty mp = item->metaObject()->property(pi);
- if (!mp.hasNotifySignal())
- qWarning("QQuickShaderEffect: property '%s' does not have notification method!", d.name.constData());
- const QByteArray signalName = '2' + mp.notifySignal().methodSignature();
- QSignalMapper *mapper = signalMappers[shaderType].at(i);
- QObject::connect(item, signalName, mapper, SLOT(map()));
- QObject::connect(mapper, SIGNAL(mapped(int)), item, SLOT(propertyChanged(int)));
- } else {
- // If the source is set via a dynamic property, like the layer is, then we need this
- // check to disable the warning.
- if (!item->property(d.name.constData()).isValid())
- qWarning("QQuickShaderEffect: '%s' does not have a matching property!", d.name.constData());
- }
-
- if (d.specialType == UniformData::Sampler) {
- QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
- if (source) {
- if (item->window())
- QQuickItemPrivate::get(source)->refWindow(item->window());
- QObject::connect(source, SIGNAL(destroyed(QObject*)), item, SLOT(sourceDestroyed(QObject*)));
- }
- }
- }
-}
-
-void QQuickShaderEffectCommon::updateParseLog(bool ignoreAttributes)
-{
- parseLog.clear();
- if (!ignoreAttributes) {
- if (!attributes.contains(qt_position_attribute_name)) {
- parseLog += QLatin1String("Warning: Missing reference to \'");
- parseLog += QLatin1String(qt_position_attribute_name);
- parseLog += QLatin1String("\'.\n");
- }
- if (!attributes.contains(qt_texcoord_attribute_name)) {
- parseLog += QLatin1String("Warning: Missing reference to \'");
- parseLog += QLatin1String(qt_texcoord_attribute_name);
- parseLog += QLatin1String("\'.\n");
- }
- }
- bool respectsMatrix = false;
- bool respectsOpacity = false;
- for (int i = 0; i < uniformData[Key::VertexShader].size(); ++i)
- respectsMatrix |= uniformData[Key::VertexShader].at(i).specialType == UniformData::Matrix;
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
- for (int i = 0; i < uniformData[shaderType].size(); ++i)
- respectsOpacity |= uniformData[shaderType].at(i).specialType == UniformData::Opacity;
- }
- if (!respectsMatrix)
- parseLog += QLatin1String("Warning: Vertex shader is missing reference to \'qt_Matrix\'.\n");
- if (!respectsOpacity)
- parseLog += QLatin1String("Warning: Shaders are missing reference to \'qt_Opacity\'.\n");
-}
-
-void QQuickShaderEffectCommon::lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code)
-{
- int index = 0;
- int typeIndex = -1;
- int typeLength = 0;
- int nameIndex = -1;
- int nameLength = 0;
- const char *s = code.constData();
- VariableQualifier decl = AttributeQualifier;
- while ((index = qt_search_for_variable(s, code.size(), index, decl, typeIndex, typeLength,
- nameIndex, nameLength, shaderType)) != -1)
- {
- if (decl == AttributeQualifier) {
- if (shaderType == Key::VertexShader)
- attributes.append(QByteArray(s + nameIndex, nameLength));
- } else {
- Q_ASSERT(decl == UniformQualifier);
-
- const int sampLen = sizeof("sampler2D") - 1;
- const int opLen = sizeof("qt_Opacity") - 1;
- const int matLen = sizeof("qt_Matrix") - 1;
- const int srLen = sizeof("qt_SubRect_") - 1;
-
- UniformData d;
- QSignalMapper *mapper = 0;
- d.name = QByteArray(s + nameIndex, nameLength);
- if (nameLength == opLen && qstrncmp("qt_Opacity", s + nameIndex, opLen) == 0) {
- d.specialType = UniformData::Opacity;
- } else if (nameLength == matLen && qstrncmp("qt_Matrix", s + nameIndex, matLen) == 0) {
- d.specialType = UniformData::Matrix;
- } else if (nameLength > srLen && qstrncmp("qt_SubRect_", s + nameIndex, srLen) == 0) {
- d.specialType = UniformData::SubRect;
- } else {
- mapper = new QSignalMapper;
- mapper->setMapping(item, uniformData[shaderType].size() | (shaderType << 16));
- d.value = item->property(d.name.constData());
- bool sampler = typeLength == sampLen && qstrncmp("sampler2D", s + typeIndex, sampLen) == 0;
- d.specialType = sampler ? UniformData::Sampler : UniformData::None;
- }
- uniformData[shaderType].append(d);
- signalMappers[shaderType].append(mapper);
- }
- }
-}
-
-void QQuickShaderEffectCommon::updateShader(QQuickItem *item, Key::ShaderType shaderType)
-{
- disconnectPropertySignals(item, shaderType);
- qDeleteAll(signalMappers[shaderType]);
- uniformData[shaderType].clear();
- signalMappers[shaderType].clear();
- if (shaderType == Key::VertexShader)
- attributes.clear();
-
- const QByteArray &code = source.sourceCode[shaderType];
- if (code.isEmpty()) {
- // Optimize for default code.
- if (shaderType == Key::VertexShader) {
- attributes.append(QByteArray(qt_position_attribute_name));
- attributes.append(QByteArray(qt_texcoord_attribute_name));
- UniformData d;
- d.name = "qt_Matrix";
- d.specialType = UniformData::Matrix;
- uniformData[Key::VertexShader].append(d);
- signalMappers[Key::VertexShader].append(0);
- } else if (shaderType == Key::FragmentShader) {
- UniformData d;
- d.name = "qt_Opacity";
- d.specialType = UniformData::Opacity;
- uniformData[Key::FragmentShader].append(d);
- signalMappers[Key::FragmentShader].append(0);
- QSignalMapper *mapper = new QSignalMapper;
- mapper->setMapping(item, 1 | (Key::FragmentShader << 16));
- const char *sourceName = "source";
- d.name = sourceName;
- d.value = item->property(sourceName);
- d.specialType = UniformData::Sampler;
- uniformData[Key::FragmentShader].append(d);
- signalMappers[Key::FragmentShader].append(mapper);
- }
- } else {
- lookThroughShaderCode(item, shaderType, code);
- }
-
- connectPropertySignals(item, shaderType);
-}
-
-void QQuickShaderEffectCommon::updateMaterial(QQuickShaderEffectNode *node,
- QQuickShaderEffectMaterial *material,
- bool updateUniforms, bool updateUniformValues,
- bool updateTextureProviders)
-{
- if (updateUniforms) {
- for (int i = 0; i < material->textureProviders.size(); ++i) {
- QSGTextureProvider *t = material->textureProviders.at(i);
- if (t) {
- QObject::disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
- QObject::disconnect(t, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
- }
- }
-
- // First make room in the textureProviders array. Set to proper value further down.
- int textureProviderCount = 0;
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
- for (int i = 0; i < uniformData[shaderType].size(); ++i) {
- if (uniformData[shaderType].at(i).specialType == UniformData::Sampler)
- ++textureProviderCount;
- }
- material->uniforms[shaderType] = uniformData[shaderType];
- }
- material->textureProviders.fill(0, textureProviderCount);
- updateUniformValues = false;
- updateTextureProviders = true;
- }
-
- if (updateUniformValues) {
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
- Q_ASSERT(uniformData[shaderType].size() == material->uniforms[shaderType].size());
- for (int i = 0; i < uniformData[shaderType].size(); ++i)
- material->uniforms[shaderType][i].value = uniformData[shaderType].at(i).value;
- }
- }
-
- if (updateTextureProviders) {
- int index = 0;
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
- for (int i = 0; i < uniformData[shaderType].size(); ++i) {
- const UniformData &d = uniformData[shaderType].at(i);
- if (d.specialType != UniformData::Sampler)
- continue;
- QSGTextureProvider *oldProvider = material->textureProviders.at(index);
- QSGTextureProvider *newProvider = 0;
- QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
- if (source && source->isTextureProvider())
- newProvider = source->textureProvider();
- if (newProvider != oldProvider) {
- if (oldProvider) {
- QObject::disconnect(oldProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
- QObject::disconnect(oldProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
- }
- if (newProvider) {
- Q_ASSERT_X(newProvider->thread() == QThread::currentThread(),
- "QQuickShaderEffect::updatePaintNode",
- "Texture provider must belong to the rendering thread");
- QObject::connect(newProvider, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
- QObject::connect(newProvider, SIGNAL(destroyed(QObject*)), node, SLOT(textureProviderDestroyed(QObject*)));
- } else {
- const char *typeName = source ? source->metaObject()->className() : d.value.typeName();
- qWarning("ShaderEffect: Property '%s' is not assigned a valid texture provider (%s).",
- d.name.constData(), typeName);
- }
- material->textureProviders[index] = newProvider;
- }
- ++index;
- }
- }
- Q_ASSERT(index == material->textureProviders.size());
- }
-}
-
-void QQuickShaderEffectCommon::updateWindow(QQuickWindow *window)
-{
- // See comment in QQuickShaderEffectCommon::propertyChanged().
- if (window) {
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
- for (int i = 0; i < uniformData[shaderType].size(); ++i) {
- const UniformData &d = uniformData[shaderType].at(i);
- if (d.specialType == UniformData::Sampler) {
- QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
- if (source)
- QQuickItemPrivate::get(source)->refWindow(window);
- }
- }
- }
- } else {
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
- for (int i = 0; i < uniformData[shaderType].size(); ++i) {
- const UniformData &d = uniformData[shaderType].at(i);
- if (d.specialType == UniformData::Sampler) {
- QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
- if (source)
- QQuickItemPrivate::get(source)->derefWindow();
- }
- }
- }
- }
-}
-
-void QQuickShaderEffectCommon::sourceDestroyed(QObject *object)
-{
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
- for (int i = 0; i < uniformData[shaderType].size(); ++i) {
- UniformData &d = uniformData[shaderType][i];
- if (d.specialType == UniformData::Sampler && d.value.canConvert<QObject *>()) {
- if (qvariant_cast<QObject *>(d.value) == object)
- d.value = QVariant();
- }
- }
- }
-}
-
-static bool qquick_uniqueInUniformData(QQuickItem *source, const QVector<QQuickShaderEffectMaterial::UniformData> *uniformData, int typeToSkip, int indexToSkip)
-{
- for (int s=0; s<QQuickShaderEffectMaterialKey::ShaderTypeCount; ++s) {
- for (int i=0; i<uniformData[s].size(); ++i) {
- if (s == typeToSkip && i == indexToSkip)
- continue;
- const QQuickShaderEffectMaterial::UniformData &d = uniformData[s][i];
- if (d.specialType == QQuickShaderEffectMaterial::UniformData::Sampler && qvariant_cast<QObject *>(d.value) == source)
- return false;
- }
- }
- return true;
-}
-
-void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
- bool *textureProviderChanged)
-{
- Key::ShaderType shaderType = Key::ShaderType(mappedId >> 16);
- int index = mappedId & 0xffff;
- UniformData &d = uniformData[shaderType][index];
- if (d.specialType == UniformData::Sampler) {
- QQuickItem *source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
- if (source) {
- if (item->window())
- QQuickItemPrivate::get(source)->derefWindow();
-
- // QObject::disconnect() will disconnect all matching connections. If the same
- // source has been attached to two separate samplers, then changing one of them
- // would trigger both to be disconnected. Without the connection we'll end up
- // with a dangling pointer in the uniformData.
- if (qquick_uniqueInUniformData(source, uniformData, shaderType, index))
- QObject::disconnect(source, SIGNAL(destroyed(QObject*)), item, SLOT(sourceDestroyed(QObject*)));
- }
-
- d.value = item->property(d.name.constData());
-
- source = qobject_cast<QQuickItem *>(qvariant_cast<QObject *>(d.value));
- if (source) {
- // 'source' needs a window to get a scene graph node. It usually gets one through its
- // parent, but if the source item is "inline" rather than a reference -- i.e.
- // "property variant source: Image { }" instead of "property variant source: foo" -- it
- // will not get a parent. In those cases, 'source' should get the window from 'item'.
- if (item->window())
- QQuickItemPrivate::get(source)->refWindow(item->window());
- QObject::connect(source, SIGNAL(destroyed(QObject*)), item, SLOT(sourceDestroyed(QObject*)));
- }
- if (textureProviderChanged)
- *textureProviderChanged = true;
- } else {
- d.value = item->property(d.name.constData());
- if (textureProviderChanged)
- *textureProviderChanged = false;
- }
-}
-
-
/*!
\qmltype ShaderEffect
\instantiates QQuickShaderEffect
@@ -546,11 +54,18 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
\ingroup qtquick-effects
\brief Applies custom shaders to a rectangle
- The ShaderEffect type applies a custom OpenGL
- \l{vertexShader}{vertex} and \l{fragmentShader}{fragment} shader to a
+ The ShaderEffect type applies a custom
+ \l{vertexShader}{vertex} and \l{fragmentShader}{fragment (pixel)} shader to a
rectangle. It allows you to write effects such as drop shadow, blur,
colorize and page curl directly in QML.
+ \note Depending on the Qt Quick scenegraph backend in use, the ShaderEffect
+ type may not be supported (for example, with the software backend), or may
+ use a different shading language with rules and expectations different from
+ OpenGL and GLSL.
+
+ \section1 OpenGL and GLSL
+
There are two types of input to the \l vertexShader:
uniform variables and attributes. Some are predefined:
\list
@@ -650,9 +165,167 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
\endqml
\endtable
- By default, the ShaderEffect consists of four vertices, one for each
- corner. For non-linear vertex transformations, like page curl, you can
- specify a fine grid of vertices by specifying a \l mesh resolution.
+ \note Scene Graph textures have origin in the top-left corner rather than
+ bottom-left which is common in OpenGL.
+
+ For information about the GLSL version being used, see \l QtQuick::OpenGLInfo.
+
+ \section1 Direct3D and HLSL
+
+ Direct3D backends provide ShaderEffect support with HLSL. The Direct3D 12
+ backend requires using at least Shader Model 5.0 both for vertex and pixel
+ shaders. When necessary, GraphicsInfo.shaderType can be used to decide
+ at runtime what kind of value to assign to \l fragmentShader or
+ \l vertexShader.
+
+ All concepts described above for OpenGL and GLSL apply to Direct3D and HLSL
+ as well. There are however a number of notable practical differences, which
+ are the following:
+
+ Instead of uniforms, HLSL shaders are expected to use a single constant
+ buffer, assigned to register \c b0. The special names \c qt_Matrix,
+ \c qt_Opacity, and \c qt_SubRect_<name> function the same way as with GLSL.
+ All other members of the buffer are expected to map to properties in the
+ ShaderEffect item.
+
+ \note The buffer layout must be compatible for both shaders. This means
+ that application-provided shaders must make sure \c qt_Matrix and
+ \c qt_Opacity are included in the buffer, starting at offset 0, when custom
+ code is provided for one type of shader only, leading to ShaderEffect
+ providing the other shader. This is due to ShaderEffect's built-in shader code
+ declaring a constant buffer containing \c{float4x4 qt_Matrix; float qt_Opacity;}.
+
+ Unlike GLSL's attributes, no names are used for vertex input elements.
+ Therefore qt_Vertex and qt_MultiTexCoord0 are not relevant. Instead, the
+ standard Direct3D semantics, \c POSITION and \c TEXCOORD (or \c TEXCOORD0)
+ are used for identifying the correct input layout.
+
+ Unlike GLSL's samplers, texture and sampler objects are separate in HLSL.
+ Shaders are expected to expect 2D, non-array, non-multisample textures.
+ Both the texture and sampler binding points are expected to be sequential
+ and start from 0 (meaning registers \c{t0, t1, ...}, and \c{s0, s1, ...},
+ respectively). Unlike with OpenGL, samplers are not mapped to Qt Quick item
+ properties and therefore the name of the sampler is not relevant. Instead,
+ it is the textures that map to properties referencing \l Image or
+ \l ShaderEffectSource items.
+
+ Unlike with OpenGL, runtime compilation of shader source code may not be
+ supported. Backends for modern APIs are likely to prefer offline
+ compilation and shipping pre-compiled bytecode with applications instead of
+ inlined shader source strings. To check what is expected at runtime, use the
+ GraphicsInfo.shaderSourceType and GraphicsInfo.shaderCompilationType properties.
+
+ \table 70%
+ \row
+ \li \image declarative-shadereffectitem.png
+ \li \qml
+ import QtQuick 2.8
+
+ Rectangle {
+ width: 200; height: 100
+ Row {
+ Image { id: img;
+ sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
+ ShaderEffect {
+ width: 100; height: 100
+ property variant src: img
+ fragmentShader: "qrc:/effect_ps.cso"
+ }
+ }
+ }
+ \endqml
+ \row
+ \li where \c effect_ps.cso is the compiled bytecode for the following HLSL shader:
+ \code
+ cbuffer ConstantBuffer : register(b0)
+ {
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ };
+ Texture2D src : register(t0);
+ SamplerState srcSampler : register(s0);
+ float4 ExamplePixelShader(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
+ {
+ float4 tex = src.Sample(srcSampler, coord);
+ float3 col = dot(tex.rgb, float3(0.344, 0.5, 0.156));
+ return float4(col, tex.a) * qt_Opacity;
+ }
+ \endcode
+ \endtable
+
+ The above is equivalent to the OpenGL example presented earlier. The vertex
+ shader is provided implicitly by ShaderEffect. Note that the output of the
+ pixel shader is using premultiplied alpha and that \c qt_Matrix is present
+ in the constant buffer at offset 0, even though the pixel shader does not
+ use the value.
+
+ Some effects will want to provide a vertex shader as well. Below is a
+ similar effect with both the vertex and fragment shader provided by the
+ application. This time the colorization factor is provided by the QML item
+ instead of hardcoding it in the shader. This can allow, among others,
+ animating the value using QML's and Qt Quick's standard facilities.
+
+ \table 70%
+ \row
+ \li \image declarative-shadereffectitem.png
+ \li \qml
+ import QtQuick 2.8
+
+ Rectangle {
+ width: 200; height: 100
+ Row {
+ Image { id: img;
+ sourceSize { width: 100; height: 100 } source: "qt-logo.png" }
+ ShaderEffect {
+ width: 100; height: 100
+ property variant src: img
+ property variant color: Qt.vector3d(0.344, 0.5, 0.156)
+ vertexShader: "qrc:/effect_vs.cso"
+ fragmentShader: "qrc:/effect_ps.cso"
+ }
+ }
+ }
+ \endqml
+ \row
+ \li where \c effect_vs.cso and \c effect_ps.cso are the compiled bytecode
+ for \c ExampleVertexShader and \c ExamplePixelShader. The source code is
+ presented as one snippet here, the shaders can however be placed in
+ separate source files as well.
+ \code
+ cbuffer ConstantBuffer : register(b0)
+ {
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ float3 color;
+ };
+ Texture2D src : register(t0);
+ SamplerState srcSampler : register(s0);
+ struct PSInput
+ {
+ float4 position : SV_POSITION;
+ float2 coord : TEXCOORD0;
+ };
+ PSInput ExampleVertexShader(float4 position : POSITION, float2 coord : TEXCOORD0)
+ {
+ PSInput result;
+ result.position = mul(qt_Matrix, position);
+ result.coord = coord;
+ return result;
+ }
+ float4 ExamplePixelShader(PSInput input) : SV_TARGET
+ {
+ float4 tex = src.Sample(srcSampler, coord);
+ float3 col = dot(tex.rgb, color);
+ return float4(col, tex.a) * qt_Opacity;
+ }
+ \endcode
+ \endtable
+
+ \note With OpenGL the \c y coordinate runs from bottom to top whereas with
+ Direct 3D it goes top to bottom. For shader effect sources Qt Quick hides
+ the difference by treating QtQuick::ShaderEffectSource::textureMirroring as
+ appropriate, meaning texture coordinates in HLSL version of the shaders
+ will not need any adjustments compared to the equivalent GLSL code.
\section1 ShaderEffect and Item Layers
@@ -675,97 +348,117 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
\li \snippet qml/opacitymask.qml 1
\endtable
- The \l {Qt Graphical Effects} module contains several ready-made effects
- for using with Qt Quick applications.
+ \section1 Other notes
- \note Scene Graph textures have origin in the top-left corner rather than
- bottom-left which is common in OpenGL.
+ By default, the ShaderEffect consists of four vertices, one for each
+ corner. For non-linear vertex transformations, like page curl, you can
+ specify a fine grid of vertices by specifying a \l mesh resolution.
- For information about the GLSL version being used, see \l QtQuick::OpenGLInfo.
+ The \l {Qt Graphical Effects} module contains several ready-made effects
+ for using with Qt Quick applications.
\sa {Item Layers}
*/
+QSGContextFactoryInterface::Flags qsg_backend_flags();
+
QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
- : QQuickItem(parent)
- , m_meshResolution(1, 1)
- , m_mesh(0)
- , m_cullMode(NoCulling)
- , m_status(Uncompiled)
- , m_blending(true)
- , m_dirtyUniforms(true)
- , m_dirtyUniformValues(true)
- , m_dirtyTextureProviders(true)
- , m_dirtyProgram(true)
- , m_dirtyParseLog(true)
- , m_dirtyMesh(true)
- , m_dirtyGeometry(true)
- , m_customVertexShader(false)
- , m_supportsAtlasTextures(false)
+ : QQuickItem(parent),
+#ifndef QT_NO_OPENGL
+ m_glImpl(nullptr),
+#endif
+ m_impl(nullptr)
{
setFlag(QQuickItem::ItemHasContents);
-}
-QQuickShaderEffect::~QQuickShaderEffect()
-{
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType)
- m_common.disconnectPropertySignals(this, Key::ShaderType(shaderType));
+#ifndef QT_NO_OPENGL
+ if (!qsg_backend_flags().testFlag(QSGContextFactoryInterface::SupportsShaderEffectNode))
+ m_glImpl = new QQuickOpenGLShaderEffect(this, this);
+
+ if (!m_glImpl)
+#endif
+ m_impl = new QQuickGenericShaderEffect(this, this);
}
/*!
\qmlproperty string QtQuick::ShaderEffect::fragmentShader
- This property holds the fragment shader's GLSL source code.
- The default shader expects the texture coordinate to be passed from the
- vertex shader as "varying highp vec2 qt_TexCoord0", and it samples from a
- sampler2D named "source".
+ This property holds the fragment (pixel) shader's source code or a
+ reference to the pre-compiled bytecode. Some APIs, like OpenGL, always
+ support runtime compilation and therefore the traditional Qt Quick way of
+ inlining shader source strings is functional. Qt Quick backends for other
+ APIs may however limit support to pre-compiled bytecode like SPIR-V or D3D
+ shader bytecode. There the string is simply a filename, which may be a file
+ in the filesystem or bundled with the executable via Qt's resource system.
+
+ With GLSL the default shader expects the texture coordinate to be passed
+ from the vertex shader as \c{varying highp vec2 qt_TexCoord0}, and it
+ samples from a sampler2D named \c source. With HLSL the texture is named
+ \c source, while the vertex shader is expected to provide
+ \c{float2 coord : TEXCOORD0} in its output in addition to
+ \c{float4 position : SV_POSITION} (names can differ since linking is done
+ based on the semantics).
+
+ \sa vertexShader, GraphicsInfo
*/
+QByteArray QQuickShaderEffect::fragmentShader() const
+{
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->fragmentShader();
+#endif
+ return m_impl->fragmentShader();
+}
+
void QQuickShaderEffect::setFragmentShader(const QByteArray &code)
{
- if (m_common.source.sourceCode[Key::FragmentShader].constData() == code.constData())
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->setFragmentShader(code);
return;
- m_common.source.sourceCode[Key::FragmentShader] = code;
- m_dirtyProgram = true;
- m_dirtyParseLog = true;
-
- if (isComponentComplete())
- m_common.updateShader(this, Key::FragmentShader);
-
- update();
- if (m_status != Uncompiled) {
- m_status = Uncompiled;
- emit statusChanged();
}
- emit fragmentShaderChanged();
+#endif
+ m_impl->setFragmentShader(code);
}
/*!
\qmlproperty string QtQuick::ShaderEffect::vertexShader
- This property holds the vertex shader's GLSL source code.
- The default shader passes the texture coordinate along to the fragment
- shader as "varying highp vec2 qt_TexCoord0".
+ This property holds the vertex shader's source code or a reference to the
+ pre-compiled bytecode. Some APIs, like OpenGL, always support runtime
+ compilation and therefore the traditional Qt Quick way of inlining shader
+ source strings is functional. Qt Quick backends for other APIs may however
+ limit support to pre-compiled bytecode like SPIR-V or D3D shader bytecode.
+ There the string is simply a filename, which may be a file in the
+ filesystem or bundled with the executable via Qt's resource system.
+
+ With GLSL the default shader passes the texture coordinate along to the
+ fragment shader as \c{varying highp vec2 qt_TexCoord0}. With HLSL it is
+ enough to use the standard \c TEXCOORD0 semantic, for example
+ \c{float2 coord : TEXCOORD0}.
+
+ \sa fragmentShader, GraphicsInfo
*/
+QByteArray QQuickShaderEffect::vertexShader() const
+{
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->vertexShader();
+#endif
+ return m_impl->vertexShader();
+}
+
void QQuickShaderEffect::setVertexShader(const QByteArray &code)
{
- if (m_common.source.sourceCode[Key::VertexShader].constData() == code.constData())
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->setVertexShader(code);
return;
- m_common.source.sourceCode[Key::VertexShader] = code;
- m_dirtyProgram = true;
- m_dirtyParseLog = true;
- m_customVertexShader = true;
-
- if (isComponentComplete())
- m_common.updateShader(this, Key::VertexShader);
-
- update();
- if (m_status != Uncompiled) {
- m_status = Uncompiled;
- emit statusChanged();
}
- emit vertexShaderChanged();
+#endif
+ m_impl->setVertexShader(code);
}
/*!
@@ -777,15 +470,24 @@ void QQuickShaderEffect::setVertexShader(const QByteArray &code)
property to false when blending is not needed. The default value is true.
*/
+bool QQuickShaderEffect::blending() const
+{
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->blending();
+#endif
+ return m_impl->blending();
+}
+
void QQuickShaderEffect::setBlending(bool enable)
{
- if (blending() == enable)
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->setBlending(enable);
return;
-
- m_blending = enable;
- update();
-
- emit blendingChanged();
+ }
+#endif
+ m_impl->setBlending(enable);
}
/*!
@@ -803,44 +505,22 @@ void QQuickShaderEffect::setBlending(bool enable)
QVariant QQuickShaderEffect::mesh() const
{
- return m_mesh ? qVariantFromValue(static_cast<QObject *>(m_mesh))
- : qVariantFromValue(m_meshResolution);
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->mesh();
+#endif
+ return m_impl->mesh();
}
void QQuickShaderEffect::setMesh(const QVariant &mesh)
{
- QQuickShaderEffectMesh *newMesh = qobject_cast<QQuickShaderEffectMesh *>(qvariant_cast<QObject *>(mesh));
- if (newMesh && newMesh == m_mesh)
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->setMesh(mesh);
return;
- if (m_mesh)
- disconnect(m_mesh, SIGNAL(geometryChanged()), this, 0);
- m_mesh = newMesh;
- if (m_mesh) {
- connect(m_mesh, SIGNAL(geometryChanged()), this, SLOT(updateGeometry()));
- } else {
- if (mesh.canConvert<QSize>()) {
- m_meshResolution = mesh.toSize();
- } else {
- QList<QByteArray> res = mesh.toByteArray().split('x');
- bool ok = res.size() == 2;
- if (ok) {
- int w = res.at(0).toInt(&ok);
- if (ok) {
- int h = res.at(1).toInt(&ok);
- if (ok)
- m_meshResolution = QSize(w, h);
- }
- }
- if (!ok)
- qWarning("ShaderEffect: mesh property must be size or object deriving from QQuickShaderEffectMesh.");
- }
- m_defaultMesh.setResolution(m_meshResolution);
}
-
- m_dirtyMesh = true;
- m_dirtyParseLog = true;
- update();
- emit meshChanged();
+#endif
+ m_impl->setMesh(mesh);
}
/*!
@@ -857,13 +537,24 @@ void QQuickShaderEffect::setMesh(const QVariant &mesh)
The default is NoCulling.
*/
+QQuickShaderEffect::CullMode QQuickShaderEffect::cullMode() const
+{
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->cullMode();
+#endif
+ return m_impl->cullMode();
+}
+
void QQuickShaderEffect::setCullMode(CullMode face)
{
- if (face == m_cullMode)
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->setCullMode(face);
return;
- m_cullMode = face;
- update();
- emit cullModeChanged();
+ }
+#endif
+ return m_impl->setCullMode(face);
}
/*!
@@ -887,41 +578,24 @@ void QQuickShaderEffect::setCullMode(CullMode face)
\since QtQuick 2.4
*/
-void QQuickShaderEffect::setSupportsAtlasTextures(bool supports)
+bool QQuickShaderEffect::supportsAtlasTextures() const
{
- if (supports == m_supportsAtlasTextures)
- return;
- m_supportsAtlasTextures = supports;
- updateGeometry();
- emit supportsAtlasTexturesChanged();
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->supportsAtlasTextures();
+#endif
+ return m_impl->supportsAtlasTextures();
}
-QString QQuickShaderEffect::parseLog()
-{
- if (m_dirtyParseLog) {
- m_common.updateParseLog(m_mesh != 0);
- m_dirtyParseLog = false;
- }
- return m_common.parseLog;
-}
-
-bool QQuickShaderEffect::event(QEvent *event)
+void QQuickShaderEffect::setSupportsAtlasTextures(bool supports)
{
- if (event->type() == QEvent::DynamicPropertyChange) {
- QDynamicPropertyChangeEvent *e = static_cast<QDynamicPropertyChangeEvent *>(event);
- for (int shaderType = 0; shaderType < Key::ShaderTypeCount; ++shaderType) {
- for (int i = 0; i < m_common.uniformData[shaderType].size(); ++i) {
- if (m_common.uniformData[shaderType].at(i).name == e->propertyName()) {
- bool textureProviderChanged;
- m_common.propertyChanged(this, (shaderType << 16) | i, &textureProviderChanged);
- m_dirtyTextureProviders |= textureProviderChanged;
- m_dirtyUniformValues = true;
- update();
- }
- }
- }
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->setSupportsAtlasTextures(supports);
+ return;
}
- return QQuickItem::event(event);
+#endif
+ m_impl->setSupportsAtlasTextures(supports);
}
/*!
@@ -935,9 +609,17 @@ bool QQuickShaderEffect::event(QEvent *event)
\li ShaderEffect.Error - the shader program failed to compile or link.
\endlist
- When setting the fragment or vertex shader source code, the status will become Uncompiled.
- The first time the ShaderEffect is rendered with new shader source code, the shaders are
- compiled and linked, and the status is updated to Compiled or Error.
+ When setting the fragment or vertex shader source code, the status will
+ become Uncompiled. The first time the ShaderEffect is rendered with new
+ shader source code, the shaders are compiled and linked, and the status is
+ updated to Compiled or Error.
+
+ When runtime compilation is not in use and the shader properties refer to
+ files with bytecode, the status is always Compiled. The contents of the
+ shader is not examined (apart from basic reflection to discover vertex
+ input elements and constant buffer data) until later in the rendering
+ pipeline so potential errors (like layout or root signature mismatches)
+ will only be detected at a later point.
\sa log
*/
@@ -945,185 +627,103 @@ bool QQuickShaderEffect::event(QEvent *event)
/*!
\qmlproperty string QtQuick::ShaderEffect::log
- This property holds a log of warnings and errors from the latest attempt at compiling and
- linking the OpenGL shader program. It is updated at the same time \l status is set to Compiled
- or Error.
+ This property holds a log of warnings and errors from the latest attempt at
+ compiling and linking the OpenGL shader program. It is updated at the same
+ time \l status is set to Compiled or Error.
\sa status
*/
-void QQuickShaderEffect::updateGeometry()
+QString QQuickShaderEffect::log() const
{
- m_dirtyGeometry = true;
- update();
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->log();
+#endif
+ return m_impl->log();
}
-void QQuickShaderEffect::updateGeometryIfAtlased()
+QQuickShaderEffect::Status QQuickShaderEffect::status() const
{
- if (m_supportsAtlasTextures)
- updateGeometry();
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->status();
+#endif
+ return m_impl->status();
}
-void QQuickShaderEffect::updateLogAndStatus(const QString &log, int status)
+bool QQuickShaderEffect::event(QEvent *e)
{
- m_log = parseLog() + log;
- m_status = Status(status);
- emit logChanged();
- emit statusChanged();
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->handleEvent(e);
+ return QQuickItem::event(e);
+ }
+#endif
+ m_impl->handleEvent(e);
+ return QQuickItem::event(e);
}
-void QQuickShaderEffect::sourceDestroyed(QObject *object)
+void QQuickShaderEffect::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
- m_common.sourceDestroyed(object);
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->handleGeometryChanged(newGeometry, oldGeometry);
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
+ return;
+ }
+#endif
+ m_impl->handleGeometryChanged(newGeometry, oldGeometry);
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
}
-
-void QQuickShaderEffect::propertyChanged(int mappedId)
+QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
{
- bool textureProviderChanged;
- m_common.propertyChanged(this, mappedId, &textureProviderChanged);
- m_dirtyTextureProviders |= textureProviderChanged;
- m_dirtyUniformValues = true;
- update();
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->handleUpdatePaintNode(oldNode, updatePaintNodeData);
+#endif
+ return m_impl->handleUpdatePaintNode(oldNode, updatePaintNodeData);
}
-void QQuickShaderEffect::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickShaderEffect::componentComplete()
{
- m_dirtyGeometry = true;
- QQuickItem::geometryChanged(newGeometry, oldGeometry);
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->handleComponentComplete();
+ QQuickItem::componentComplete();
+ return;
+ }
+#endif
+ m_impl->handleComponentComplete();
+ QQuickItem::componentComplete();
}
-QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+void QQuickShaderEffect::itemChange(ItemChange change, const ItemChangeData &value)
{
- QQuickShaderEffectNode *node = static_cast<QQuickShaderEffectNode *>(oldNode);
-
- // In the case of zero-size or a bad vertex shader, don't try to create a node...
- if (m_common.attributes.isEmpty() || width() <= 0 || height() <= 0) {
- if (node)
- delete node;
- return 0;
- }
-
- if (!node) {
- node = new QQuickShaderEffectNode;
- node->setMaterial(new QQuickShaderEffectMaterial(node));
- node->setFlag(QSGNode::OwnsMaterial, true);
- m_dirtyProgram = true;
- m_dirtyUniforms = true;
- m_dirtyGeometry = true;
- connect(node, SIGNAL(logAndStatusChanged(QString,int)), this, SLOT(updateLogAndStatus(QString,int)));
- connect(node, &QQuickShaderEffectNode::dirtyTexture,
- this, &QQuickShaderEffect::updateGeometryIfAtlased);
- }
-
- QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(node->material());
-
- // Update blending
- if (bool(material->flags() & QSGMaterial::Blending) != m_blending) {
- material->setFlag(QSGMaterial::Blending, m_blending);
- node->markDirty(QSGNode::DirtyMaterial);
- }
-
- if (int(material->cullMode) != int(m_cullMode)) {
- material->cullMode = QQuickShaderEffectMaterial::CullMode(m_cullMode);
- node->markDirty(QSGNode::DirtyMaterial);
- }
-
- if (m_dirtyProgram) {
- Key s = m_common.source;
- QSGShaderSourceBuilder builder;
- if (s.sourceCode[Key::FragmentShader].isEmpty()) {
- builder.appendSourceFile(QStringLiteral(":/qt-project.org/items/shaders/shadereffect.frag"));
- s.sourceCode[Key::FragmentShader] = builder.source();
- builder.clear();
- }
- if (s.sourceCode[Key::VertexShader].isEmpty()) {
- builder.appendSourceFile(QStringLiteral(":/qt-project.org/items/shaders/shadereffect.vert"));
- s.sourceCode[Key::VertexShader] = builder.source();
- }
-
- material->setProgramSource(s);
- material->attributes = m_common.attributes;
- node->markDirty(QSGNode::DirtyMaterial);
- m_dirtyProgram = false;
- m_dirtyUniforms = true;
- }
-
- if (m_dirtyUniforms || m_dirtyUniformValues || m_dirtyTextureProviders) {
- m_common.updateMaterial(node, material, m_dirtyUniforms, m_dirtyUniformValues,
- m_dirtyTextureProviders);
- node->markDirty(QSGNode::DirtyMaterial);
- m_dirtyUniforms = m_dirtyUniformValues = m_dirtyTextureProviders = false;
- }
-
- QRectF srcRect(0, 0, 1, 1);
- bool geometryUsesTextureSubRect = false;
- if (m_supportsAtlasTextures && material->textureProviders.size() == 1) {
- QSGTextureProvider *provider = material->textureProviders.at(0);
- if (provider->texture()) {
- srcRect = provider->texture()->normalizedTextureSubRect();
- geometryUsesTextureSubRect = true;
- }
- }
-
- if (bool(material->flags() & QSGMaterial::RequiresFullMatrix) != m_customVertexShader) {
- material->setFlag(QSGMaterial::RequiresFullMatrix, m_customVertexShader);
- node->markDirty(QSGNode::DirtyMaterial);
- }
-
- if (material->geometryUsesTextureSubRect != geometryUsesTextureSubRect) {
- material->geometryUsesTextureSubRect = geometryUsesTextureSubRect;
- node->markDirty(QSGNode::DirtyMaterial);
- }
-
- if (m_dirtyMesh) {
- node->setGeometry(0);
- m_dirtyMesh = false;
- m_dirtyGeometry = true;
- }
-
- if (m_dirtyGeometry) {
- node->setFlag(QSGNode::OwnsGeometry, false);
- QSGGeometry *geometry = node->geometry();
- QRectF rect(0, 0, width(), height());
- QQuickShaderEffectMesh *mesh = m_mesh ? m_mesh : &m_defaultMesh;
-
- geometry = mesh->updateGeometry(geometry, m_common.attributes, srcRect, rect);
- if (!geometry) {
- QString log = mesh->log();
- if (!log.isNull()) {
- m_log = parseLog();
- m_log += QLatin1String("*** Mesh ***\n");
- m_log += log;
- m_status = Error;
- emit logChanged();
- emit statusChanged();
- }
- delete node;
- return 0;
- }
-
- node->setGeometry(geometry);
- node->setFlag(QSGNode::OwnsGeometry, true);
-
- m_dirtyGeometry = false;
+#ifndef QT_NO_OPENGL
+ if (m_glImpl) {
+ m_glImpl->handleItemChange(change, value);
+ QQuickItem::itemChange(change, value);
+ return;
}
-
- return node;
+#endif
+ m_impl->handleItemChange(change, value);
+ QQuickItem::itemChange(change, value);
}
-void QQuickShaderEffect::componentComplete()
+bool QQuickShaderEffect::isComponentComplete() const
{
- m_common.updateShader(this, Key::VertexShader);
- m_common.updateShader(this, Key::FragmentShader);
- QQuickItem::componentComplete();
+ return QQuickItem::isComponentComplete();
}
-void QQuickShaderEffect::itemChange(ItemChange change, const ItemChangeData &value)
+QString QQuickShaderEffect::parseLog() // for OpenGL-based autotests
{
- if (change == QQuickItem::ItemSceneChange)
- m_common.updateWindow(value.window);
- QQuickItem::itemChange(change, value);
+#ifndef QT_NO_OPENGL
+ if (m_glImpl)
+ return m_glImpl->parseLog();
+#endif
+ return QString();
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index fb266d4c44..62d7e6fe5f 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -52,51 +52,12 @@
//
#include <QtQuick/qquickitem.h>
-
-#include <QtQuick/qsgmaterial.h>
#include <private/qtquickglobal_p.h>
-#include <private/qsgadaptationlayer_p.h>
-#include <private/qquickshadereffectnode_p.h>
-#include "qquickshadereffectmesh_p.h"
-
-#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
-const char *qtPositionAttributeName();
-const char *qtTexCoordAttributeName();
-
-class QSGContext;
-class QSignalMapper;
-class QQuickCustomMaterialShader;
-
-// Common class for QQuickShaderEffect and QQuickCustomParticle.
-struct Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectCommon
-{
- typedef QQuickShaderEffectMaterialKey Key;
- typedef QQuickShaderEffectMaterial::UniformData UniformData;
-
- ~QQuickShaderEffectCommon();
- void disconnectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
- void connectPropertySignals(QQuickItem *item, Key::ShaderType shaderType);
- void updateParseLog(bool ignoreAttributes);
- void lookThroughShaderCode(QQuickItem *item, Key::ShaderType shaderType, const QByteArray &code);
- void updateShader(QQuickItem *item, Key::ShaderType shaderType);
- void updateMaterial(QQuickShaderEffectNode *node, QQuickShaderEffectMaterial *material,
- bool updateUniforms, bool updateUniformValues, bool updateTextureProviders);
- void updateWindow(QQuickWindow *window);
-
- // Called by slots in QQuickShaderEffect:
- void sourceDestroyed(QObject *object);
- void propertyChanged(QQuickItem *item, int mappedId, bool *textureProviderChanged);
-
- Key source;
- QVector<QByteArray> attributes;
- QVector<UniformData> uniformData[Key::ShaderTypeCount];
- QVector<QSignalMapper *> signalMappers[Key::ShaderTypeCount];
- QString parseLog;
-};
-
+class QQuickOpenGLShaderEffect;
+class QQuickGenericShaderEffect;
class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
{
@@ -111,16 +72,14 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
Q_PROPERTY(bool supportsAtlasTextures READ supportsAtlasTextures WRITE setSupportsAtlasTextures NOTIFY supportsAtlasTexturesChanged REVISION 1)
public:
- enum CullMode
- {
- NoCulling = QQuickShaderEffectMaterial::NoCulling,
- BackFaceCulling = QQuickShaderEffectMaterial::BackFaceCulling,
- FrontFaceCulling = QQuickShaderEffectMaterial::FrontFaceCulling
+ enum CullMode {
+ NoCulling,
+ BackFaceCulling,
+ FrontFaceCulling
};
Q_ENUM(CullMode)
- enum Status
- {
+ enum Status {
Compiled,
Uncompiled,
Error
@@ -128,32 +87,30 @@ public:
Q_ENUM(Status)
QQuickShaderEffect(QQuickItem *parent = 0);
- ~QQuickShaderEffect();
- QByteArray fragmentShader() const { return m_common.source.sourceCode[Key::FragmentShader]; }
+ QByteArray fragmentShader() const;
void setFragmentShader(const QByteArray &code);
- QByteArray vertexShader() const { return m_common.source.sourceCode[Key::VertexShader]; }
+ QByteArray vertexShader() const;
void setVertexShader(const QByteArray &code);
- bool blending() const { return m_blending; }
+ bool blending() const;
void setBlending(bool enable);
QVariant mesh() const;
void setMesh(const QVariant &mesh);
- CullMode cullMode() const { return m_cullMode; }
+ CullMode cullMode() const;
void setCullMode(CullMode face);
- QString log() const { return m_log; }
- Status status() const { return m_status; }
-
- bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
+ bool supportsAtlasTextures() const;
void setSupportsAtlasTextures(bool supports);
- QString parseLog();
+ QString log() const;
+ Status status() const;
- bool event(QEvent *) Q_DECL_OVERRIDE;
+ bool isComponentComplete() const;
+ QString parseLog();
Q_SIGNALS:
void fragmentShaderChanged();
@@ -166,44 +123,17 @@ Q_SIGNALS:
void supportsAtlasTexturesChanged();
protected:
- void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
- QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE;
- void componentComplete() Q_DECL_OVERRIDE;
- void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
-
-private Q_SLOTS:
- void updateGeometry();
- void updateGeometryIfAtlased();
- void updateLogAndStatus(const QString &log, int status);
- void sourceDestroyed(QObject *object);
- void propertyChanged(int mappedId);
+ bool event(QEvent *e) override;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override;
+ void componentComplete() override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
private:
- friend class QQuickCustomMaterialShader;
- friend class QQuickShaderEffectNode;
-
- typedef QQuickShaderEffectMaterialKey Key;
- typedef QQuickShaderEffectMaterial::UniformData UniformData;
-
- QSize m_meshResolution;
- QQuickShaderEffectMesh *m_mesh;
- QQuickGridMesh m_defaultMesh;
- CullMode m_cullMode;
- QString m_log;
- Status m_status;
-
- QQuickShaderEffectCommon m_common;
-
- uint m_blending : 1;
- uint m_dirtyUniforms : 1;
- uint m_dirtyUniformValues : 1;
- uint m_dirtyTextureProviders : 1;
- uint m_dirtyProgram : 1;
- uint m_dirtyParseLog : 1;
- uint m_dirtyMesh : 1;
- uint m_dirtyGeometry : 1;
- uint m_customVertexShader : 1;
- uint m_supportsAtlasTextures : 1;
+#ifndef QT_NO_OPENGL
+ QQuickOpenGLShaderEffect *m_glImpl;
+#endif
+ QQuickGenericShaderEffect *m_impl;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffectmesh.cpp b/src/quick/items/qquickshadereffectmesh.cpp
index 0811025654..f5cc19c877 100644
--- a/src/quick/items/qquickshadereffectmesh.cpp
+++ b/src/quick/items/qquickshadereffectmesh.cpp
@@ -40,9 +40,25 @@
#include "qquickshadereffectmesh_p.h"
#include <QtQuick/qsggeometry.h>
#include "qquickshadereffect_p.h"
+#include "qquickscalegrid_p_p.h"
+#include "qquickborderimage_p_p.h"
+#include <QtQuick/private/qsgbasicimagenode_p.h>
QT_BEGIN_NAMESPACE
+static const char qt_position_attribute_name[] = "qt_Vertex";
+static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0";
+
+const char *qtPositionAttributeName()
+{
+ return qt_position_attribute_name;
+}
+
+const char *qtTexCoordAttributeName()
+{
+ return qt_texcoord_attribute_name;
+}
+
QQuickShaderEffectMesh::QQuickShaderEffectMesh(QObject *parent)
: QObject(parent)
{
@@ -67,54 +83,64 @@ QQuickGridMesh::QQuickGridMesh(QObject *parent)
{
}
-QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &dstRect)
+bool QQuickGridMesh::validateAttributes(const QVector<QByteArray> &attributes, int *posIndex)
{
- int vmesh = m_resolution.height();
- int hmesh = m_resolution.width();
- int attrCount = attributes.count();
-
+ const int attrCount = attributes.count();
int positionIndex = attributes.indexOf(qtPositionAttributeName());
int texCoordIndex = attributes.indexOf(qtTexCoordAttributeName());
- if (!geometry) {
- switch (attrCount) {
- case 0:
- m_log = QLatin1String("Error: No attributes specified.");
- return 0;
- case 1:
- if (positionIndex != 0) {
+ switch (attrCount) {
+ case 0:
+ m_log = QLatin1String("Error: No attributes specified.");
+ return false;
+ case 1:
+ if (positionIndex != 0) {
+ m_log = QLatin1String("Error: Missing \'");
+ m_log += QLatin1String(qtPositionAttributeName());
+ m_log += QLatin1String("\' attribute.\n");
+ return false;
+ }
+ break;
+ case 2:
+ if (positionIndex == -1 || texCoordIndex == -1) {
+ m_log.clear();
+ if (positionIndex == -1) {
m_log = QLatin1String("Error: Missing \'");
m_log += QLatin1String(qtPositionAttributeName());
m_log += QLatin1String("\' attribute.\n");
- return 0;
}
- break;
- case 2:
- if (positionIndex == -1 || texCoordIndex == -1) {
- m_log.clear();
- if (positionIndex == -1) {
- m_log = QLatin1String("Error: Missing \'");
- m_log += QLatin1String(qtPositionAttributeName());
- m_log += QLatin1String("\' attribute.\n");
- }
- if (texCoordIndex == -1) {
- m_log += QLatin1String("Error: Missing \'");
- m_log += QLatin1String(qtTexCoordAttributeName());
- m_log += QLatin1String("\' attribute.\n");
- }
- return 0;
+ if (texCoordIndex == -1) {
+ m_log += QLatin1String("Error: Missing \'");
+ m_log += QLatin1String(qtTexCoordAttributeName());
+ m_log += QLatin1String("\' attribute.\n");
}
- break;
- default:
- m_log = QLatin1String("Error: Too many attributes specified.");
- return 0;
+ return false;
}
+ break;
+ default:
+ m_log = QLatin1String("Error: Too many attributes specified.");
+ return false;
+ }
+
+ if (posIndex)
+ *posIndex = positionIndex;
+
+ return true;
+}
+QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
+ const QRectF &srcRect, const QRectF &dstRect)
+{
+ int vmesh = m_resolution.height();
+ int hmesh = m_resolution.width();
+
+ if (!geometry) {
+ Q_ASSERT(attrCount == 1 || attrCount == 2);
geometry = new QSGGeometry(attrCount == 1
? QSGGeometry::defaultAttributes_Point2D()
: QSGGeometry::defaultAttributes_TexturedPoint2D(),
(vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2),
- GL_UNSIGNED_SHORT);
+ QSGGeometry::TypeUnsignedShort);
} else {
geometry->allocate((vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2));
@@ -129,7 +155,7 @@ QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector
for (int ix = 0; ix <= hmesh; ++ix) {
float fx = ix / float(hmesh);
for (int ia = 0; ia < attrCount; ++ia) {
- if (ia == positionIndex) {
+ if (ia == posIndex) {
vdata->x = float(dstRect.left()) + fx * float(dstRect.width());
vdata->y = y;
++vdata;
@@ -217,4 +243,197 @@ QSize QQuickGridMesh::resolution() const
return m_resolution;
}
+/*!
+ \qmltype BorderImageMesh
+ \instantiates QQuickBorderImageMesh
+ \inqmlmodule QtQuick
+ \since 5.8
+ \ingroup qtquick-effects
+ \brief Defines a mesh with vertices arranged like those of a BorderImage.
+
+ BorderImageMesh provides BorderImage-like capabilities to a ShaderEffect
+ without the need for a potentially costly ShaderEffectSource.
+
+ The following are functionally equivalent:
+ \qml
+ BorderImage {
+ id: borderImage
+ border {
+ left: 10
+ right: 10
+ top: 10
+ bottom: 10
+ }
+ source: "myImage.png"
+ visible: false
+ }
+ ShaderEffectSource {
+ id: effectSource
+ sourceItem: borderImage
+ visible: false
+ }
+ ShaderEffect {
+ property var source: effectSource
+ ...
+ }
+ \endqml
+
+ \qml
+ Image {
+ id: image
+ source: "myImage.png"
+ visible: false
+ }
+ ShaderEffect {
+ property var source: image
+ mesh: BorderImageMesh {
+ border {
+ left: 10
+ right: 10
+ top: 10
+ bottom: 10
+ }
+ size: image.sourceSize
+ }
+ ...
+ }
+ \endqml
+
+ But the BorderImageMesh version can typically be better optimized.
+*/
+QQuickBorderImageMesh::QQuickBorderImageMesh(QObject *parent)
+ : QQuickShaderEffectMesh(parent), m_border(new QQuickScaleGrid(this)),
+ m_horizontalTileMode(QQuickBorderImageMesh::Stretch),
+ m_verticalTileMode(QQuickBorderImageMesh::Stretch)
+{
+}
+
+bool QQuickBorderImageMesh::validateAttributes(const QVector<QByteArray> &attributes, int *posIndex)
+{
+ Q_UNUSED(attributes);
+ Q_UNUSED(posIndex);
+ return true;
+}
+
+QSGGeometry *QQuickBorderImageMesh::updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
+ const QRectF &srcRect, const QRectF &rect)
+{
+ Q_UNUSED(attrCount);
+ Q_UNUSED(posIndex);
+
+ QRectF innerSourceRect;
+ QRectF targetRect;
+ QRectF innerTargetRect;
+ QRectF subSourceRect;
+
+ QQuickBorderImagePrivate::calculateRects(m_border, m_size, rect.size(), m_horizontalTileMode, m_verticalTileMode,
+ 1, &targetRect, &innerTargetRect, &innerSourceRect, &subSourceRect);
+
+ QRectF sourceRect = srcRect;
+ QRectF modifiedInnerSourceRect(sourceRect.x() + innerSourceRect.x() * sourceRect.width(),
+ sourceRect.y() + innerSourceRect.y() * sourceRect.height(),
+ innerSourceRect.width() * sourceRect.width(),
+ innerSourceRect.height() * sourceRect.height());
+
+ geometry = QSGBasicImageNode::updateGeometry(targetRect, innerTargetRect, sourceRect,
+ modifiedInnerSourceRect, subSourceRect, geometry);
+
+ return geometry;
+}
+
+/*!
+ \qmlpropertygroup QtQuick::BorderImageMesh::border
+ \qmlproperty int QtQuick::BorderImageMesh::border.left
+ \qmlproperty int QtQuick::BorderImageMesh::border.right
+ \qmlproperty int QtQuick::BorderImageMesh::border.top
+ \qmlproperty int QtQuick::BorderImageMesh::border.bottom
+
+ The 4 border lines (2 horizontal and 2 vertical) break the image into 9 sections,
+ as shown below:
+
+ \image declarative-scalegrid.png
+
+ Each border line (left, right, top, and bottom) specifies an offset in pixels
+ from the respective edge of the mesh. By default, each border line has
+ a value of 0.
+
+ For example, the following definition sets the bottom line 10 pixels up from
+ the bottom of the mesh:
+
+ \qml
+ BorderImageMesh {
+ border.bottom: 10
+ // ...
+ }
+ \endqml
+*/
+QQuickScaleGrid *QQuickBorderImageMesh::border()
+{
+ return m_border;
+}
+
+/*!
+ \qmlproperty size QtQuick::BorderImageMesh::size
+
+ The base size of the mesh. This generally corresponds to the \l {Image::}{sourceSize}
+ of the image being used by the ShaderEffect.
+*/
+QSize QQuickBorderImageMesh::size() const
+{
+ return m_size;
+}
+
+void QQuickBorderImageMesh::setSize(const QSize &size)
+{
+ if (size == m_size)
+ return;
+ m_size = size;
+ Q_EMIT sizeChanged();
+ Q_EMIT geometryChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::BorderImageMesh::horizontalTileMode
+ \qmlproperty enumeration QtQuick::BorderImageMesh::verticalTileMode
+
+ This property describes how to repeat or stretch the middle parts of an image.
+
+ \list
+ \li BorderImage.Stretch - Scales the image to fit to the available area.
+ \li BorderImage.Repeat - Tile the image until there is no more space. May crop the last image.
+ \li BorderImage.Round - Like Repeat, but scales the images down to ensure that the last image is not cropped.
+ \endlist
+
+ The default tile mode for each property is BorderImage.Stretch.
+*/
+
+QQuickBorderImageMesh::TileMode QQuickBorderImageMesh::horizontalTileMode() const
+{
+ return m_horizontalTileMode;
+}
+
+void QQuickBorderImageMesh::setHorizontalTileMode(TileMode t)
+{
+ if (t == m_horizontalTileMode)
+ return;
+ m_horizontalTileMode = t;
+ Q_EMIT horizontalTileModeChanged();
+ Q_EMIT geometryChanged();
+}
+
+QQuickBorderImageMesh::TileMode QQuickBorderImageMesh::verticalTileMode() const
+{
+ return m_verticalTileMode;
+}
+
+void QQuickBorderImageMesh::setVerticalTileMode(TileMode t)
+{
+ if (t == m_verticalTileMode)
+ return;
+
+ m_verticalTileMode = t;
+ Q_EMIT verticalTileModeChanged();
+ Q_EMIT geometryChanged();
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h
index 7f9c95888c..c5f1d19866 100644
--- a/src/quick/items/qquickshadereffectmesh_p.h
+++ b/src/quick/items/qquickshadereffectmesh_p.h
@@ -43,8 +43,8 @@
#include <QtGui/qcolor.h>
#include <QtCore/qobject.h>
#include <QtCore/qsize.h>
-#include <QtCore/qvariant.h>
-#include <QtGui/qopenglfunctions.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qbytearray.h>
#ifndef QQUICKSHADEREFFECTMESH_P_H
#define QQUICKSHADEREFFECTMESH_P_H
@@ -62,6 +62,9 @@
QT_BEGIN_NAMESPACE
+const char *qtPositionAttributeName();
+const char *qtTexCoordAttributeName();
+
class QSGGeometry;
class QRectF;
@@ -70,8 +73,10 @@ class QQuickShaderEffectMesh : public QObject
Q_OBJECT
public:
QQuickShaderEffectMesh(QObject *parent = 0);
- // If 'geometry' != 0, 'attributes' is the same as last time the function was called.
- virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &rect) = 0;
+ virtual bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) = 0;
+ // If 'geometry' != 0, 'attrCount' is the same as last time the function was called.
+ virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
+ const QRectF &srcRect, const QRectF &rect) = 0;
// If updateGeometry() fails, the reason should appear in the log.
virtual QString log() const { return QString(); }
@@ -86,7 +91,9 @@ class QQuickGridMesh : public QQuickShaderEffectMesh
Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged)
public:
QQuickGridMesh(QObject *parent = 0);
- QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &rect) Q_DECL_OVERRIDE;
+ bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) Q_DECL_OVERRIDE;
+ QSGGeometry *updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
+ const QRectF &srcRect, const QRectF &rect) Q_DECL_OVERRIDE;
QString log() const Q_DECL_OVERRIDE { return m_log; }
void setResolution(const QSize &res);
@@ -100,6 +107,48 @@ private:
QString m_log;
};
+class QQuickScaleGrid;
+class QQuickBorderImageMesh : public QQuickShaderEffectMesh
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QQuickScaleGrid *border READ border CONSTANT)
+ Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged)
+ Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode NOTIFY horizontalTileModeChanged)
+ Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode NOTIFY verticalTileModeChanged)
+public:
+ QQuickBorderImageMesh(QObject *parent = 0);
+
+ bool validateAttributes(const QVector<QByteArray> &attributes, int *posIndex) override;
+ QSGGeometry *updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
+ const QRectF &srcRect, const QRectF &rect) override;
+
+ QQuickScaleGrid *border();
+
+ enum TileMode { Stretch = Qt::StretchTile, Repeat = Qt::RepeatTile, Round = Qt::RoundTile };
+ Q_ENUM(TileMode)
+
+ QSize size() const;
+ void setSize(const QSize &size);
+
+ TileMode horizontalTileMode() const;
+ void setHorizontalTileMode(TileMode);
+
+ TileMode verticalTileMode() const;
+ void setVerticalTileMode(TileMode);
+
+Q_SIGNALS:
+ void sizeChanged();
+ void horizontalTileModeChanged();
+ void verticalTileModeChanged();
+
+private:
+ QQuickScaleGrid *m_border;
+ QSize m_size;
+ TileMode m_horizontalTileMode;
+ TileMode m_verticalTileMode;
+};
+
inline QColor qt_premultiply_color(const QColor &c)
{
return QColor::fromRgbF(c.redF() * c.alphaF(), c.greenF() * c.alphaF(), c.blueF() * c.alphaF(), c.alphaF());
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index a8cf6155a0..338e4dc3a7 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -45,7 +45,6 @@
#include <QtQuick/private/qsgrenderer_p.h>
#include <qsgsimplerectnode.h>
-#include "qopenglframebufferobject.h"
#include "qmath.h"
#include <QtQuick/private/qsgtexture_p.h>
#include <QtCore/QRunnable>
@@ -680,7 +679,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
m_texture->setDevicePixelRatio(d->window->effectiveDevicePixelRatio());
m_texture->setSize(textureSize);
m_texture->setRecursive(m_recursive);
- m_texture->setFormat(GLenum(m_format));
+ m_texture->setFormat(m_format);
m_texture->setHasMipmaps(m_mipmap);
m_texture->setMirrorHorizontal(m_textureMirroring & MirrorHorizontally);
m_texture->setMirrorVertical(m_textureMirroring & MirrorVertically);
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 92b04f4ca7..680ba85aa1 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -93,11 +93,11 @@ public:
Repeat
};
Q_ENUM(WrapMode)
-
+ // Equivalents to GL_ALPHA and similar type constants.
enum Format {
- Alpha = GL_ALPHA,
- RGB = GL_RGB,
- RGBA = GL_RGBA
+ Alpha = 0x1906,
+ RGB = 0x1907,
+ RGBA = 0x1908
};
Q_ENUM(Format)
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index 60d5e3f6dd..c82966cf6b 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -111,7 +111,7 @@ QQuickSpriteEngine::QQuickSpriteEngine(QObject *parent)
}
QQuickSpriteEngine::QQuickSpriteEngine(QList<QQuickSprite*> sprites, QObject *parent)
- : QQuickStochasticEngine(parent), m_startedImageAssembly(false), m_loaded(false)
+ : QQuickSpriteEngine(parent)
{
foreach (QQuickSprite* sprite, sprites)
m_states << (QQuickStochasticState*)sprite;
@@ -390,12 +390,15 @@ QImage QQuickSpriteEngine::assembledImage()
m_maxFrames = 0;
m_imageStateCount = 0;
int maxSize = 0;
-
+#ifndef QT_NO_OPENGL
//If there is no current OpenGL Context
if (!QOpenGLContext::currentContext())
return QImage();
QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
+#else
+ maxSize = 2048;
+#endif
#ifdef SPRITE_IMAGE_DEBUG
qDebug() << "MAX TEXTURE SIZE" << maxSize;
#endif
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 59331647e5..4dc59b100a 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -69,6 +69,7 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
@@ -1431,6 +1432,39 @@ QQuickText::~QQuickText()
Text { text: "Hello"; font.capitalization: Font.AllLowercase }
\endqml
*/
+
+/*!
+ \qmlproperty enumeration QtQuick::Text::font.hintingPreference
+ \since 5.8
+
+ Sets the preferred hinting on the text. This is a hint to the underlying text rendering system
+ to use a certain level of hinting, and has varying support across platforms. See the table in
+ the documentation for QFont::HintingPreference for more details.
+
+ \note This property only has an effect when used together with render type Text.NativeRendering.
+
+ \list
+ \value Font.PreferDefaultHinting - Use the default hinting level for the target platform.
+ \value Font.PreferNoHinting - If possible, render text without hinting the outlines
+ of the glyphs. The text layout will be typographically accurate, using the same metrics
+ as are used e.g. when printing.
+ \value Font.PreferVerticalHinting - If possible, render text with no horizontal hinting,
+ but align glyphs to the pixel grid in the vertical direction. The text will appear
+ crisper on displays where the density is too low to give an accurate rendering
+ of the glyphs. But since the horizontal metrics of the glyphs are unhinted, the text's
+ layout will be scalable to higher density devices (such as printers) without impacting
+ details such as line breaks.
+ \value Font.PreferFullHinting - If possible, render text with hinting in both horizontal and
+ vertical directions. The text will be altered to optimize legibility on the target
+ device, but since the metrics will depend on the target size of the text, the positions
+ of glyphs, line breaks, and other typographical detail will not scale, meaning that a
+ text layout may look different on devices with different pixel densities.
+ \endlist
+
+ \qml
+ Text { text: "Hello"; renderType: Text.NativeRendering; font.hintingPreference: Font.PreferVerticalHinting }
+ \endqml
+*/
QFont QQuickText::font() const
{
Q_D(const QQuickText);
@@ -2690,6 +2724,7 @@ QString QQuickText::hoveredLink() const
void QQuickTextPrivate::processHoverEvent(QHoverEvent *event)
{
Q_Q(QQuickText);
+ qCDebug(DBG_HOVER_TRACE) << q;
QString link;
if (isLinkHoveredConnected()) {
if (event->type() != QEvent::HoverLeave)
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 0cee9c7d27..ef7485a8e9 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -44,6 +44,7 @@
#include <qcoreapplication.h>
#include <qfont.h>
+#include <qfontmetrics.h>
#include <qevent.h>
#include <qdebug.h>
#include <qdrag.h>
@@ -57,6 +58,7 @@
#include "qtextlist.h"
#include "qtextdocumentwriter.h"
#include "private/qtextcursor_p.h"
+#include <QtCore/qloggingcategory.h>
#include <qtextformat.h>
#include <qdatetime.h>
@@ -75,6 +77,7 @@
const int textCursorWidth = 1;
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
#ifndef QT_NO_CONTEXTMENU
#endif
@@ -982,6 +985,14 @@ process:
{
QString text = e->text();
if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
+ if (overwriteMode
+ // no need to call deleteChar() if we have a selection, insertText
+ // does it already
+ && !cursor.hasSelection()
+ && !cursor.atBlockEnd()) {
+ cursor.deleteChar();
+ }
+
cursor.insertText(text);
selectionChanged();
} else {
@@ -1024,6 +1035,12 @@ QRectF QQuickTextControlPrivate::rectForPosition(int position) const
if (line.isValid()) {
qreal x = line.cursorToX(relativePos);
qreal w = 0;
+ if (overwriteMode) {
+ if (relativePos < line.textLength() - line.textStart())
+ w = line.cursorToX(relativePos + 1) - x;
+ else
+ w = QFontMetrics(block.layout()->font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
+ }
r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(), textCursorWidth + w, line.height());
} else {
r = QRectF(layoutPos.x(), layoutPos.y(), textCursorWidth, 10); // #### correct height
@@ -1498,6 +1515,7 @@ void QQuickTextControlPrivate::hoverEvent(QHoverEvent *e, const QPointF &pos)
hoveredLink = link;
emit q->linkHovered(link);
}
+ qCDebug(DBG_HOVER_TRACE) << q << e->type() << pos << "hoveredLink" << hoveredLink;
}
bool QQuickTextControl::hasImState() const
@@ -1506,6 +1524,21 @@ bool QQuickTextControl::hasImState() const
return d->hasImState;
}
+bool QQuickTextControl::overwriteMode() const
+{
+ Q_D(const QQuickTextControl);
+ return d->overwriteMode;
+}
+
+void QQuickTextControl::setOverwriteMode(bool overwrite)
+{
+ Q_D(QQuickTextControl);
+ if (d->overwriteMode == overwrite)
+ return;
+ d->overwriteMode = overwrite;
+ emit overwriteModeChanged(overwrite);
+}
+
bool QQuickTextControl::cursorVisible() const
{
Q_D(const QQuickTextControl);
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index ca5a3d3191..602e457cb8 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -94,6 +94,8 @@ public:
#endif
bool hasImState() const;
+ bool overwriteMode() const;
+ void setOverwriteMode(bool overwrite);
bool cursorVisible() const;
void setCursorVisible(bool visible);
QRectF anchorRect() const;
@@ -149,6 +151,7 @@ Q_SIGNALS:
void copyAvailable(bool b);
void selectionChanged();
void cursorPositionChanged();
+ void overwriteModeChanged(bool overwriteMode);
// control signals
void updateCursorRequest();
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 5968028c26..36eb5d3cde 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -323,6 +323,39 @@ QString QQuickTextEdit::text() const
*/
/*!
+ \qmlproperty enumeration QtQuick::TextEdit::font.hintingPreference
+ \since 5.8
+
+ Sets the preferred hinting on the text. This is a hint to the underlying text rendering system
+ to use a certain level of hinting, and has varying support across platforms. See the table in
+ the documentation for QFont::HintingPreference for more details.
+
+ \note This property only has an effect when used together with render type TextEdit.NativeRendering.
+
+ \list
+ \value Font.PreferDefaultHinting - Use the default hinting level for the target platform.
+ \value Font.PreferNoHinting - If possible, render text without hinting the outlines
+ of the glyphs. The text layout will be typographically accurate, using the same metrics
+ as are used e.g. when printing.
+ \value Font.PreferVerticalHinting - If possible, render text with no horizontal hinting,
+ but align glyphs to the pixel grid in the vertical direction. The text will appear
+ crisper on displays where the density is too low to give an accurate rendering
+ of the glyphs. But since the horizontal metrics of the glyphs are unhinted, the text's
+ layout will be scalable to higher density devices (such as printers) without impacting
+ details such as line breaks.
+ \value Font.PreferFullHinting - If possible, render text with hinting in both horizontal and
+ vertical directions. The text will be altered to optimize legibility on the target
+ device, but since the metrics will depend on the target size of the text, the positions
+ of glyphs, line breaks, and other typographical detail will not scale, meaning that a
+ text layout may look different on devices with different pixel densities.
+ \endlist
+
+ \qml
+ TextEdit { text: "Hello"; renderType: TextEdit.NativeRendering; font.hintingPreference: Font.PreferVerticalHinting }
+ \endqml
+*/
+
+/*!
\qmlproperty string QtQuick::TextEdit::text
The text to display. If the text format is AutoText the text edit will
@@ -1583,6 +1616,32 @@ bool QQuickTextEdit::event(QEvent *event)
}
/*!
+ \qmlproperty bool QtQuick::TextEdit::overwriteMode
+ \since 5.8
+ Whether text entered by the user will overwrite existing text.
+
+ As with many text editors, the text editor widget can be configured
+ to insert or overwrite existing text with new text entered by the user.
+
+ If this property is \c true, existing text is overwritten, character-for-character
+ by new text; otherwise, text is inserted at the cursor position, displacing
+ existing text.
+
+ By default, this property is \c false (new text does not overwrite existing text).
+*/
+bool QQuickTextEdit::overwriteMode() const
+{
+ Q_D(const QQuickTextEdit);
+ return d->control->overwriteMode();
+}
+
+void QQuickTextEdit::setOverwriteMode(bool overwrite)
+{
+ Q_D(QQuickTextEdit);
+ d->control->setOverwriteMode(overwrite);
+}
+
+/*!
\overload
Handles the given key \a event.
*/
@@ -2193,6 +2252,7 @@ void QQuickTextEditPrivate::init()
qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate()));
qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString)));
qmlobject_connect(control, QQuickTextControl, SIGNAL(linkHovered(QString)), q, QQuickTextEdit, SIGNAL(linkHovered(QString)));
+ qmlobject_connect(control, QQuickTextControl, SIGNAL(overwriteModeChanged(bool)), q, QQuickTextEdit, SIGNAL(overwriteModeChanged(bool)));
qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged()));
qmlobject_connect(control, QQuickTextControl, SIGNAL(preeditTextChanged()), q, QQuickTextEdit, SIGNAL(preeditTextChanged()));
#ifndef QT_NO_CLIPBOARD
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index f6ecb984e3..42c9064860 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -86,6 +86,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem
Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged)
Q_PROPERTY(QQmlComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged)
+ Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode NOTIFY overwriteModeChanged)
Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged)
Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged)
Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged)
@@ -199,6 +200,9 @@ public:
QQmlComponent* cursorDelegate() const;
void setCursorDelegate(QQmlComponent*);
+ bool overwriteMode() const;
+ void setOverwriteMode(bool overwrite);
+
int selectionStart() const;
int selectionEnd() const;
@@ -313,6 +317,7 @@ Q_SIGNALS:
void readOnlyChanged(bool isReadOnly);
void cursorVisibleChanged(bool isCursorVisible);
void cursorDelegateChanged();
+ void overwriteModeChanged(bool overwriteMode);
void activeFocusOnPressChanged(bool activeFocusOnPressed);
void persistentSelectionChanged(bool isPersistentSelection);
void textMarginChanged(qreal textMargin);
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 03c6b892c4..65e066c611 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -345,6 +345,38 @@ QString QQuickTextInputPrivate::realText() const
\endqml
*/
+/*!
+ \qmlproperty enumeration QtQuick::TextInput::font.hintingPreference
+ \since 5.8
+
+ Sets the preferred hinting on the text. This is a hint to the underlying text rendering system
+ to use a certain level of hinting, and has varying support across platforms. See the table in
+ the documentation for QFont::HintingPreference for more details.
+
+ \note This property only has an effect when used together with render type TextInput.NativeRendering.
+
+ \list
+ \value Font.PreferDefaultHinting - Use the default hinting level for the target platform.
+ \value Font.PreferNoHinting - If possible, render text without hinting the outlines
+ of the glyphs. The text layout will be typographically accurate, using the same metrics
+ as are used e.g. when printing.
+ \value Font.PreferVerticalHinting - If possible, render text with no horizontal hinting,
+ but align glyphs to the pixel grid in the vertical direction. The text will appear
+ crisper on displays where the density is too low to give an accurate rendering
+ of the glyphs. But since the horizontal metrics of the glyphs are unhinted, the text's
+ layout will be scalable to higher density devices (such as printers) without impacting
+ details such as line breaks.
+ \value Font.PreferFullHinting - If possible, render text with hinting in both horizontal and
+ vertical directions. The text will be altered to optimize legibility on the target
+ device, but since the metrics will depend on the target size of the text, the positions
+ of glyphs, line breaks, and other typographical detail will not scale, meaning that a
+ text layout may look different on devices with different pixel densities.
+ \endlist
+
+ \qml
+ TextInput { text: "Hello"; renderType: TextInput.NativeRendering; font.hintingPreference: Font.PreferVerticalHinting }
+ \endqml
+*/
QFont QQuickTextInput::font() const
{
Q_D(const QQuickTextInput);
@@ -808,7 +840,14 @@ QRectF QQuickTextInput::cursorRectangle() const
return QRectF();
qreal x = l.cursorToX(c) - d->hscroll + leftPadding();
qreal y = l.y() - d->vscroll + topPadding();
- return QRectF(x, y, 1, l.height());
+ qreal w = 1;
+ if (d->overwriteMode) {
+ if (c < text().length())
+ w = l.cursorToX(c + 1) - x;
+ else
+ w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
+ }
+ return QRectF(x, y, w, l.height());
}
/*!
@@ -1289,7 +1328,14 @@ QRectF QQuickTextInput::positionToRectangle(int pos) const
return QRectF();
qreal x = l.cursorToX(pos) - d->hscroll;
qreal y = l.y() - d->vscroll;
- return QRectF(x, y, 1, l.height());
+ qreal w = 1;
+ if (d->overwriteMode) {
+ if (pos < text().length())
+ w = l.cursorToX(pos + 1) - x;
+ else
+ w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw()
+ }
+ return QRectF(x, y, w, l.height());
}
/*!
@@ -1371,6 +1417,36 @@ int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPositi
return line.isValid() ? line.xToCursor(x, position) : 0;
}
+/*!
+ \qmlproperty bool QtQuick::TextInput::overwriteMode
+ \since 5.8
+
+ Whether text entered by the user will overwrite existing text.
+
+ As with many text editors, the text editor widget can be configured
+ to insert or overwrite existing text with new text entered by the user.
+
+ If this property is \c true, existing text is overwritten, character-for-character
+ by new text; otherwise, text is inserted at the cursor position, displacing
+ existing text.
+
+ By default, this property is \c false (new text does not overwrite existing text).
+*/
+bool QQuickTextInput::overwriteMode() const
+{
+ Q_D(const QQuickTextInput);
+ return d->overwriteMode;
+}
+
+void QQuickTextInput::setOverwriteMode(bool overwrite)
+{
+ Q_D(QQuickTextInput);
+ if (d->overwriteMode == overwrite)
+ return;
+ d->overwriteMode = overwrite;
+ emit overwriteModeChanged(overwrite);
+}
+
void QQuickTextInput::keyPressEvent(QKeyEvent* ev)
{
Q_D(QQuickTextInput);
@@ -2768,7 +2844,7 @@ void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate)
// characters)
QChar* uc = str.data();
for (int i = 0; i < (int)str.length(); ++i) {
- if ((uc[i] < 0x20 && uc[i] != 0x09)
+ if ((uc[i].unicode() < 0x20 && uc[i] != QChar::Tabulation)
|| uc[i] == QChar::LineSeparator
|| uc[i] == QChar::ParagraphSeparator
|| uc[i] == QChar::ObjectReplacementCharacter)
@@ -4449,6 +4525,14 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
if (unknown && !m_readOnly) {
QString t = event->text();
if (!t.isEmpty() && t.at(0).isPrint()) {
+ if (overwriteMode
+ // no need to call del() if we have a selection, insert
+ // does it already
+ && !hasSelectedText()
+ && !(m_cursor == q_func()->text().length())) {
+ del();
+ }
+
insert(t);
event->accept();
return;
diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h
index 211d9146fc..d0461f551e 100644
--- a/src/quick/items/qquicktextinput_p.h
+++ b/src/quick/items/qquicktextinput_p.h
@@ -79,6 +79,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem
Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged)
Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged)
Q_PROPERTY(QQmlComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged)
+ Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode NOTIFY overwriteModeChanged)
Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged)
Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged)
Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged)
@@ -245,6 +246,9 @@ public:
QQmlComponent* cursorDelegate() const;
void setCursorDelegate(QQmlComponent*);
+ bool overwriteMode() const;
+ void setOverwriteMode(bool overwrite);
+
bool focusOnPress() const;
void setFocusOnPress(bool);
@@ -325,6 +329,7 @@ Q_SIGNALS:
void readOnlyChanged(bool isReadOnly);
void cursorVisibleChanged(bool isCursorVisible);
void cursorDelegateChanged();
+ void overwriteModeChanged(bool overwriteMode);
void maximumLengthChanged(int maximumLength);
void validatorChanged();
void inputMaskChanged(const QString &inputMask);
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index 57a9f6413a..93a8778c40 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -158,6 +158,7 @@ public:
, m_passwordEchoEditing(false)
, inLayout(false)
, requireImplicitWidth(false)
+ , overwriteMode(false)
{
}
@@ -299,6 +300,7 @@ public:
bool m_passwordEchoEditing : 1;
bool inLayout:1;
bool requireImplicitWidth:1;
+ bool overwriteMode:1;
static inline QQuickTextInputPrivate *get(QQuickTextInput *t) {
return t->d_func();
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index ef94b0eef7..11249be8c6 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -734,10 +734,13 @@ void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularN
QVector<QPointF> glyphPositions = glyphRun.positions();
glyphPositions.reserve(count);
+ QRectF glyphBoundingRect = glyphRun.boundingRect();
+
for (int j = 1; j < nodes.size(); ++j) {
BinaryTreeNode *otherNode = nodes.at(j);
glyphIndexes += otherNode->glyphRun.glyphIndexes();
primaryNode->ranges += otherNode->ranges;
+ glyphBoundingRect = glyphBoundingRect.united(otherNode->boundingRect);
QVector<QPointF> otherPositions = otherNode->glyphRun.positions();
for (int k = 0; k < otherPositions.size(); ++k)
@@ -749,6 +752,7 @@ void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularN
glyphRun.setGlyphIndexes(glyphIndexes);
glyphRun.setPositions(glyphPositions);
+ glyphRun.setBoundingRect(glyphBoundingRect);
}
}
}
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index 3ce96b673d..1101b88992 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -194,9 +194,8 @@ QQuickView::QQuickView(QWindow *parent)
*/
QQuickView::QQuickView(const QUrl &source, QWindow *parent)
-: QQuickWindow(*(new QQuickViewPrivate), parent)
+ : QQuickView(parent)
{
- d_func()->init();
setSource(source);
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 9ef651bffa..98e450abdb 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -74,16 +74,20 @@
#include <private/qqmlmemoryprofiler_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
#include <private/qqmldebugconnector_p.h>
-
-#include <private/qopenglvertexarrayobject_p.h>
+#ifndef QT_NO_OPENGL
+# include <private/qopenglvertexarrayobject_p.h>
+# include <private/qsgdefaultrendercontext_p.h>
+#endif
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch");
-Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target");
-Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse");
-Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus");
-Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty");
+Q_LOGGING_CATEGORY(DBG_TOUCH, "qt.quick.touch")
+Q_LOGGING_CATEGORY(DBG_TOUCH_TARGET, "qt.quick.touch.target")
+Q_LOGGING_CATEGORY(DBG_MOUSE, "qt.quick.mouse")
+Q_LOGGING_CATEGORY(DBG_MOUSE_TARGET, "qt.quick.mouse.target")
+Q_LOGGING_CATEGORY(DBG_HOVER_TRACE, "qt.quick.hover.trace")
+Q_LOGGING_CATEGORY(DBG_FOCUS, "qt.quick.focus")
+Q_LOGGING_CATEGORY(DBG_DIRTY, "qt.quick.dirty")
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@@ -746,6 +750,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
if (mouseGrabberItem == grabber)
return;
+ qCDebug(DBG_MOUSE_TARGET) << "grabber" << mouseGrabberItem << "->" << grabber;
QQuickItem *oldGrabber = mouseGrabberItem;
mouseGrabberItem = grabber;
@@ -1120,8 +1125,8 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
\section1 Rendering
- QQuickWindow uses a scene graph on top of OpenGL to
- render. This scene graph is disconnected from the QML scene and
+ QQuickWindow uses a scene graph to represent what needs to be rendered.
+ This scene graph is disconnected from the QML scene and
potentially lives in another thread, depending on the platform
implementation. Since the rendering scene graph lives
independently from the QML scene, it can also be completely
@@ -1135,9 +1140,9 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
\section2 Integration with OpenGL
- It is possible to integrate OpenGL calls directly into the
- QQuickWindow using the same OpenGL context as the Qt Quick Scene
- Graph. This is done by connecting to the
+ When using the default OpenGL adaptation, it is possible to integrate
+ OpenGL calls directly into the QQuickWindow using the same OpenGL
+ context as the Qt Quick Scene Graph. This is done by connecting to the
QQuickWindow::beforeRendering() or QQuickWindow::afterRendering()
signal.
@@ -1150,10 +1155,10 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
When a QQuickWindow instance is deliberately hidden with hide() or
setVisible(false), it will stop rendering and its scene graph and
- OpenGL context might be released. The sceneGraphInvalidated()
+ graphics context might be released. The sceneGraphInvalidated()
signal will be emitted when this happens.
- \warning It is crucial that OpenGL operations and interaction with
+ \warning It is crucial that graphics operations and interaction with
the scene graph happens exclusively on the rendering thread,
primarily during the updatePaintNode() phase.
@@ -1169,8 +1174,9 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
required to aggressively release these resources. The
releaseResources() can be used to force the clean up of certain
resources. Calling releaseResources() may result in the entire
- scene graph and its OpenGL context being deleted. The
- sceneGraphInvalidated() signal will be emitted when this happens.
+ scene graph and in the case of the OpenGL adaptation the associated
+ context will be deleted. The sceneGraphInvalidated() signal will be
+ emitted when this happens.
\note All classes with QSG prefix should be used solely on the scene graph's
rendering thread. See \l {Scene Graph and Rendering} for more information.
@@ -1193,10 +1199,8 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
Constructs a window for displaying a QML scene with parent window \a parent.
*/
QQuickWindow::QQuickWindow(QWindow *parent)
- : QWindow(*(new QQuickWindowPrivate), parent)
+ : QQuickWindow(*new QQuickWindowPrivate, parent)
{
- Q_D(QQuickWindow);
- d->init(this);
}
@@ -1306,6 +1310,9 @@ void QQuickWindow::releaseResources()
The OpenGL context is still released when the last QQuickWindow is
deleted.
+ \note This only has an effect when using the default OpenGL scene
+ graph adaptation.
+
\sa setPersistentSceneGraph(),
QOpenGLContext::aboutToBeDestroyed(), sceneGraphInitialized()
*/
@@ -1323,7 +1330,8 @@ void QQuickWindow::setPersistentOpenGLContext(bool persistent)
lifetime of the QQuickWindow.
\note This is a hint. When and how this happens is implementation
- specific.
+ specific. It also only has an effect when using the default OpenGL
+ scene graph adaptation
*/
bool QQuickWindow::isPersistentOpenGLContext() const
@@ -1673,7 +1681,7 @@ void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
return;
}
- qCDebug(DBG_MOUSE) << "QQuickWindow::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons();
+ qCDebug(DBG_MOUSE) << "QQuickWindow::mouseReleaseEvent()" << event->localPos() << event->button() << event->buttons() << "grabber:" << d->mouseGrabberItem;
if (!d->mouseGrabberItem) {
QWindow::mouseReleaseEvent(event);
@@ -1744,6 +1752,7 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
}
qCDebug(DBG_MOUSE) << "QQuickWindow::mouseMoveEvent()" << event->localPos() << event->button() << event->buttons();
+ qCDebug(DBG_HOVER_TRACE) << this;
#ifndef QT_NO_CURSOR
d->updateCursor(event->windowPos());
@@ -1780,13 +1789,16 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
return false;
}
- QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
- for (int ii = children.count() - 1; ii >= 0; --ii) {
- QQuickItem *child = children.at(ii);
- if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
- continue;
- if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
- return true;
+ qCDebug(DBG_HOVER_TRACE) << q << item << scenePos << lastScenePos << "subtreeHoverEnabled" << itemPrivate->subtreeHoverEnabled;
+ if (itemPrivate->subtreeHoverEnabled) {
+ QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
+ for (int ii = children.count() - 1; ii >= 0; --ii) {
+ QQuickItem *child = children.at(ii);
+ if (!child->isVisible() || !child->isEnabled() || QQuickItemPrivate::get(child)->culled)
+ continue;
+ if (deliverHoverEvent(child, scenePos, lastScenePos, modifiers, accepted))
+ return true;
+ }
}
if (itemPrivate->hoverEnabled) {
@@ -2038,7 +2050,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
}
}
-void QQuickWindowPrivate::flushDelayedTouchEvent()
+void QQuickWindowPrivate::flushFrameSynchronousEvents()
{
if (delayedTouch) {
deliverDelayedTouchEvent();
@@ -2049,6 +2061,17 @@ void QQuickWindowPrivate::flushDelayedTouchEvent()
if (ut && ut->hasStartAnimationPending())
ut->startAnimations();
}
+
+ // Once per frame, send a synthetic hover, in case items have changed position.
+ // For instance, during animation (including the case of a ListView
+ // whose delegates contain MouseAreas), a MouseArea needs to know
+ // whether it has moved into a position where it is now under the cursor.
+ if (!mouseGrabberItem && !lastMousePosition.isNull()) {
+ bool accepted = false;
+ bool delivered = deliverHoverEvent(contentItem, lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), accepted);
+ if (!delivered)
+ clearHover(); // take care of any exits
+ }
}
void QQuickWindowPrivate::reallyDeliverTouchEvent(QTouchEvent *event)
@@ -2201,7 +2224,7 @@ bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
return (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty());
}
-// touchEventForItemBounds has no means to generate a touch event that contains
+// touchEventForItem has no means to generate a touch event that contains
// only the points that are relevant for this item. Thus the need for
// matchingPoints to already be that set of interesting points.
// They are all pre-transformed, too.
@@ -2263,7 +2286,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv
return touchEventAccepted;
}
-QTouchEvent *QQuickWindowPrivate::touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent)
+QTouchEvent *QQuickWindowPrivate::touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds)
{
const QList<QTouchEvent::TouchPoint> &touchPoints = originalEvent.touchPoints();
QList<QTouchEvent::TouchPoint> pointsInBounds;
@@ -2271,7 +2294,10 @@ QTouchEvent *QQuickWindowPrivate::touchEventForItemBounds(QQuickItem *target, co
if (originalEvent.touchPointStates() != Qt::TouchPointStationary) {
for (int i = 0; i < touchPoints.count(); ++i) {
const QTouchEvent::TouchPoint &tp = touchPoints.at(i);
- if (tp.state() == Qt::TouchPointPressed) {
+ // Touch presses are relevant to the target item only if they occur inside its bounds.
+ // Touch updates and releases are relevant if they occur inside, or if we want to
+ // finish the sequence because the press occurred inside.
+ if (tp.state() == Qt::TouchPointPressed || alwaysCheckBounds) {
QPointF p = target->mapFromScene(tp.scenePos());
if (target->contains(p))
pointsInBounds.append(tp);
@@ -2500,7 +2526,7 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) {
hasFiltered->insert(target);
- QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event));
+ QScopedPointer<QTouchEvent> targetEvent(touchEventForItem(target, *event));
if (!targetEvent->touchPoints().isEmpty()) {
if (target->childMouseEventFilter(item, targetEvent.data())) {
qCDebug(DBG_TOUCH) << " - first chance intercepted on childMouseEventFilter by " << target;
@@ -2580,6 +2606,7 @@ bool QQuickWindowPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem
hasFiltered->insert(target);
if (target->childMouseEventFilter(item, event))
filtered = true;
+ qCDebug(DBG_MOUSE_TARGET) << target << "childMouseEventFilter ->" << filtered;
}
return sendFilteredMouseEvent(target->parentItem(), item, event, hasFiltered) || filtered;
@@ -2600,6 +2627,15 @@ bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent
return overThreshold;
}
+bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, const QTouchEvent::TouchPoint *tp, int startDragThreshold)
+{
+ QStyleHints *styleHints = qApp->styleHints();
+ bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
+ qreal velocity = axis == Qt::XAxis ? tp->velocity().x() : tp->velocity().y();
+ overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
+ return overThreshold;
+}
+
/*!
\qmlproperty list<Object> Window::data
\default
@@ -3166,10 +3202,10 @@ void QQuickWindow::maybeUpdate()
void QQuickWindow::cleanupSceneGraph()
{
Q_D(QQuickWindow);
-
+#ifndef QT_NO_OPENGL
delete d->vaoHelper;
d->vaoHelper = 0;
-
+#endif
if (!d->renderer)
return;
@@ -3192,17 +3228,30 @@ void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
}
/*!
- Returns the opengl context used for rendering.
+ Returns the OpenGL context used for rendering.
+
+ If the scene graph is not ready, or the scene graph is not using OpenGL,
+ this function will return null.
- If the scene graph is not ready, this function will return 0.
+ \note If using a scene graph adaptation other than OpenGL this
+ function will return nullptr.
\sa sceneGraphInitialized(), sceneGraphInvalidated()
*/
QOpenGLContext *QQuickWindow::openglContext() const
{
+#ifndef QT_NO_OPENGL
Q_D(const QQuickWindow);
- return d->context ? d->context->openglContext() : 0;
+ if (d->context && d->context->isValid()) {
+ QSGRendererInterface *rif = d->context->sceneGraphContext()->rendererInterface(d->context);
+ if (rif && rif->graphicsApi() == QSGRendererInterface::OpenGL) {
+ auto openglRenderContext = static_cast<const QSGDefaultRenderContext *>(d->context);
+ return openglRenderContext->openglContext();
+ }
+ }
+#endif
+ return nullptr;
}
/*!
@@ -3238,14 +3287,14 @@ bool QQuickWindow::isSceneGraphInitialized() const
This signal is emitted when the scene graph has been invalidated.
- This signal implies that the opengl rendering context used
+ This signal implies that the graphics rendering context used
has been invalidated and all user resources tied to that context
should be released.
- The OpenGL context of this window will be bound when this function
- is called. The only exception is if the native OpenGL has been
- destroyed outside Qt's control, for instance through
- EGL_CONTEXT_LOST.
+ In the case of the default OpenGL adaptation the context of this
+ window will be bound when this function is called. The only exception
+ is if the native OpenGL has been destroyed outside Qt's control,
+ for instance through EGL_CONTEXT_LOST.
This signal will be emitted from the scene graph rendering thread.
*/
@@ -3256,7 +3305,7 @@ bool QQuickWindow::isSceneGraphInitialized() const
This signal is emitted when an \a error occurred during scene graph initialization.
Applications should connect to this signal if they wish to handle errors,
- like OpenGL context creation failures, in a custom way. When no slot is
+ like graphics context creation failures, in a custom way. When no slot is
connected to the signal, the behavior will be different: Quick will print
the \a message, or show a message box, and terminate the application.
@@ -3318,13 +3367,17 @@ bool QQuickWindow::isSceneGraphInitialized() const
The corresponding handler is \c onClosing.
*/
-
+#ifndef QT_NO_OPENGL
/*!
Sets the render target for this window to be \a fbo.
The specified fbo must be created in the context of the window
or one that shares with it.
+ \note
+ This function only has an effect when using the default OpenGL scene
+ graph adaptation.
+
\warning
This function can only be called from the thread doing
the rendering.
@@ -3347,7 +3400,7 @@ void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo)
d->renderTargetSize = QSize();
}
}
-
+#endif
/*!
\overload
@@ -3357,6 +3410,10 @@ void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo)
The specified FBO must be created in the context of the window
or one that shares with it.
+ \note
+ This function only has an effect when using the default OpenGL scene
+ graph adaptation.
+
\warning
This function can only be called from the thread doing
the rendering.
@@ -3398,19 +3455,23 @@ QSize QQuickWindow::renderTargetSize() const
-
+#ifndef QT_NO_OPENGL
/*!
Returns the render target for this window.
The default is to render to the surface of the window, in which
case the render target is 0.
+
+ \note
+ This function will return nullptr when not using the OpenGL scene
+ graph adaptation.
*/
QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
{
Q_D(const QQuickWindow);
return d->renderTarget;
}
-
+#endif
/*!
Grabs the contents of the window and returns it as an image.
@@ -3427,33 +3488,42 @@ QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
QImage QQuickWindow::grabWindow()
{
Q_D(QQuickWindow);
- if (!isVisible() && !d->context->openglContext()) {
- if (!handle() || !size().isValid()) {
- qWarning("QQuickWindow::grabWindow: window must be created and have a valid size");
- return QImage();
- }
+ if (!isVisible() && !d->renderControl) {
+ if (d->windowManager && (d->windowManager->flags() & QSGRenderLoop::SupportsGrabWithoutExpose))
+ return d->windowManager->grab(this);
+ }
+
+#ifndef QT_NO_OPENGL
+ if (!isVisible() && !d->renderControl) {
+ auto openglRenderContext = static_cast<QSGDefaultRenderContext *>(d->context);
+ if (!openglRenderContext->openglContext()) {
+ if (!handle() || !size().isValid()) {
+ qWarning("QQuickWindow::grabWindow: window must be created and have a valid size");
+ return QImage();
+ }
- QOpenGLContext context;
- context.setFormat(requestedFormat());
- context.setShareContext(qt_gl_global_share_context());
- context.create();
- context.makeCurrent(this);
- d->context->initialize(&context);
+ QOpenGLContext context;
+ context.setFormat(requestedFormat());
+ context.setShareContext(qt_gl_global_share_context());
+ context.create();
+ context.makeCurrent(this);
+ d->context->initialize(&context);
- d->polishItems();
- d->syncSceneGraph();
- d->renderSceneGraph(size());
+ d->polishItems();
+ d->syncSceneGraph();
+ d->renderSceneGraph(size());
- bool alpha = format().alphaBufferSize() > 0 && color().alpha() < 255;
- QImage image = qt_gl_read_framebuffer(size() * effectiveDevicePixelRatio(), alpha, alpha);
- d->cleanupNodesOnShutdown();
- d->context->invalidate();
- context.doneCurrent();
+ bool alpha = format().alphaBufferSize() > 0 && color().alpha() < 255;
+ QImage image = qt_gl_read_framebuffer(size() * effectiveDevicePixelRatio(), alpha, alpha);
+ d->cleanupNodesOnShutdown();
+ d->context->invalidate();
+ context.doneCurrent();
- return image;
+ return image;
+ }
}
-
+#endif
if (d->renderControl)
return d->renderControl->grab();
else if (d->windowManager)
@@ -3495,7 +3565,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
mipmapping enabled.
\value TextureOwnsGLTexture The texture object owns the texture id and
- will delete the GL texture when the texture object is deleted.
+ will delete the OpenGL texture when the texture object is deleted.
\value TextureCanUseAtlas The image can be uploaded into a texture atlas.
@@ -3510,7 +3580,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
This enum describes the error in a sceneGraphError() signal.
- \value ContextNotAvailable OpenGL context creation failed. This typically means that
+ \value ContextNotAvailable graphics context creation failed. This typically means that
no suitable OpenGL implementation was found, for example because no graphics drivers
are installed and so no OpenGL 2 support is present. On mobile and embedded boards
that use OpenGL ES such an error is likely to indicate issues in the windowing system
@@ -3527,7 +3597,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
This signal can be used to do any preparation required before calls to
QQuickItem::updatePaintNode().
- The GL context used for rendering the scene graph will be bound at this point.
+ The OpenGL context used for rendering the scene graph will be bound at this point.
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
@@ -3548,15 +3618,16 @@ QQmlIncubationController *QQuickWindow::incubationController() const
This signal can be used to do preparation required after calls to
QQuickItem::updatePaintNode(), while the GUI thread is still locked.
- The GL context used for rendering the scene graph will be bound at this point.
+ The graphics context used for rendering the scene graph will be bound at this point.
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
- \warning Make very sure that a signal handler for afterSynchronizing leaves the GL
- context in the same state as it was when the signal handler was entered. Failing to
- do so can result in the scene not rendering properly.
+ \warning When using the OpenGL adaptation, make sure that a signal handler for
+ afterSynchronizing leaves the OpenGL context in the same state as it was when the
+ signal handler was entered. Failing to do so can result in the scene not rendering
+ properly.
\since 5.3
\sa resetOpenGLState()
@@ -3568,16 +3639,16 @@ QQmlIncubationController *QQuickWindow::incubationController() const
This signal is emitted before the scene starts rendering.
Combined with the modes for clearing the background, this option
- can be used to paint using raw GL under QML content.
+ can be used to paint using raw OpenGL under QML content.
- The GL context used for rendering the scene graph will be bound
+ The OpenGL context used for rendering the scene graph will be bound
at this point.
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
- \warning Make very sure that a signal handler for beforeRendering leaves the GL
+ \warning Make very sure that a signal handler for beforeRendering leaves the OpenGL
context in the same state as it was when the signal handler was entered. Failing to
do so can result in the scene not rendering properly.
@@ -3589,16 +3660,16 @@ QQmlIncubationController *QQuickWindow::incubationController() const
This signal is emitted after the scene has completed rendering, before swapbuffers is called.
- This signal can be used to paint using raw GL on top of QML content,
+ This signal can be used to paint using raw OpenGL on top of QML content,
or to do screen scraping of the current frame buffer.
- The GL context used for rendering the scene graph will be bound at this point.
+ The OpenGL context used for rendering the scene graph will be bound at this point.
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
- \warning Make very sure that a signal handler for afterRendering() leaves the GL
+ \warning Make very sure that a signal handler for afterRendering() leaves the OpenGL
context in the same state as it was when the signal handler was entered. Failing to
do so can result in the scene not rendering properly.
@@ -3633,6 +3704,10 @@ QQmlIncubationController *QQuickWindow::incubationController() const
until after the QQuickWindow::sceneGraphInitialize() has been
emitted.
+ \note
+ This signal will only be emmited when using the default OpenGL scene
+ graph adaptation.
+
\since 5.3
*/
@@ -3645,15 +3720,15 @@ QQmlIncubationController *QQuickWindow::incubationController() const
Applications may use this signal to release resources, but should be
prepared to reinstantiated them again fast. The scene graph and the
- OpenGL context are not released at this time.
+ graphics context are not released at this time.
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
the connection is direct (see Qt::ConnectionType).
- \warning Make very sure that a signal handler for sceneGraphAboutToStop() leaves the GL
- context in the same state as it was when the signal handler was entered. Failing to
- do so can result in the scene not rendering properly.
+ \warning Make very sure that a signal handler for sceneGraphAboutToStop() leaves the
+ graphics context in the same state as it was when the signal handler was entered.
+ Failing to do so can result in the scene not rendering properly.
\sa sceneGraphInvalidated(), resetOpenGLState()
\since 5.3
@@ -3664,7 +3739,7 @@ QQmlIncubationController *QQuickWindow::incubationController() const
Sets whether the scene graph rendering of QML should clear the color buffer
before it starts rendering to \a enabled.
- By disabling clearing of the color buffer, it is possible to do GL painting
+ By disabling clearing of the color buffer, it is possible to render OpengGL content
under the scene graph.
The color buffer is cleared by default.
@@ -3705,7 +3780,8 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
alpha channel, the corresponding texture will have an alpha channel.
The caller of the function is responsible for deleting the returned texture.
- The actual GL texture will be deleted when the texture object is deleted.
+ For example whe using the OpenGL adaptation the actual OpenGL texture will
+ be deleted when the texture object is deleted.
When \a options contains TextureCanUseAtlas, the engine may put the image
into a texture atlas. Textures in an atlas need to rely on
@@ -3722,9 +3798,9 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
texture which can use mipmap filtering. Mipmapped textures can not be in
an atlas.
- The returned texture will be using \c GL_TEXTURE_2D as texture target and
- \c GL_RGBA as internal format. Reimplement QSGTexture to create textures
- with different parameters.
+ When using the OpenGL adaptation, the returned texture will be using
+ \c GL_TEXTURE_2D as texture target and \c GL_RGBA as internal format.
+ Reimplement QSGTexture to create textures with different parameters.
\warning This function will return 0 if the scene graph has not yet been
initialized.
@@ -3743,7 +3819,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const
{
Q_D(const QQuickWindow);
- if (!d->context)
+ if (!isSceneGraphInitialized()) // check both for d->context and d->context->isValid()
return 0;
uint flags = 0;
if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas;
@@ -3755,7 +3831,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
/*!
- Creates a new QSGTexture object from an existing GL texture \a id and \a size.
+ Creates a new QSGTexture object from an existing OpenGL texture \a id and \a size.
The caller of the function is responsible for deleting the returned texture.
@@ -3766,15 +3842,18 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText
Use \a options to customize the texture attributes. The TextureUsesAtlas
option is ignored.
- \warning This function will return 0 if the scenegraph has not yet been
- initialized.
+ \warning This function will return null if the scenegraph has not yet been
+ initialized or OpenGL is not in use.
+
+ \note This function only has an effect when using the default OpenGL scene graph
+ adpation.
\sa sceneGraphInitialized(), QSGTexture
*/
QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, CreateTextureOptions options) const
{
- Q_D(const QQuickWindow);
- if (d->context && d->context->openglContext()) {
+#ifndef QT_NO_OPENGL
+ if (openglContext()) {
QSGPlainTexture *texture = new QSGPlainTexture();
texture->setTextureId(id);
texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
@@ -3782,6 +3861,11 @@ QSGTexture *QQuickWindow::createTextureFromId(uint id, const QSize &size, Create
texture->setTextureSize(size);
return texture;
}
+#else
+ Q_UNUSED(id)
+ Q_UNUSED(size)
+ Q_UNUSED(options)
+#endif
return 0;
}
@@ -3851,7 +3935,7 @@ void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha)
{
QQuickWindowPrivate::defaultAlphaBuffer = useAlpha;
}
-
+#ifndef QT_NO_OPENGL
/*!
\since 5.2
@@ -3869,6 +3953,9 @@ void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha)
buffer. The depth and stencil buffer might be clobbered by the scene
graph renderer. Clear these manually on demand.
+ \note This function only has an effect when using the default OpenGL scene graph
+ adpation.
+
\sa QQuickWindow::beforeRendering()
*/
void QQuickWindow::resetOpenGLState()
@@ -3923,7 +4010,7 @@ void QQuickWindow::resetOpenGLState()
QOpenGLFramebufferObject::bindDefault();
}
-
+#endif
/*!
\qmlproperty string Window::title
@@ -4362,6 +4449,70 @@ qreal QQuickWindow::effectiveDevicePixelRatio() const
return w ? w->devicePixelRatio() : devicePixelRatio();
}
+/*!
+ Returns the current renderer interface if there is one. Otherwise null is returned.
+
+ \sa QSGRenderNode, QSGRendererInterface, isSceneGraphInitialized()
+
+ \since 5.8
+ */
+QSGRendererInterface *QQuickWindow::rendererInterface() const
+{
+ Q_D(const QQuickWindow);
+ return isSceneGraphInitialized() ? d->context->sceneGraphContext()->rendererInterface(d->context) : nullptr;
+}
+
+/*!
+ Requests a Qt Quick scenegraph backend for the specified graphics \a api.
+ Backends can either be built-in or be installed in form of dynamically
+ loaded plugins.
+
+ \note The call to the function must happen before constructing the first
+ QQuickWindow in the application. It cannot be changed afterwards.
+
+ If \a backend is invalid or an error occurs, the default backend (OpenGL or
+ software, depending on the Qt configuration) is used.
+
+ \since 5.8
+ */
+void QQuickWindow::setSceneGraphBackend(QSGRendererInterface::GraphicsApi api)
+{
+ switch (api) {
+ case QSGRendererInterface::Software:
+ setSceneGraphBackend(QStringLiteral("software"));
+ break;
+ case QSGRendererInterface::Direct3D12:
+ setSceneGraphBackend(QStringLiteral("d3d12"));
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ Requests the specified Qt Quick scenegraph \a backend. Backends can either
+ be built-in or be installed in form of dynamically loaded plugins.
+
+ \overload
+
+ \note The call to the function must happen before constructing the first
+ QQuickWindow in the application. It cannot be changed afterwards.
+
+ If \a backend is invalid or an error occurs, the default backend (OpenGL or
+ software, depending on the Qt configuration) is used.
+
+ \note Calling this function is equivalent to setting the
+ \c QT_QUICK_BACKEND or \c QMLSCENE_DEVICE environment variables. However, this
+ API is safer to use in applications that spawn other processes as there is
+ no need to worry about environment inheritance.
+
+ \since 5.8
+ */
+void QQuickWindow::setSceneGraphBackend(const QString &backend)
+{
+ QSGContext::setBackend(backend);
+}
+
#include "moc_qquickwindow.cpp"
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 1024147bb4..c741772253 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -41,6 +41,7 @@
#define QQUICKWINDOW_H
#include <QtQuick/qtquickglobal.h>
+#include <QtQuick/qsgrendererinterface.h>
#include <QtCore/qmetatype.h>
#include <QtGui/qopengl.h>
#include <QtGui/qwindow.h>
@@ -110,16 +111,16 @@ public:
bool sendEvent(QQuickItem *, QEvent *);
QImage grabWindow();
-
+#ifndef QT_NO_OPENGL
void setRenderTarget(QOpenGLFramebufferObject *fbo);
QOpenGLFramebufferObject *renderTarget() const;
-
+#endif
void setRenderTarget(uint fboId, const QSize &size);
uint renderTargetId() const;
QSize renderTargetSize() const;
-
+#ifndef QT_NO_OPENGL
void resetOpenGLState();
-
+#endif
QQmlIncubationController *incubationController() const;
#ifndef QT_NO_ACCESSIBILITY
@@ -153,6 +154,11 @@ public:
qreal effectiveDevicePixelRatio() const;
+ QSGRendererInterface *rendererInterface() const;
+
+ static void setSceneGraphBackend(QSGRendererInterface::GraphicsApi api);
+ static void setSceneGraphBackend(const QString &backend);
+
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 1064be7178..daff9ef473 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -160,11 +160,11 @@ public:
void reallyDeliverTouchEvent(QTouchEvent *);
bool deliverTouchCancelEvent(QTouchEvent *);
void deliverDelayedTouchEvent();
- void flushDelayedTouchEvent();
+ void flushFrameSynchronousEvents();
bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted);
bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered);
- QTouchEvent *touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent);
- QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints);
+ static QTouchEvent *touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds = false);
+ static QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints);
bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem*> *filtered);
bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos,
Qt::KeyboardModifiers modifiers, bool accepted);
@@ -265,6 +265,7 @@ public:
static bool defaultAlphaBuffer;
static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold = -1);
+ static bool dragOverThreshold(qreal d, Qt::Axis axis, const QTouchEvent::TouchPoint *tp, int startDragThreshold = -1);
// data property
static void data_append(QQmlListProperty<QObject> *, QObject *);