aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/quick/items/items.pri15
-rw-r--r--src/quick/items/items.qrc4
-rw-r--r--src/quick/items/qquickitemsmodule.cpp9
-rw-r--r--src/quick/items/qquickpathitem.cpp792
-rw-r--r--src/quick/items/qquickpathitem_p.h281
-rw-r--r--src/quick/items/qquickpathitem_p_p.h177
-rw-r--r--src/quick/items/qquickpathitemgenericrenderer.cpp510
-rw-r--r--src/quick/items/qquickpathitemgenericrenderer_p.h232
-rw-r--r--src/quick/items/qquickpathitemnvprrenderer.cpp567
-rw-r--r--src/quick/items/qquickpathitemnvprrenderer_p.h194
-rw-r--r--src/quick/items/qquickpathitemsoftwarerenderer.cpp234
-rw-r--r--src/quick/items/qquickpathitemsoftwarerenderer_p.h127
-rw-r--r--src/quick/items/shaders/lineargradient.frag9
-rw-r--r--src/quick/items/shaders/lineargradient.vert15
-rw-r--r--src/quick/items/shaders/lineargradient_core.frag12
-rw-r--r--src/quick/items/shaders/lineargradient_core.vert17
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp4
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.cpp3
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp2
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp24
-rw-r--r--src/quick/scenegraph/util/qsgtexture.h3
-rw-r--r--src/quick/scenegraph/util/qsgtexture_p.h4
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp4
-rw-r--r--src/quick/util/qquicknvprfunctions.cpp284
-rw-r--r--src/quick/util/qquicknvprfunctions_p.h406
-rw-r--r--src/quick/util/qquicknvprfunctions_p_p.h70
-rw-r--r--src/quick/util/qquickpath.cpp70
-rw-r--r--src/quick/util/qquickpath_p.h10
-rw-r--r--src/quick/util/util.pri7
29 files changed, 4068 insertions, 18 deletions
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index 0f8061b5ef..511c6f18d8 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -148,9 +148,20 @@ qtConfig(quick-listview) {
qtConfig(quick-pathview) {
HEADERS += \
$$PWD/qquickpathview_p.h \
- $$PWD/qquickpathview_p_p.h
+ $$PWD/qquickpathview_p_p.h \
+ $$PWD/qquickpathitem_p.h \
+ $$PWD/qquickpathitem_p_p.h \
+ $$PWD/qquickpathitemgenericrenderer_p.h \
+ $$PWD/qquickpathitemsoftwarerenderer_p.h
SOURCES += \
- $$PWD/qquickpathview.cpp
+ $$PWD/qquickpathview.cpp \
+ $$PWD/qquickpathitem.cpp \
+ $$PWD/qquickpathitemgenericrenderer.cpp \
+ $$PWD/qquickpathitemsoftwarerenderer.cpp
+ qtConfig(opengl) {
+ HEADERS += $$PWD/qquickpathitemnvprrenderer_p.h
+ SOURCES += $$PWD/qquickpathitemnvprrenderer.cpp
+ }
}
qtConfig(quick-positioners) {
diff --git a/src/quick/items/items.qrc b/src/quick/items/items.qrc
index 6aaf757c29..da9bf0c828 100644
--- a/src/quick/items/items.qrc
+++ b/src/quick/items/items.qrc
@@ -8,5 +8,9 @@
<file>shaders/shadereffect_core.vert</file>
<file>shaders/shadereffectfallback_core.frag</file>
<file>shaders/shadereffectfallback_core.vert</file>
+ <file>shaders/lineargradient.vert</file>
+ <file>shaders/lineargradient.frag</file>
+ <file>shaders/lineargradient_core.vert</file>
+ <file>shaders/lineargradient_core.frag</file>
</qresource>
</RCC>
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index dbe30fbc83..b0d7f7f8a3 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -70,6 +70,7 @@
#if QT_CONFIG(quick_path)
#include <private/qquickpath_p.h>
#include <private/qquickpathinterpolator_p.h>
+#include "qquickpathitem_p.h"
#endif
#if QT_CONFIG(quick_positioners)
#include "qquickpositioners_p.h"
@@ -370,6 +371,14 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor)
#endif
qmlRegisterType<QQuickMouseArea, 9>(uri, 2, 9, "MouseArea");
+
+#if QT_CONFIG(quick_path)
+ qmlRegisterType<QQuickPathMove>(uri, 2, 9, "PathMove");
+ qmlRegisterType<QQuickPathItem>(uri, 2, 9, "PathItem");
+ qmlRegisterType<QQuickPathGradientStop>(uri, 2, 9, "PathGradientStop");
+ qmlRegisterUncreatableType<QQuickPathGradient>(uri, 2, 9, "PathGradient", QQuickPathGradient::tr("PathGradient is an abstract base class"));
+ qmlRegisterType<QQuickPathLinearGradient>(uri, 2, 9, "PathLinearGradient");
+#endif
}
static void initResources()
diff --git a/src/quick/items/qquickpathitem.cpp b/src/quick/items/qquickpathitem.cpp
new file mode 100644
index 0000000000..0d2c7a8bbe
--- /dev/null
+++ b/src/quick/items/qquickpathitem.cpp
@@ -0,0 +1,792 @@
+/****************************************************************************
+**
+** 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 "qquickpathitem_p.h"
+#include "qquickpathitem_p_p.h"
+#include "qquickpathitemgenericrenderer_p.h"
+#include "qquickpathitemnvprrenderer_p.h"
+#include "qquickpathitemsoftwarerenderer_p.h"
+#include <private/qsgtexture_p.h>
+#include <QtGui/private/qdrawhelper_p.h>
+#include <QOpenGLFunctions>
+
+QT_BEGIN_NAMESPACE
+
+QQuickPathItemPrivate::QQuickPathItemPrivate()
+ : rendererType(QQuickPathItem::UnknownRenderer),
+ renderer(nullptr),
+ path(nullptr),
+ dirty(DirtyAll),
+ strokeColor(Qt::white),
+ strokeWidth(1),
+ fillColor(Qt::white),
+ fillRule(QQuickPathItem::OddEvenFill),
+ joinStyle(QQuickPathItem::BevelJoin),
+ miterLimit(2),
+ capStyle(QQuickPathItem::SquareCap),
+ strokeStyle(QQuickPathItem::SolidLine),
+ dashOffset(0),
+ fillGradient(nullptr)
+{
+ dashPattern << 4 << 2; // 4 * strokeWidth dash followed by 2 * strokeWidth space
+}
+
+QQuickPathItemPrivate::~QQuickPathItemPrivate()
+{
+ delete renderer;
+}
+
+/*!
+ \qmltype PathItem
+ \instantiates QQuickPathItem
+ \inqmlmodule QtQuick
+ \ingroup qtquick-paths
+ \ingroup qtquick-views
+ \inherits Item
+ \brief Renders a path
+
+ Renders a path either by generating geometry via QPainterPath and manual
+ triangulation or by using an extension like \c{GL_NV_path_rendering}.
+
+ This approach is different from rendering shapes via QQuickPaintedItem or
+ the 2D Canvas because the path never gets rasterized in software. Therefore
+ it is suitable for creating shapes spreading over larger areas of the
+ screen, avoiding the performance penalty for texture uploads or framebuffer
+ blits.
+
+ Nonetheless it is important to be aware of performance implications, in
+ particular when the application is running on the generic PathItem
+ implementation due to not having support for accelerated path rendering.
+ The geometry generation happens entirely on the CPU in this case, and this
+ is potentially expensive. Changing the set of path elements, changing the
+ properties of these elements, or changing certain properties of the
+ PathItem itself all lead to retriangulation on every change. Therefore,
+ applying animation to such properties can heavily affect performance on
+ less powerful systems. If animating properties other than stroke and fill
+ colors is a must, it is recommended to target systems providing
+ \c{GL_NV_path_rendering} where the cost of path property changes is much
+ smaller.
+
+ \note The types for specifying path elements are shared between PathView
+ and PathItem. However, not all PathItem implementations support all path
+ element types, while some may not make sense for PathView. PathItem's
+ currently supported subset is: PathMove, PathLine, PathQuad, PathCubic,
+ PathArc.
+
+ \sa Path, PathMove, PathLine, PathQuad, PathCubic, PathArc
+*/
+
+QQuickPathItem::QQuickPathItem(QQuickItem *parent)
+ : QQuickItem(*(new QQuickPathItemPrivate), parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QQuickPathItem::~QQuickPathItem()
+{
+}
+
+QQuickPathItem::RendererType QQuickPathItem::rendererType() const
+{
+ Q_D(const QQuickPathItem);
+ return d->rendererType;
+}
+
+/*!
+ \qmlproperty Path QtQuick::PathItem::path
+ This property holds the path to be rendered.
+ For more information see the \l Path documentation.
+*/
+QQuickPath *QQuickPathItem::path() const
+{
+ Q_D(const QQuickPathItem);
+ return d->path;
+}
+
+void QQuickPathItem::setPath(QQuickPath *path)
+{
+ Q_D(QQuickPathItem);
+ if (d->path == path)
+ return;
+
+ if (d->path)
+ qmlobject_disconnect(d->path, QQuickPath, SIGNAL(changed()),
+ this, QQuickPathItem, SLOT(_q_pathChanged()));
+ d->path = path;
+ qmlobject_connect(d->path, QQuickPath, SIGNAL(changed()),
+ this, QQuickPathItem, SLOT(_q_pathChanged()));
+
+ d->dirty |= QQuickPathItemPrivate::DirtyPath;
+ emit pathChanged();
+ polish();
+}
+
+void QQuickPathItemPrivate::_q_pathChanged()
+{
+ Q_Q(QQuickPathItem);
+ dirty |= DirtyPath;
+ q->polish();
+}
+
+QColor QQuickPathItem::strokeColor() const
+{
+ Q_D(const QQuickPathItem);
+ return d->strokeColor;
+}
+
+void QQuickPathItem::setStrokeColor(const QColor &color)
+{
+ Q_D(QQuickPathItem);
+ if (d->strokeColor != color) {
+ d->strokeColor = color;
+ d->dirty |= QQuickPathItemPrivate::DirtyStrokeColor;
+ emit strokeColorChanged();
+ polish();
+ }
+}
+
+qreal QQuickPathItem::strokeWidth() const
+{
+ Q_D(const QQuickPathItem);
+ return d->strokeWidth;
+}
+
+void QQuickPathItem::setStrokeWidth(qreal w)
+{
+ Q_D(QQuickPathItem);
+ if (d->strokeWidth != w) {
+ d->strokeWidth = w;
+ d->dirty |= QQuickPathItemPrivate::DirtyStrokeWidth;
+ emit strokeWidthChanged();
+ polish();
+ }
+}
+
+QColor QQuickPathItem::fillColor() const
+{
+ Q_D(const QQuickPathItem);
+ return d->fillColor;
+}
+
+void QQuickPathItem::setFillColor(const QColor &color)
+{
+ Q_D(QQuickPathItem);
+ if (d->fillColor != color) {
+ d->fillColor = color;
+ d->dirty |= QQuickPathItemPrivate::DirtyFillColor;
+ emit fillColorChanged();
+ polish();
+ }
+}
+
+QQuickPathItem::FillRule QQuickPathItem::fillRule() const
+{
+ Q_D(const QQuickPathItem);
+ return d->fillRule;
+}
+
+void QQuickPathItem::setFillRule(FillRule fillRule)
+{
+ Q_D(QQuickPathItem);
+ if (d->fillRule != fillRule) {
+ d->fillRule = fillRule;
+ d->dirty |= QQuickPathItemPrivate::DirtyFillRule;
+ emit fillRuleChanged();
+ polish();
+ }
+}
+
+QQuickPathItem::JoinStyle QQuickPathItem::joinStyle() const
+{
+ Q_D(const QQuickPathItem);
+ return d->joinStyle;
+}
+
+void QQuickPathItem::setJoinStyle(JoinStyle style)
+{
+ Q_D(QQuickPathItem);
+ if (d->joinStyle != style) {
+ d->joinStyle = style;
+ d->dirty |= QQuickPathItemPrivate::DirtyStyle;
+ emit joinStyleChanged();
+ polish();
+ }
+}
+
+int QQuickPathItem::miterLimit() const
+{
+ Q_D(const QQuickPathItem);
+ return d->miterLimit;
+}
+
+void QQuickPathItem::setMiterLimit(int limit)
+{
+ Q_D(QQuickPathItem);
+ if (d->miterLimit != limit) {
+ d->miterLimit = limit;
+ d->dirty |= QQuickPathItemPrivate::DirtyStyle;
+ emit miterLimitChanged();
+ polish();
+ }
+}
+
+QQuickPathItem::CapStyle QQuickPathItem::capStyle() const
+{
+ Q_D(const QQuickPathItem);
+ return d->capStyle;
+}
+
+void QQuickPathItem::setCapStyle(CapStyle style)
+{
+ Q_D(QQuickPathItem);
+ if (d->capStyle != style) {
+ d->capStyle = style;
+ d->dirty |= QQuickPathItemPrivate::DirtyStyle;
+ emit capStyleChanged();
+ polish();
+ }
+}
+
+QQuickPathItem::StrokeStyle QQuickPathItem::strokeStyle() const
+{
+ Q_D(const QQuickPathItem);
+ return d->strokeStyle;
+}
+
+void QQuickPathItem::setStrokeStyle(StrokeStyle style)
+{
+ Q_D(QQuickPathItem);
+ if (d->strokeStyle != style) {
+ d->strokeStyle = style;
+ d->dirty |= QQuickPathItemPrivate::DirtyDash;
+ emit strokeStyleChanged();
+ polish();
+ }
+}
+
+qreal QQuickPathItem::dashOffset() const
+{
+ Q_D(const QQuickPathItem);
+ return d->dashOffset;
+}
+
+void QQuickPathItem::setDashOffset(qreal offset)
+{
+ Q_D(QQuickPathItem);
+ if (d->dashOffset != offset) {
+ d->dashOffset = offset;
+ d->dirty |= QQuickPathItemPrivate::DirtyDash;
+ emit dashOffsetChanged();
+ polish();
+ }
+}
+
+QVector<qreal> QQuickPathItem::dashPattern() const
+{
+ Q_D(const QQuickPathItem);
+ return d->dashPattern;
+}
+
+void QQuickPathItem::setDashPattern(const QVector<qreal> &array)
+{
+ Q_D(QQuickPathItem);
+ if (d->dashPattern != array) {
+ d->dashPattern = array;
+ d->dirty |= QQuickPathItemPrivate::DirtyDash;
+ emit dashPatternChanged();
+ polish();
+ }
+}
+
+QQuickPathGradient *QQuickPathItem::fillGradient() const
+{
+ Q_D(const QQuickPathItem);
+ return d->fillGradient;
+}
+
+void QQuickPathItem::setFillGradient(QQuickPathGradient *gradient)
+{
+ Q_D(QQuickPathItem);
+ if (d->fillGradient != gradient) {
+ if (d->fillGradient)
+ qmlobject_disconnect(d->fillGradient, QQuickPathGradient, SIGNAL(updated()),
+ this, QQuickPathItem, SLOT(_q_fillGradientChanged()));
+ d->fillGradient = gradient;
+ if (d->fillGradient)
+ qmlobject_connect(d->fillGradient, QQuickPathGradient, SIGNAL(updated()),
+ this, QQuickPathItem, SLOT(_q_fillGradientChanged()));
+ d->dirty |= QQuickPathItemPrivate::DirtyFillGradient;
+ polish();
+ }
+}
+
+void QQuickPathItemPrivate::_q_fillGradientChanged()
+{
+ Q_Q(QQuickPathItem);
+ dirty |= DirtyFillGradient;
+ q->polish();
+}
+
+void QQuickPathItem::resetFillGradient()
+{
+ setFillGradient(nullptr);
+}
+
+void QQuickPathItem::updatePolish()
+{
+ Q_D(QQuickPathItem);
+
+ if (!d->dirty)
+ return;
+
+ if (!d->renderer) {
+ d->createRenderer();
+ if (!d->renderer)
+ return;
+ emit rendererChanged();
+ }
+
+ // endSync() is where expensive calculations may happen, depending on the
+ // backend. Therefore do this only when the item is visible.
+ if (isVisible())
+ d->sync();
+
+ update();
+}
+
+void QQuickPathItem::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ // sync may have been deferred; do it now if the item became visible
+ if (change == ItemVisibleHasChanged && data.boolValue)
+ polish();
+
+ QQuickItem::itemChange(change, data);
+}
+
+QSGNode *QQuickPathItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
+{
+ // Called on the render thread, with the gui thread blocked. We can now
+ // safely access gui thread data.
+
+ Q_D(QQuickPathItem);
+ if (d->renderer) {
+ if (!node)
+ node = d->createRenderNode();
+ d->renderer->updatePathRenderNode();
+ }
+ return node;
+}
+
+// the renderer object lives on the gui thread
+void QQuickPathItemPrivate::createRenderer()
+{
+ Q_Q(QQuickPathItem);
+ QSGRendererInterface *ri = q->window()->rendererInterface();
+ if (!ri)
+ return;
+
+ switch (ri->graphicsApi()) {
+#ifndef QT_NO_OPENGL
+ case QSGRendererInterface::OpenGL:
+ if (QQuickPathItemNvprRenderNode::isSupported()) {
+ rendererType = QQuickPathItem::NvprRenderer;
+ renderer = new QQuickPathItemNvprRenderer;
+ } else {
+ rendererType = QQuickPathItem::GeometryRenderer;
+ renderer = new QQuickPathItemGenericRenderer(q);
+ }
+ break;
+#endif
+ case QSGRendererInterface::Software:
+ rendererType = QQuickPathItem::SoftwareRenderer;
+ renderer = new QQuickPathItemSoftwareRenderer;
+ break;
+ default:
+ qWarning("No path backend for this graphics API yet");
+ break;
+ }
+}
+
+// the node lives on the render thread
+QSGNode *QQuickPathItemPrivate::createRenderNode()
+{
+ Q_Q(QQuickPathItem);
+ QSGNode *node = nullptr;
+ if (!q->window())
+ return node;
+ QSGRendererInterface *ri = q->window()->rendererInterface();
+ if (!ri)
+ return node;
+
+ const bool hasFill = fillColor != Qt::transparent;
+ const bool hasStroke = !qFuzzyIsNull(strokeWidth) && strokeColor != Qt::transparent;
+
+ switch (ri->graphicsApi()) {
+#ifndef QT_NO_OPENGL
+ case QSGRendererInterface::OpenGL:
+ if (QQuickPathItemNvprRenderNode::isSupported()) {
+ node = new QQuickPathItemNvprRenderNode(q);
+ static_cast<QQuickPathItemNvprRenderer *>(renderer)->setNode(
+ static_cast<QQuickPathItemNvprRenderNode *>(node));
+ } else {
+ node = new QQuickPathItemGenericRootRenderNode(q->window(), hasFill, hasStroke);
+ static_cast<QQuickPathItemGenericRenderer *>(renderer)->setRootNode(
+ static_cast<QQuickPathItemGenericRootRenderNode *>(node));
+ }
+ break;
+#endif
+ case QSGRendererInterface::Software:
+ node = new QQuickPathItemSoftwareRenderNode(q);
+ static_cast<QQuickPathItemSoftwareRenderer *>(renderer)->setNode(
+ static_cast<QQuickPathItemSoftwareRenderNode *>(node));
+ break;
+ default:
+ qWarning("No path backend for this graphics API yet");
+ break;
+ }
+
+ return node;
+}
+
+void QQuickPathItemPrivate::sync()
+{
+ renderer->beginSync();
+
+ if (dirty & QQuickPathItemPrivate::DirtyPath)
+ renderer->setPath(path);
+ if (dirty & DirtyStrokeColor)
+ renderer->setStrokeColor(strokeColor);
+ if (dirty & DirtyStrokeWidth)
+ renderer->setStrokeWidth(strokeWidth);
+ if (dirty & DirtyFillColor)
+ renderer->setFillColor(fillColor);
+ if (dirty & DirtyFillRule)
+ renderer->setFillRule(fillRule);
+ if (dirty & DirtyStyle) {
+ renderer->setJoinStyle(joinStyle, miterLimit);
+ renderer->setCapStyle(capStyle);
+ }
+ if (dirty & DirtyDash)
+ renderer->setStrokeStyle(strokeStyle, dashOffset, dashPattern);
+ if (dirty & DirtyFillGradient)
+ renderer->setFillGradient(fillGradient);
+
+ renderer->endSync();
+ dirty = 0;
+}
+
+// ***** gradient support *****
+
+QQuickPathGradientStop::QQuickPathGradientStop(QObject *parent)
+ : QObject(parent),
+ m_position(0),
+ m_color(Qt::black)
+{
+}
+
+qreal QQuickPathGradientStop::position() const
+{
+ return m_position;
+}
+
+void QQuickPathGradientStop::setPosition(qreal position)
+{
+ if (m_position != position) {
+ m_position = position;
+ if (QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(parent()))
+ emit grad->updated();
+ }
+}
+
+QColor QQuickPathGradientStop::color() const
+{
+ return m_color;
+}
+
+void QQuickPathGradientStop::setColor(const QColor &color)
+{
+ if (m_color != color) {
+ m_color = color;
+ if (QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(parent()))
+ emit grad->updated();
+ }
+}
+
+QQuickPathGradient::QQuickPathGradient(QObject *parent)
+ : QObject(parent),
+ m_spread(PadSpread)
+{
+}
+
+void QQuickPathGradient::appendStop(QQmlListProperty<QObject> *list, QObject *stop)
+{
+ QQuickPathGradientStop *sstop = qobject_cast<QQuickPathGradientStop *>(stop);
+ if (!sstop) {
+ qWarning("Gradient stop list only supports QQuickPathGradientStop elements");
+ return;
+ }
+ QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(list->object);
+ Q_ASSERT(grad);
+ sstop->setParent(grad);
+ grad->m_stops.append(sstop);
+}
+
+QQmlListProperty<QObject> QQuickPathGradient::stops()
+{
+ return QQmlListProperty<QObject>(this, nullptr, &QQuickPathGradient::appendStop, nullptr, nullptr, nullptr);
+}
+
+QGradientStops QQuickPathGradient::sortedGradientStops() const
+{
+ QGradientStops result;
+ for (int i = 0; i < m_stops.count(); ++i) {
+ QQuickPathGradientStop *s = static_cast<QQuickPathGradientStop *>(m_stops[i]);
+ int j = 0;
+ while (j < result.count() && result[j].first < s->position())
+ ++j;
+ result.insert(j, QGradientStop(s->position(), s->color()));
+ }
+ return result;
+}
+
+QQuickPathGradient::SpreadMode QQuickPathGradient::spread() const
+{
+ return m_spread;
+}
+
+void QQuickPathGradient::setSpread(SpreadMode mode)
+{
+ if (m_spread != mode) {
+ m_spread = mode;
+ emit spreadChanged();
+ emit updated();
+ }
+}
+
+QQuickPathLinearGradient::QQuickPathLinearGradient(QObject *parent)
+ : QQuickPathGradient(parent)
+{
+}
+
+qreal QQuickPathLinearGradient::x1() const
+{
+ return m_start.x();
+}
+
+void QQuickPathLinearGradient::setX1(qreal v)
+{
+ if (m_start.x() != v) {
+ m_start.setX(v);
+ emit x1Changed();
+ emit updated();
+ }
+}
+
+qreal QQuickPathLinearGradient::y1() const
+{
+ return m_start.y();
+}
+
+void QQuickPathLinearGradient::setY1(qreal v)
+{
+ if (m_start.y() != v) {
+ m_start.setY(v);
+ emit y1Changed();
+ emit updated();
+ }
+}
+
+qreal QQuickPathLinearGradient::x2() const
+{
+ return m_end.x();
+}
+
+void QQuickPathLinearGradient::setX2(qreal v)
+{
+ if (m_end.x() != v) {
+ m_end.setX(v);
+ emit x2Changed();
+ emit updated();
+ }
+}
+
+qreal QQuickPathLinearGradient::y2() const
+{
+ return m_end.y();
+}
+
+void QQuickPathLinearGradient::setY2(qreal v)
+{
+ if (m_end.y() != v) {
+ m_end.setY(v);
+ emit y2Changed();
+ emit updated();
+ }
+}
+
+#ifndef QT_NO_OPENGL
+
+// contexts sharing with each other get the same cache instance
+class QQuickPathItemGradientCacheWrapper
+{
+public:
+ QQuickPathItemGradientCache *get(QOpenGLContext *context)
+ {
+ return m_resource.value<QQuickPathItemGradientCache>(context);
+ }
+
+private:
+ QOpenGLMultiGroupSharedResource m_resource;
+};
+
+QQuickPathItemGradientCache *QQuickPathItemGradientCache::currentCache()
+{
+ static QQuickPathItemGradientCacheWrapper qt_path_gradient_caches;
+ return qt_path_gradient_caches.get(QOpenGLContext::currentContext());
+}
+
+// let QOpenGLContext manage the lifetime of the cached textures
+QQuickPathItemGradientCache::~QQuickPathItemGradientCache()
+{
+ m_cache.clear();
+}
+
+void QQuickPathItemGradientCache::invalidateResource()
+{
+ m_cache.clear();
+}
+
+void QQuickPathItemGradientCache::freeResource(QOpenGLContext *)
+{
+ qDeleteAll(m_cache);
+ m_cache.clear();
+}
+
+static void generateGradientColorTable(const QQuickPathItemGradientCache::GradientDesc &gradient,
+ uint *colorTable, int size, float opacity)
+{
+ int pos = 0;
+ const QGradientStops &s = gradient.stops;
+ const bool colorInterpolation = true;
+
+ uint alpha = qRound(opacity * 256);
+ uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha);
+ qreal incr = 1.0 / qreal(size);
+ qreal fpos = 1.5 * incr;
+ colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color));
+
+ while (fpos <= s.first().first) {
+ colorTable[pos] = colorTable[pos - 1];
+ pos++;
+ fpos += incr;
+ }
+
+ if (colorInterpolation)
+ current_color = qPremultiply(current_color);
+
+ const int sLast = s.size() - 1;
+ for (int i = 0; i < sLast; ++i) {
+ qreal delta = 1/(s[i+1].first - s[i].first);
+ uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha);
+ if (colorInterpolation)
+ next_color = qPremultiply(next_color);
+
+ while (fpos < s[i+1].first && pos < size) {
+ int dist = int(256 * ((fpos - s[i].first) * delta));
+ int idist = 256 - dist;
+ if (colorInterpolation)
+ colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
+ else
+ colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
+ ++pos;
+ fpos += incr;
+ }
+ current_color = next_color;
+ }
+
+ Q_ASSERT(s.size() > 0);
+
+ uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
+ for ( ; pos < size; ++pos)
+ colorTable[pos] = last_color;
+
+ colorTable[size-1] = last_color;
+}
+
+QSGTexture *QQuickPathItemGradientCache::get(const GradientDesc &grad)
+{
+ QSGPlainTexture *tx = m_cache[grad];
+ if (!tx) {
+ QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
+ GLuint id;
+ f->glGenTextures(1, &id);
+ f->glBindTexture(GL_TEXTURE_2D, id);
+ static const uint W = 1024; // texture size is 1024x1
+ uint buf[W];
+ generateGradientColorTable(grad, buf, W, 1.0f);
+ f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, W, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
+ tx = new QSGPlainTexture;
+ tx->setTextureId(id);
+ switch (grad.spread) {
+ case QQuickPathGradient::PadSpread:
+ tx->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+ tx->setVerticalWrapMode(QSGTexture::ClampToEdge);
+ break;
+ case QQuickPathGradient::RepeatSpread:
+ tx->setHorizontalWrapMode(QSGTexture::Repeat);
+ tx->setVerticalWrapMode(QSGTexture::Repeat);
+ break;
+ case QQuickPathGradient::ReflectSpread:
+ tx->setHorizontalWrapMode(QSGTexture::MirroredRepeat);
+ tx->setVerticalWrapMode(QSGTexture::MirroredRepeat);
+ break;
+ default:
+ qWarning("Unknown gradient spread mode %d", grad.spread);
+ break;
+ }
+ m_cache[grad] = tx;
+ }
+ return tx;
+}
+
+#endif // QT_NO_OPENGL
+
+QT_END_NAMESPACE
+
+#include "moc_qquickpathitem_p.cpp"
diff --git a/src/quick/items/qquickpathitem_p.h b/src/quick/items/qquickpathitem_p.h
new file mode 100644
index 0000000000..39b407cf87
--- /dev/null
+++ b/src/quick/items/qquickpathitem_p.h
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** 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 QQUICKPATHITEM_P_H
+#define QQUICKPATHITEM_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 "qquickitem.h"
+
+#include <private/qtquickglobal_p.h>
+#include <private/qquickpath_p.h>
+#include <QGradientStops>
+
+QT_REQUIRE_CONFIG(quick_path);
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPathItemPrivate;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPathGradientStop : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal position READ position WRITE setPosition)
+ Q_PROPERTY(QColor color READ color WRITE setColor)
+
+public:
+ QQuickPathGradientStop(QObject *parent = nullptr);
+
+ qreal position() const;
+ void setPosition(qreal position);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+private:
+ qreal m_position;
+ QColor m_color;
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPathGradient : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<QObject> stops READ stops)
+ Q_PROPERTY(SpreadMode spread READ spread WRITE setSpread NOTIFY spreadChanged)
+ Q_CLASSINFO("DefaultProperty", "stops")
+
+public:
+ enum SpreadMode {
+ PadSpread,
+ RepeatSpread,
+ ReflectSpread
+ };
+ Q_ENUM(SpreadMode)
+
+ QQuickPathGradient(QObject *parent = nullptr);
+
+ QQmlListProperty<QObject> stops();
+
+ QGradientStops sortedGradientStops() const;
+
+ SpreadMode spread() const;
+ void setSpread(SpreadMode mode);
+
+signals:
+ void updated();
+ void spreadChanged();
+
+private:
+ static void appendStop(QQmlListProperty<QObject> *list, QObject *stop);
+
+ QVector<QObject *> m_stops;
+ SpreadMode m_spread;
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPathLinearGradient : public QQuickPathGradient
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal x1 READ x1 WRITE setX1 NOTIFY x1Changed)
+ Q_PROPERTY(qreal y1 READ y1 WRITE setY1 NOTIFY y1Changed)
+ Q_PROPERTY(qreal x2 READ x2 WRITE setX2 NOTIFY x2Changed)
+ Q_PROPERTY(qreal y2 READ y2 WRITE setY2 NOTIFY y2Changed)
+ Q_CLASSINFO("DefaultProperty", "stops")
+
+public:
+ QQuickPathLinearGradient(QObject *parent = nullptr);
+
+ qreal x1() const;
+ void setX1(qreal v);
+ qreal y1() const;
+ void setY1(qreal v);
+ qreal x2() const;
+ void setX2(qreal v);
+ qreal y2() const;
+ void setY2(qreal v);
+
+signals:
+ void x1Changed();
+ void y1Changed();
+ void x2Changed();
+ void y2Changed();
+
+private:
+ QPointF m_start;
+ QPointF m_end;
+};
+
+class Q_QUICK_PRIVATE_EXPORT QQuickPathItem : public QQuickItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(RendererType renderer READ rendererType NOTIFY rendererChanged)
+
+ Q_PROPERTY(QQuickPath *path READ path WRITE setPath NOTIFY pathChanged)
+
+ Q_PROPERTY(QColor strokeColor READ strokeColor WRITE setStrokeColor NOTIFY strokeColorChanged)
+ Q_PROPERTY(qreal strokeWidth READ strokeWidth WRITE setStrokeWidth NOTIFY strokeWidthChanged)
+ Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor NOTIFY fillColorChanged)
+ Q_PROPERTY(FillRule fillRule READ fillRule WRITE setFillRule NOTIFY fillRuleChanged)
+ Q_PROPERTY(JoinStyle joinStyle READ joinStyle WRITE setJoinStyle NOTIFY joinStyleChanged)
+ Q_PROPERTY(int miterLimit READ miterLimit WRITE setMiterLimit NOTIFY miterLimitChanged)
+ Q_PROPERTY(CapStyle capStyle READ capStyle WRITE setCapStyle NOTIFY capStyleChanged)
+ Q_PROPERTY(StrokeStyle strokeStyle READ strokeStyle WRITE setStrokeStyle NOTIFY strokeStyleChanged)
+ Q_PROPERTY(qreal dashOffset READ dashOffset WRITE setDashOffset NOTIFY dashOffsetChanged)
+ Q_PROPERTY(QVector<qreal> dashPattern READ dashPattern WRITE setDashPattern NOTIFY dashPatternChanged)
+ Q_PROPERTY(QQuickPathGradient *fillGradient READ fillGradient WRITE setFillGradient RESET resetFillGradient)
+
+public:
+ enum FillRule {
+ OddEvenFill = Qt::OddEvenFill,
+ WindingFill = Qt::WindingFill
+ };
+ Q_ENUM(FillRule)
+
+ enum JoinStyle {
+ MiterJoin = Qt::MiterJoin,
+ BevelJoin = Qt::BevelJoin,
+ RoundJoin = Qt::RoundJoin
+ };
+ Q_ENUM(JoinStyle)
+
+ enum CapStyle {
+ FlatCap = Qt::FlatCap,
+ SquareCap = Qt::SquareCap,
+ RoundCap = Qt::RoundCap
+ };
+ Q_ENUM(CapStyle)
+
+ enum StrokeStyle {
+ SolidLine = Qt::SolidLine,
+ DashLine = Qt::DashLine
+ };
+ Q_ENUM(StrokeStyle)
+
+ enum RendererType {
+ UnknownRenderer,
+ GeometryRenderer,
+ NvprRenderer,
+ SoftwareRenderer
+ };
+ Q_ENUM(RendererType)
+
+ QQuickPathItem(QQuickItem *parent = nullptr);
+ ~QQuickPathItem();
+
+ RendererType rendererType() const;
+
+ QQuickPath *path() const;
+ void setPath(QQuickPath *path);
+
+ QColor strokeColor() const;
+ void setStrokeColor(const QColor &color);
+
+ qreal strokeWidth() const;
+ void setStrokeWidth(qreal w);
+
+ QColor fillColor() const;
+ void setFillColor(const QColor &color);
+
+ FillRule fillRule() const;
+ void setFillRule(FillRule fillRule);
+
+ JoinStyle joinStyle() const;
+ void setJoinStyle(JoinStyle style);
+
+ int miterLimit() const;
+ void setMiterLimit(int limit);
+
+ CapStyle capStyle() const;
+ void setCapStyle(CapStyle style);
+
+ StrokeStyle strokeStyle() const;
+ void setStrokeStyle(StrokeStyle style);
+
+ qreal dashOffset() const;
+ void setDashOffset(qreal offset);
+
+ QVector<qreal> dashPattern() const;
+ void setDashPattern(const QVector<qreal> &array);
+
+ QQuickPathGradient *fillGradient() const;
+ void setFillGradient(QQuickPathGradient *gradient);
+ void resetFillGradient();
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override;
+ void updatePolish() override;
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+
+Q_SIGNALS:
+ void rendererChanged();
+ void pathChanged();
+ void strokeColorChanged();
+ void strokeWidthChanged();
+ void fillColorChanged();
+ void fillRuleChanged();
+ void joinStyleChanged();
+ void miterLimitChanged();
+ void capStyleChanged();
+ void strokeStyleChanged();
+ void dashOffsetChanged();
+ void dashPatternChanged();
+ void fillGradientChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickPathItem)
+ Q_DECLARE_PRIVATE(QQuickPathItem)
+ Q_PRIVATE_SLOT(d_func(), void _q_pathChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_fillGradientChanged())
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPathItem)
+
+#endif // QQUICKPATHITEM_P_H
diff --git a/src/quick/items/qquickpathitem_p_p.h b/src/quick/items/qquickpathitem_p_p.h
new file mode 100644
index 0000000000..366628d867
--- /dev/null
+++ b/src/quick/items/qquickpathitem_p_p.h
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** 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 QQUICKPATHITEM_P_P_H
+#define QQUICKPATHITEM_P_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 "qquickpathitem_p.h"
+#include "qquickitem_p.h"
+#include <QPainterPath>
+#include <QColor>
+#include <QBrush>
+#include <private/qopenglcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGPlainTexture;
+
+class QQuickAbstractPathRenderer
+{
+public:
+ virtual ~QQuickAbstractPathRenderer() { }
+
+ // Gui thread
+ virtual void beginSync() = 0;
+ virtual void setPath(const QQuickPath *path) = 0;
+ virtual void setStrokeColor(const QColor &color) = 0;
+ virtual void setStrokeWidth(qreal w) = 0;
+ virtual void setFillColor(const QColor &color) = 0;
+ virtual void setFillRule(QQuickPathItem::FillRule fillRule) = 0;
+ virtual void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) = 0;
+ virtual void setCapStyle(QQuickPathItem::CapStyle capStyle) = 0;
+ virtual void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern) = 0;
+ virtual void setFillGradient(QQuickPathGradient *gradient) = 0;
+ virtual void endSync() = 0;
+
+ // Render thread, with gui blocked
+ virtual void updatePathRenderNode() = 0;
+};
+
+class QQuickPathItemPrivate : public QQuickItemPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPathItem)
+
+public:
+ enum Dirty {
+ DirtyPath = 0x01,
+ DirtyStrokeColor = 0x02,
+ DirtyStrokeWidth = 0x04,
+ DirtyFillColor = 0x08,
+ DirtyFillRule = 0x10,
+ DirtyStyle = 0x20,
+ DirtyDash = 0x40,
+ DirtyFillGradient = 0x80,
+
+ DirtyAll = 0xFF
+ };
+
+ QQuickPathItemPrivate();
+ ~QQuickPathItemPrivate();
+
+ void createRenderer();
+ QSGNode *createRenderNode();
+ void sync();
+
+ void _q_pathChanged();
+ void _q_fillGradientChanged();
+
+ QQuickPathItem::RendererType rendererType;
+ QQuickAbstractPathRenderer *renderer;
+ QQuickPath *path;
+ int dirty;
+ QColor strokeColor;
+ qreal strokeWidth;
+ QColor fillColor;
+ QQuickPathItem::FillRule fillRule;
+ QQuickPathItem::JoinStyle joinStyle;
+ int miterLimit;
+ QQuickPathItem::CapStyle capStyle;
+ QQuickPathItem::StrokeStyle strokeStyle;
+ qreal dashOffset;
+ QVector<qreal> dashPattern;
+ QQuickPathGradient *fillGradient;
+};
+
+#ifndef QT_NO_OPENGL
+
+class QQuickPathItemGradientCache : public QOpenGLSharedResource
+{
+public:
+ struct GradientDesc {
+ QGradientStops stops;
+ QPointF start;
+ QPointF end;
+ QQuickPathGradient::SpreadMode spread;
+ bool operator==(const GradientDesc &other) const
+ {
+ return start == other.start && end == other.end && spread == other.spread
+ && stops == other.stops;
+ }
+ };
+
+ QQuickPathItemGradientCache(QOpenGLContext *context) : QOpenGLSharedResource(context->shareGroup()) { }
+ ~QQuickPathItemGradientCache();
+
+ void invalidateResource() override;
+ void freeResource(QOpenGLContext *) override;
+
+ QSGTexture *get(const GradientDesc &grad);
+
+ static QQuickPathItemGradientCache *currentCache();
+
+private:
+ QHash<GradientDesc, QSGPlainTexture *> m_cache;
+};
+
+inline uint qHash(const QQuickPathItemGradientCache::GradientDesc &v, uint seed = 0)
+{
+ uint h = seed;
+ h += v.start.x() + v.end.y() + v.spread;
+ for (int i = 0; i < 3 && i < v.stops.count(); ++i)
+ h += v.stops[i].second.rgba();
+ return h;
+}
+
+#endif // QT_NO_OPENGL
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quick/items/qquickpathitemgenericrenderer.cpp b/src/quick/items/qquickpathitemgenericrenderer.cpp
new file mode 100644
index 0000000000..9bd03c0e51
--- /dev/null
+++ b/src/quick/items/qquickpathitemgenericrenderer.cpp
@@ -0,0 +1,510 @@
+/****************************************************************************
+**
+** 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 "qquickpathitemgenericrenderer_p.h"
+#include <QtGui/private/qtriangulator_p.h>
+#include <QSGVertexColorMaterial>
+
+QT_BEGIN_NAMESPACE
+
+static const qreal SCALE = 100;
+
+struct ColoredVertex // must match QSGGeometry::ColoredPoint2D
+{
+ float x, y;
+ QQuickPathItemGenericRenderer::Color4ub color;
+ void set(float nx, float ny, QQuickPathItemGenericRenderer::Color4ub ncolor)
+ {
+ x = nx; y = ny; color = ncolor;
+ }
+};
+
+static inline QQuickPathItemGenericRenderer::Color4ub colorToColor4ub(const QColor &c)
+{
+ QQuickPathItemGenericRenderer::Color4ub color = {
+ uchar(qRound(c.redF() * c.alphaF() * 255)),
+ uchar(qRound(c.greenF() * c.alphaF() * 255)),
+ uchar(qRound(c.blueF() * c.alphaF() * 255)),
+ uchar(qRound(c.alphaF() * 255))
+ };
+ return color;
+}
+
+QQuickPathItemGenericRootRenderNode::QQuickPathItemGenericRootRenderNode(QQuickWindow *window,
+ bool hasFill,
+ bool hasStroke)
+ : m_fillNode(nullptr),
+ m_strokeNode(nullptr)
+{
+ if (hasFill) {
+ m_fillNode = new QQuickPathItemGenericRenderNode(window, this);
+ appendChildNode(m_fillNode);
+ }
+ if (hasStroke) {
+ m_strokeNode = new QQuickPathItemGenericRenderNode(window, this);
+ appendChildNode(m_strokeNode);
+ }
+}
+
+QQuickPathItemGenericRootRenderNode::~QQuickPathItemGenericRootRenderNode()
+{
+}
+
+QQuickPathItemGenericRenderNode::QQuickPathItemGenericRenderNode(QQuickWindow *window,
+ QQuickPathItemGenericRootRenderNode *rootNode)
+ : m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0),
+ m_window(window),
+ m_rootNode(rootNode),
+ m_material(nullptr)
+{
+ setGeometry(&m_geometry);
+ activateMaterial(MatSolidColor);
+}
+
+QQuickPathItemGenericRenderNode::~QQuickPathItemGenericRenderNode()
+{
+}
+
+void QQuickPathItemGenericRenderNode::activateMaterial(Material m)
+{
+ switch (m) {
+ case MatSolidColor:
+ // Use vertexcolor material. Items with different colors remain batchable
+ // this way, at the expense of having to provide per-vertex color values.
+ if (!m_solidColorMaterial)
+ m_solidColorMaterial.reset(QQuickPathItemGenericMaterialFactory::createVertexColor(m_window));
+ m_material = m_solidColorMaterial.data();
+ break;
+ case MatLinearGradient:
+ if (!m_linearGradientMaterial)
+ m_linearGradientMaterial.reset(QQuickPathItemGenericMaterialFactory::createLinearGradient(m_window, this));
+ m_material = m_linearGradientMaterial.data();
+ break;
+ default:
+ qWarning("Unknown material %d", m);
+ return;
+ }
+
+ if (material() != m_material)
+ setMaterial(m_material);
+}
+
+// sync, and so triangulation too, happens on the gui thread
+void QQuickPathItemGenericRenderer::beginSync()
+{
+ m_syncDirty = 0;
+}
+
+void QQuickPathItemGenericRenderer::setPath(const QQuickPath *path)
+{
+ m_path = path ? path->path() : QPainterPath();
+ m_syncDirty |= DirtyGeom;
+}
+
+void QQuickPathItemGenericRenderer::setStrokeColor(const QColor &color)
+{
+ m_strokeColor = colorToColor4ub(color);
+ m_syncDirty |= DirtyColor;
+}
+
+void QQuickPathItemGenericRenderer::setStrokeWidth(qreal w)
+{
+ m_pen.setWidthF(w);
+ m_syncDirty |= DirtyGeom;
+}
+
+void QQuickPathItemGenericRenderer::setFillColor(const QColor &color)
+{
+ m_fillColor = colorToColor4ub(color);
+ m_syncDirty |= DirtyColor;
+}
+
+void QQuickPathItemGenericRenderer::setFillRule(QQuickPathItem::FillRule fillRule)
+{
+ m_fillRule = Qt::FillRule(fillRule);
+ m_syncDirty |= DirtyGeom;
+}
+
+void QQuickPathItemGenericRenderer::setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit)
+{
+ m_pen.setJoinStyle(Qt::PenJoinStyle(joinStyle));
+ m_pen.setMiterLimit(miterLimit);
+ m_syncDirty |= DirtyGeom;
+}
+
+void QQuickPathItemGenericRenderer::setCapStyle(QQuickPathItem::CapStyle capStyle)
+{
+ m_pen.setCapStyle(Qt::PenCapStyle(capStyle));
+ m_syncDirty |= DirtyGeom;
+}
+
+void QQuickPathItemGenericRenderer::setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern)
+{
+ m_pen.setStyle(Qt::PenStyle(strokeStyle));
+ if (strokeStyle == QQuickPathItem::DashLine) {
+ m_pen.setDashPattern(dashPattern);
+ m_pen.setDashOffset(dashOffset);
+ }
+ m_syncDirty |= DirtyGeom;
+}
+
+void QQuickPathItemGenericRenderer::setFillGradient(QQuickPathGradient *gradient)
+{
+ m_fillGradientActive = gradient != nullptr;
+ if (gradient) {
+ m_fillGradient.stops = gradient->sortedGradientStops();
+ m_fillGradient.spread = gradient->spread();
+ if (QQuickPathLinearGradient *g = qobject_cast<QQuickPathLinearGradient *>(gradient)) {
+ m_fillGradient.start = QPointF(g->x1(), g->y1());
+ m_fillGradient.end = QPointF(g->x2(), g->y2());
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+ m_syncDirty |= DirtyFillGradient;
+}
+
+void QQuickPathItemGenericRenderer::endSync()
+{
+ if (!m_syncDirty)
+ return;
+
+ // Use a shadow dirty flag in order to avoid losing state in case there are
+ // multiple syncs with different dirty flags before we get to
+ // updatePathRenderNode() on the render thread (with the gui thread
+ // blocked). For our purposes here m_syncDirty is still required since
+ // geometry regeneration must only happen when there was an actual change
+ // in this particular sync round.
+ m_effectiveDirty |= m_syncDirty;
+
+ if (m_path.isEmpty()) {
+ m_fillVertices.clear();
+ m_fillIndices.clear();
+ m_strokeVertices.clear();
+ return;
+ }
+
+ triangulateFill();
+ triangulateStroke();
+}
+
+void QQuickPathItemGenericRenderer::triangulateFill()
+{
+ m_path.setFillRule(m_fillRule);
+
+ const QVectorPath &vp = qtVectorPathForPath(m_path);
+
+ QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(SCALE, SCALE));
+ const int vertexCount = ts.vertices.count() / 2; // just a qreal vector with x,y hence the / 2
+ m_fillVertices.resize(vertexCount);
+ ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(m_fillVertices.data());
+ const qreal *vsrc = ts.vertices.constData();
+ for (int i = 0; i < vertexCount; ++i)
+ vdst[i].set(vsrc[i * 2] / SCALE, vsrc[i * 2 + 1] / SCALE, m_fillColor);
+
+ m_fillIndices.resize(ts.indices.size());
+ quint16 *idst = m_fillIndices.data();
+ if (ts.indices.type() == QVertexIndexVector::UnsignedShort) {
+ memcpy(idst, ts.indices.data(), m_fillIndices.count() * sizeof(quint16));
+ } else {
+ const quint32 *isrc = (const quint32 *) ts.indices.data();
+ for (int i = 0; i < m_fillIndices.count(); ++i)
+ idst[i] = isrc[i];
+ }
+}
+
+void QQuickPathItemGenericRenderer::triangulateStroke()
+{
+ const QVectorPath &vp = qtVectorPathForPath(m_path);
+
+ const QRectF clip(0, 0, m_item->width(), m_item->height());
+ const qreal inverseScale = 1.0 / SCALE;
+ m_stroker.setInvScale(inverseScale);
+ if (m_pen.style() == Qt::SolidLine) {
+ m_stroker.process(vp, m_pen, clip, 0);
+ } else {
+ m_dashStroker.setInvScale(inverseScale);
+ m_dashStroker.process(vp, m_pen, clip, 0);
+ QVectorPath dashStroke(m_dashStroker.points(), m_dashStroker.elementCount(),
+ m_dashStroker.elementTypes(), 0);
+ m_stroker.process(dashStroke, m_pen, clip, 0);
+ }
+
+ if (!m_stroker.vertexCount()) {
+ m_strokeVertices.clear();
+ return;
+ }
+
+ const int vertexCount = m_stroker.vertexCount() / 2; // just a float vector with x,y hence the / 2
+ m_strokeVertices.resize(vertexCount);
+ ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(m_strokeVertices.data());
+ const float *vsrc = m_stroker.vertices();
+ for (int i = 0; i < vertexCount; ++i)
+ vdst[i].set(vsrc[i * 2], vsrc[i * 2 + 1], m_strokeColor);
+}
+
+void QQuickPathItemGenericRenderer::setRootNode(QQuickPathItemGenericRootRenderNode *rn)
+{
+ if (m_rootNode != rn) {
+ m_rootNode = rn;
+ // Scenegraph nodes can be destroyed and then replaced by new ones over
+ // time; hence it is important to mark everything dirty for
+ // updatePathRenderNode(). We can assume the renderer has a full sync
+ // of the data at this point.
+ m_effectiveDirty = DirtyAll;
+ }
+}
+
+// on the render thread with gui blocked
+void QQuickPathItemGenericRenderer::updatePathRenderNode()
+{
+ if (!m_effectiveDirty || !m_rootNode)
+ return;
+
+ if (m_fillColor.a == 0) {
+ delete m_rootNode->m_fillNode;
+ m_rootNode->m_fillNode = nullptr;
+ } else if (!m_rootNode->m_fillNode) {
+ m_rootNode->m_fillNode = new QQuickPathItemGenericRenderNode(m_item->window(), m_rootNode);
+ if (m_rootNode->m_strokeNode)
+ m_rootNode->removeChildNode(m_rootNode->m_strokeNode);
+ m_rootNode->appendChildNode(m_rootNode->m_fillNode);
+ if (m_rootNode->m_strokeNode)
+ m_rootNode->appendChildNode(m_rootNode->m_strokeNode);
+ m_effectiveDirty |= DirtyGeom;
+ }
+
+ if (qFuzzyIsNull(m_pen.widthF()) || m_strokeColor.a == 0) {
+ delete m_rootNode->m_strokeNode;
+ m_rootNode->m_strokeNode = nullptr;
+ } else if (!m_rootNode->m_strokeNode) {
+ m_rootNode->m_strokeNode = new QQuickPathItemGenericRenderNode(m_item->window(), m_rootNode);
+ m_rootNode->appendChildNode(m_rootNode->m_strokeNode);
+ m_effectiveDirty |= DirtyGeom;
+ }
+
+ updateFillNode();
+ updateStrokeNode();
+
+ m_effectiveDirty = 0;
+}
+
+void QQuickPathItemGenericRenderer::updateFillNode()
+{
+ if (!m_rootNode->m_fillNode)
+ return;
+
+ QQuickPathItemGenericRenderNode *n = m_rootNode->m_fillNode;
+ QSGGeometry *g = &n->m_geometry;
+ if (m_fillVertices.isEmpty()) {
+ g->allocate(0, 0);
+ n->markDirty(QSGNode::DirtyGeometry);
+ return;
+ }
+
+ if (m_fillGradientActive) {
+ n->activateMaterial(QQuickPathItemGenericRenderNode::MatLinearGradient);
+ if (m_effectiveDirty & DirtyFillGradient) {
+ // Make a copy of the data that will be accessed by the material on
+ // the render thread.
+ n->m_fillGradient = m_fillGradient;
+ // Gradients are implemented via a texture-based material.
+ n->markDirty(QSGNode::DirtyMaterial);
+ // stop here if only the gradient changed; no need to touch the geometry
+ if (!(m_effectiveDirty & DirtyGeom))
+ return;
+ }
+ } else {
+ n->activateMaterial(QQuickPathItemGenericRenderNode::MatSolidColor);
+ // fast path for updating only color values when no change in vertex positions
+ if ((m_effectiveDirty & DirtyColor) && !(m_effectiveDirty & DirtyGeom)) {
+ ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
+ for (int i = 0; i < g->vertexCount(); ++i)
+ vdst[i].set(vdst[i].x, vdst[i].y, m_fillColor);
+ n->markDirty(QSGNode::DirtyGeometry);
+ return;
+ }
+ }
+
+ g->allocate(m_fillVertices.count(), m_fillIndices.count());
+ g->setDrawingMode(QSGGeometry::DrawTriangles);
+ memcpy(g->vertexData(), m_fillVertices.constData(), g->vertexCount() * g->sizeOfVertex());
+ memcpy(g->indexData(), m_fillIndices.constData(), g->indexCount() * g->sizeOfIndex());
+
+ n->markDirty(QSGNode::DirtyGeometry);
+}
+
+void QQuickPathItemGenericRenderer::updateStrokeNode()
+{
+ if (!m_rootNode->m_strokeNode)
+ return;
+ if (m_effectiveDirty == DirtyFillGradient) // not applicable
+ return;
+
+ QQuickPathItemGenericRenderNode *n = m_rootNode->m_strokeNode;
+ n->markDirty(QSGNode::DirtyGeometry);
+
+ QSGGeometry *g = &n->m_geometry;
+ if (m_strokeVertices.isEmpty()) {
+ g->allocate(0, 0);
+ return;
+ }
+
+ if ((m_effectiveDirty & DirtyColor) && !(m_effectiveDirty & DirtyGeom)) {
+ ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
+ for (int i = 0; i < g->vertexCount(); ++i)
+ vdst[i].set(vdst[i].x, vdst[i].y, m_strokeColor);
+ return;
+ }
+
+ g->allocate(m_strokeVertices.count(), 0);
+ g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ memcpy(g->vertexData(), m_strokeVertices.constData(), g->vertexCount() * g->sizeOfVertex());
+}
+
+QSGMaterial *QQuickPathItemGenericMaterialFactory::createVertexColor(QQuickWindow *window)
+{
+ QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
+
+#ifndef QT_NO_OPENGL
+ if (api == QSGRendererInterface::OpenGL) // ### so much for "generic"...
+ return new QSGVertexColorMaterial;
+#endif
+
+ qWarning("Vertex-color material: Unsupported graphics API %d", api);
+ return nullptr;
+}
+
+QSGMaterial *QQuickPathItemGenericMaterialFactory::createLinearGradient(QQuickWindow *window,
+ QQuickPathItemGenericRenderNode *node)
+{
+ QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
+
+#ifndef QT_NO_OPENGL
+ if (api == QSGRendererInterface::OpenGL) // ### so much for "generic"...
+ return new QQuickPathItemLinearGradientMaterial(node);
+#endif
+
+ qWarning("Linear gradient material: Unsupported graphics API %d", api);
+ return nullptr;
+}
+
+#ifndef QT_NO_OPENGL
+
+QSGMaterialType QQuickPathItemLinearGradientShader::type;
+
+QQuickPathItemLinearGradientShader::QQuickPathItemLinearGradientShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex,
+ QStringLiteral(":/qt-project.org/items/shaders/lineargradient.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment,
+ QStringLiteral(":/qt-project.org/items/shaders/lineargradient.frag"));
+}
+
+void QQuickPathItemLinearGradientShader::initialize()
+{
+ m_opacityLoc = program()->uniformLocation("opacity");
+ m_matrixLoc = program()->uniformLocation("matrix");
+ m_gradStartLoc = program()->uniformLocation("gradStart");
+ m_gradEndLoc = program()->uniformLocation("gradEnd");
+}
+
+void QQuickPathItemLinearGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *)
+{
+ QQuickPathItemLinearGradientMaterial *m = static_cast<QQuickPathItemLinearGradientMaterial *>(mat);
+
+ if (state.isOpacityDirty())
+ program()->setUniformValue(m_opacityLoc, state.opacity());
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrixLoc, state.combinedMatrix());
+
+ QQuickPathItemGenericRenderNode *node = m->node();
+ program()->setUniformValue(m_gradStartLoc, QVector2D(node->m_fillGradient.start));
+ program()->setUniformValue(m_gradEndLoc, QVector2D(node->m_fillGradient.end));
+
+ QSGTexture *tx = QQuickPathItemGradientCache::currentCache()->get(node->m_fillGradient);
+ tx->bind();
+}
+
+char const *const *QQuickPathItemLinearGradientShader::attributeNames() const
+{
+ static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr };
+ return attr;
+}
+
+int QQuickPathItemLinearGradientMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ const QQuickPathItemLinearGradientMaterial *m = static_cast<const QQuickPathItemLinearGradientMaterial *>(other);
+
+ QQuickPathItemGenericRenderNode *a = node();
+ QQuickPathItemGenericRenderNode *b = m->node();
+ Q_ASSERT(a && b);
+ if (a == b)
+ return 0;
+
+ const QQuickPathItemGradientCache::GradientDesc *ga = &a->m_fillGradient;
+ const QQuickPathItemGradientCache::GradientDesc *gb = &b->m_fillGradient;
+ if (int d = ga->start.x() - gb->start.x())
+ return d;
+ if (int d = ga->start.y() - gb->start.y())
+ return d;
+ if (int d = ga->end.x() - gb->end.x())
+ return d;
+ if (int d = ga->end.y() - gb->end.y())
+ return d;
+
+ if (int d = ga->stops.count() - gb->stops.count())
+ return d;
+
+ for (int i = 0; i < ga->stops.count(); ++i) {
+ if (int d = ga->stops[i].first - gb->stops[i].first)
+ return d;
+ if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba())
+ return d;
+ }
+
+ return 0;
+}
+
+#endif // QT_NO_OPENGL
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickpathitemgenericrenderer_p.h b/src/quick/items/qquickpathitemgenericrenderer_p.h
new file mode 100644
index 0000000000..c186959c88
--- /dev/null
+++ b/src/quick/items/qquickpathitemgenericrenderer_p.h
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** 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 QQUICKPATHITEMGENERICRENDERER_P_H
+#define QQUICKPATHITEMGENERICRENDERER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickpathitem_p_p.h"
+#include <qsgnode.h>
+#include <qsggeometry.h>
+#include <qsgmaterial.h>
+#include <QtGui/private/qtriangulatingstroker_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPathItemGenericRootRenderNode;
+
+class QQuickPathItemGenericRenderer : public QQuickAbstractPathRenderer
+{
+public:
+ enum Dirty {
+ DirtyGeom = 0x01,
+ DirtyColor = 0x02,
+ DirtyFillGradient = 0x04,
+
+ DirtyAll = 0xFF
+ };
+
+ QQuickPathItemGenericRenderer(QQuickItem *item)
+ : m_item(item),
+ m_rootNode(nullptr),
+ m_effectiveDirty(0)
+ { }
+
+ void beginSync() override;
+ void setPath(const QQuickPath *path) override;
+ void setStrokeColor(const QColor &color) override;
+ void setStrokeWidth(qreal w) override;
+ void setFillColor(const QColor &color) override;
+ void setFillRule(QQuickPathItem::FillRule fillRule) override;
+ void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) override;
+ void setCapStyle(QQuickPathItem::CapStyle capStyle) override;
+ void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern) override;
+ void setFillGradient(QQuickPathGradient *gradient) override;
+ void endSync() override;
+ void updatePathRenderNode() override;
+
+ void setRootNode(QQuickPathItemGenericRootRenderNode *rn);
+
+ struct Color4ub { unsigned char r, g, b, a; };
+
+private:
+ void triangulateFill();
+ void triangulateStroke();
+ void updateFillNode();
+ void updateStrokeNode();
+
+ QQuickItem *m_item;
+ QQuickPathItemGenericRootRenderNode *m_rootNode;
+ QTriangulatingStroker m_stroker;
+ QDashedStrokeProcessor m_dashStroker;
+
+ QPen m_pen;
+ Color4ub m_strokeColor;
+ Color4ub m_fillColor;
+ Qt::FillRule m_fillRule;
+ QPainterPath m_path;
+ bool m_fillGradientActive;
+ QQuickPathItemGradientCache::GradientDesc m_fillGradient;
+
+ QVector<QSGGeometry::ColoredPoint2D> m_fillVertices;
+ QVector<quint16> m_fillIndices;
+ QVector<QSGGeometry::ColoredPoint2D> m_strokeVertices;
+
+ int m_syncDirty;
+ int m_effectiveDirty;
+};
+
+class QQuickPathItemGenericRenderNode : public QSGGeometryNode
+{
+public:
+ QQuickPathItemGenericRenderNode(QQuickWindow *window, QQuickPathItemGenericRootRenderNode *rootNode);
+ ~QQuickPathItemGenericRenderNode();
+
+ enum Material {
+ MatSolidColor,
+ MatLinearGradient
+ };
+
+ void activateMaterial(Material m);
+
+ QQuickWindow *window() const { return m_window; }
+ QQuickPathItemGenericRootRenderNode *rootNode() const { return m_rootNode; }
+
+ // shadow data for custom materials
+ QQuickPathItemGradientCache::GradientDesc m_fillGradient;
+
+private:
+ QSGGeometry m_geometry;
+ QQuickWindow *m_window;
+ QQuickPathItemGenericRootRenderNode *m_rootNode;
+ QSGMaterial *m_material;
+ QScopedPointer<QSGMaterial> m_solidColorMaterial;
+ QScopedPointer<QSGMaterial> m_linearGradientMaterial;
+
+ friend class QQuickPathItemGenericRenderer;
+};
+
+class QQuickPathItemGenericRootRenderNode : public QSGNode
+{
+public:
+ QQuickPathItemGenericRootRenderNode(QQuickWindow *window, bool hasFill, bool hasStroke);
+ ~QQuickPathItemGenericRootRenderNode();
+
+private:
+ QQuickPathItemGenericRenderNode *m_fillNode;
+ QQuickPathItemGenericRenderNode *m_strokeNode;
+
+ friend class QQuickPathItemGenericRenderer;
+};
+
+class QQuickPathItemGenericMaterialFactory
+{
+public:
+ static QSGMaterial *createVertexColor(QQuickWindow *window);
+ static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickPathItemGenericRenderNode *node);
+};
+
+#ifndef QT_NO_OPENGL
+
+class QQuickPathItemLinearGradientShader : public QSGMaterialShader
+{
+public:
+ QQuickPathItemLinearGradientShader();
+
+ void initialize() override;
+ void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ char const *const *attributeNames() const override;
+
+ static QSGMaterialType type;
+
+private:
+ int m_opacityLoc;
+ int m_matrixLoc;
+ int m_gradStartLoc;
+ int m_gradEndLoc;
+};
+
+class QQuickPathItemLinearGradientMaterial : public QSGMaterial
+{
+public:
+ QQuickPathItemLinearGradientMaterial(QQuickPathItemGenericRenderNode *node)
+ : m_node(node)
+ {
+ // Passing RequiresFullMatrix is essential in order to prevent the
+ // batch renderer from baking in simple, translate-only transforms into
+ // the vertex data. The shader will rely on the fact that
+ // vertexCoord.xy is the PathItem-space coordinate and so no modifications
+ // are welcome.
+ setFlag(Blending | RequiresFullMatrix);
+ }
+
+ QSGMaterialType *type() const override
+ {
+ return &QQuickPathItemLinearGradientShader::type;
+ }
+
+ int compare(const QSGMaterial *other) const override;
+
+ QSGMaterialShader *createShader() const override
+ {
+ return new QQuickPathItemLinearGradientShader;
+ }
+
+ QQuickPathItemGenericRenderNode *node() const { return m_node; }
+
+private:
+ QQuickPathItemGenericRenderNode *m_node;
+};
+
+#endif // QT_NO_OPENGL
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPATHITEMGENERICRENDERER_P_H
diff --git a/src/quick/items/qquickpathitemnvprrenderer.cpp b/src/quick/items/qquickpathitemnvprrenderer.cpp
new file mode 100644
index 0000000000..d07a63c86d
--- /dev/null
+++ b/src/quick/items/qquickpathitemnvprrenderer.cpp
@@ -0,0 +1,567 @@
+/****************************************************************************
+**
+** 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 "qquickpathitemnvprrenderer_p.h"
+#include <QOpenGLExtraFunctions>
+#include <private/qquickpath_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickPathItemNvprRenderer::beginSync()
+{
+ // nothing to do here
+}
+
+void QQuickPathItemNvprRenderer::setPath(const QQuickPath *path)
+{
+ convertPath(path);
+ m_dirty |= DirtyPath;
+}
+
+void QQuickPathItemNvprRenderer::setStrokeColor(const QColor &color)
+{
+ m_strokeColor = color;
+ m_dirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setStrokeWidth(qreal w)
+{
+ m_strokeWidth = w;
+ m_dirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setFillColor(const QColor &color)
+{
+ m_fillColor = color;
+ m_dirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setFillRule(QQuickPathItem::FillRule fillRule)
+{
+ m_fillRule = fillRule;
+ m_dirty |= DirtyFillRule;
+}
+
+void QQuickPathItemNvprRenderer::setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit)
+{
+ m_joinStyle = joinStyle;
+ m_miterLimit = miterLimit;
+ m_dirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setCapStyle(QQuickPathItem::CapStyle capStyle)
+{
+ m_capStyle = capStyle;
+ m_dirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern)
+{
+ m_dashActive = strokeStyle == QQuickPathItem::DashLine;
+ m_dashOffset = dashOffset;
+ m_dashPattern = dashPattern;
+ m_dirty |= DirtyDash;
+}
+
+void QQuickPathItemNvprRenderer::setFillGradient(QQuickPathGradient *gradient)
+{
+ m_fillGradientActive = gradient != nullptr;
+ if (gradient) {
+ m_fillGradient.stops = gradient->sortedGradientStops();
+ m_fillGradient.spread = gradient->spread();
+ if (QQuickPathLinearGradient *g = qobject_cast<QQuickPathLinearGradient *>(gradient)) {
+ m_fillGradient.start = QPointF(g->x1(), g->y1());
+ m_fillGradient.end = QPointF(g->x2(), g->y2());
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+ m_dirty |= DirtyFillGradient;
+}
+
+void QQuickPathItemNvprRenderer::endSync()
+{
+ // nothing to do here
+}
+
+void QQuickPathItemNvprRenderer::setNode(QQuickPathItemNvprRenderNode *node)
+{
+ if (m_node != node) {
+ m_node = node;
+ // Scenegraph nodes can be destroyed and then replaced by new ones over
+ // time; hence it is important to mark everything dirty for
+ // updatePathRenderNode(). We can assume the renderer has a full sync
+ // of the data at this point.
+ m_dirty = DirtyAll;
+ }
+}
+
+QDebug operator<<(QDebug debug, const QQuickPathItemNvprRenderer::NvprPath &path)
+{
+ QDebugStateSaver saver(debug);
+ debug.space().noquote();
+ debug << "Path with" << path.cmd.count() << "commands";
+ int ci = 0;
+ for (GLubyte cmd : path.cmd) {
+ static struct { GLubyte cmd; const char *s; int coordCount; } nameTab[] = {
+ { GL_MOVE_TO_NV, "moveTo", 2 },
+ { GL_LINE_TO_NV, "lineTo", 2 },
+ { GL_QUADRATIC_CURVE_TO_NV, "quadTo", 4 },
+ { GL_CUBIC_CURVE_TO_NV, "cubicTo", 6 },
+ { GL_LARGE_CW_ARC_TO_NV, "arcTo-large-CW", 5 },
+ { GL_LARGE_CCW_ARC_TO_NV, "arcTo-large-CCW", 5 },
+ { GL_SMALL_CW_ARC_TO_NV, "arcTo-small-CW", 5 },
+ { GL_SMALL_CCW_ARC_TO_NV, "arcTo-small-CCW", 5 },
+ { GL_CLOSE_PATH_NV, "closePath", 0 } };
+ for (size_t i = 0; i < sizeof(nameTab) / sizeof(nameTab[0]); ++i) {
+ if (nameTab[i].cmd == cmd) {
+ QByteArray cs;
+ for (int j = 0; j < nameTab[i].coordCount; ++j) {
+ cs.append(QByteArray::number(path.coord[ci++]));
+ cs.append(' ');
+ }
+ debug << "\n " << nameTab[i].s << " " << cs;
+ break;
+ }
+ }
+ }
+ return debug;
+}
+
+static inline void appendCoords(QVector<GLfloat> *v, QQuickCurve *c, QPointF *pos)
+{
+ QPointF p(c->hasRelativeX() ? pos->x() + c->relativeX() : c->x(),
+ c->hasRelativeY() ? pos->y() + c->relativeY() : c->y());
+ v->append(p.x());
+ v->append(p.y());
+ *pos = p;
+}
+
+static inline void appendControlCoords(QVector<GLfloat> *v, QQuickPathQuad *c, const QPointF &pos)
+{
+ QPointF p(c->hasRelativeControlX() ? pos.x() + c->relativeControlX() : c->controlX(),
+ c->hasRelativeControlY() ? pos.y() + c->relativeControlY() : c->controlY());
+ v->append(p.x());
+ v->append(p.y());
+}
+
+static inline void appendControl1Coords(QVector<GLfloat> *v, QQuickPathCubic *c, const QPointF &pos)
+{
+ QPointF p(c->hasRelativeControl1X() ? pos.x() + c->relativeControl1X() : c->control1X(),
+ c->hasRelativeControl1Y() ? pos.y() + c->relativeControl1Y() : c->control1Y());
+ v->append(p.x());
+ v->append(p.y());
+}
+
+static inline void appendControl2Coords(QVector<GLfloat> *v, QQuickPathCubic *c, const QPointF &pos)
+{
+ QPointF p(c->hasRelativeControl2X() ? pos.x() + c->relativeControl2X() : c->control2X(),
+ c->hasRelativeControl2Y() ? pos.y() + c->relativeControl2Y() : c->control2Y());
+ v->append(p.x());
+ v->append(p.y());
+}
+
+void QQuickPathItemNvprRenderer::convertPath(const QQuickPath *path)
+{
+ m_path = NvprPath();
+ if (!path)
+ return;
+
+ const QList<QQuickPathElement *> &pp(QQuickPathPrivate::get(path)->_pathElements);
+ if (pp.isEmpty())
+ return;
+
+ QPointF pos(path->startX(), path->startY());
+ m_path.cmd.append(GL_MOVE_TO_NV);
+ m_path.coord.append(pos.x());
+ m_path.coord.append(pos.y());
+
+ for (QQuickPathElement *e : pp) {
+ if (QQuickPathMove *o = qobject_cast<QQuickPathMove *>(e)) {
+ m_path.cmd.append(GL_MOVE_TO_NV);
+ appendCoords(&m_path.coord, o, &pos);
+ } else if (QQuickPathLine *o = qobject_cast<QQuickPathLine *>(e)) {
+ m_path.cmd.append(GL_LINE_TO_NV);
+ appendCoords(&m_path.coord, o, &pos);
+ } else if (QQuickPathQuad *o = qobject_cast<QQuickPathQuad *>(e)) {
+ m_path.cmd.append(GL_QUADRATIC_CURVE_TO_NV);
+ appendControlCoords(&m_path.coord, o, pos);
+ appendCoords(&m_path.coord, o, &pos);
+ } else if (QQuickPathCubic *o = qobject_cast<QQuickPathCubic *>(e)) {
+ m_path.cmd.append(GL_CUBIC_CURVE_TO_NV);
+ appendControl1Coords(&m_path.coord, o, pos);
+ appendControl2Coords(&m_path.coord, o, pos);
+ appendCoords(&m_path.coord, o, &pos);
+ } else if (QQuickPathArc *o = qobject_cast<QQuickPathArc *>(e)) {
+ const bool sweepFlag = o->direction() == QQuickPathArc::Clockwise; // maps to CCW, not a typo
+ GLenum cmd;
+ if (o->useLargeArc())
+ cmd = sweepFlag ? GL_LARGE_CCW_ARC_TO_NV : GL_LARGE_CW_ARC_TO_NV;
+ else
+ cmd = sweepFlag ? GL_SMALL_CCW_ARC_TO_NV : GL_SMALL_CW_ARC_TO_NV;
+ m_path.cmd.append(cmd);
+ m_path.coord.append(o->radiusX());
+ m_path.coord.append(o->radiusY());
+ m_path.coord.append(0.0f); // X axis rotation
+ appendCoords(&m_path.coord, o, &pos);
+ } else {
+ qWarning() << "PathItem/NVPR: unsupported Path element" << e;
+ }
+ }
+
+ if (qFuzzyCompare(pos.x(), path->startX()) && qFuzzyCompare(pos.y(), path->startY()))
+ m_path.cmd.append(GL_CLOSE_PATH_NV);
+}
+
+static inline QVector4D qsg_premultiply(const QColor &c, float globalOpacity)
+{
+ const float o = c.alphaF() * globalOpacity;
+ return QVector4D(c.redF() * o, c.greenF() * o, c.blueF() * o, o);
+}
+
+void QQuickPathItemNvprRenderer::updatePathRenderNode()
+{
+ // Called on the render thread with gui blocked -> update the node with its
+ // own copy of all relevant data.
+
+ if (!m_dirty)
+ return;
+
+ // updatePathRenderNode() can be called several times with different dirty
+ // state before render() gets invoked. So accumulate.
+ m_node->m_dirty |= m_dirty;
+
+ if (m_dirty & DirtyPath)
+ m_node->m_source = m_path;
+
+ if (m_dirty & DirtyStyle) {
+ m_node->m_strokeWidth = m_strokeWidth;
+ m_node->m_strokeColor = qsg_premultiply(m_strokeColor, 1.0f);
+ m_node->m_fillColor = qsg_premultiply(m_fillColor, 1.0f);
+ switch (m_joinStyle) {
+ case QQuickPathItem::MiterJoin:
+ m_node->m_joinStyle = GL_MITER_TRUNCATE_NV;
+ break;
+ case QQuickPathItem::BevelJoin:
+ m_node->m_joinStyle = GL_BEVEL_NV;
+ break;
+ case QQuickPathItem::RoundJoin:
+ m_node->m_joinStyle = GL_ROUND_NV;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ m_node->m_miterLimit = m_miterLimit;
+ switch (m_capStyle) {
+ case QQuickPathItem::FlatCap:
+ m_node->m_capStyle = GL_FLAT;
+ break;
+ case QQuickPathItem::SquareCap:
+ m_node->m_capStyle = GL_SQUARE_NV;
+ break;
+ case QQuickPathItem::RoundCap:
+ m_node->m_capStyle = GL_ROUND_NV;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+
+ if (m_dirty & DirtyFillRule) {
+ switch (m_fillRule) {
+ case QQuickPathItem::OddEvenFill:
+ m_node->m_fillRule = GL_COUNT_UP_NV;
+ break;
+ case QQuickPathItem::WindingFill:
+ m_node->m_fillRule = GL_INVERT;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+
+ if (m_dirty & DirtyDash) {
+ m_node->m_dashOffset = m_dashOffset;
+ if (m_dashActive) {
+ m_node->m_dashPattern.resize(m_dashPattern.count());
+ // Multiply by strokeWidth because the PathItem API follows QPen
+ // meaning the input dash pattern here is in width units.
+ for (int i = 0; i < m_dashPattern.count(); ++i)
+ m_node->m_dashPattern[i] = GLfloat(m_dashPattern[i]) * m_strokeWidth;
+ } else {
+ m_node->m_dashPattern.clear();
+ }
+ }
+
+ if (m_dirty & DirtyFillGradient) {
+ m_node->m_fillGradientActive = m_fillGradientActive;
+ if (m_fillGradientActive)
+ m_node->m_fillGradient = m_fillGradient;
+ }
+
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ m_dirty = 0;
+}
+
+bool QQuickPathItemNvprRenderNode::nvprInited = false;
+QQuickNvprFunctions QQuickPathItemNvprRenderNode::nvpr;
+QQuickNvprMaterialManager QQuickPathItemNvprRenderNode::mtlmgr;
+
+QQuickPathItemNvprRenderNode::QQuickPathItemNvprRenderNode(QQuickPathItem *item)
+ : m_item(item)
+{
+}
+
+QQuickPathItemNvprRenderNode::~QQuickPathItemNvprRenderNode()
+{
+ releaseResources();
+}
+
+void QQuickPathItemNvprRenderNode::releaseResources()
+{
+ if (m_path) {
+ nvpr.deletePaths(m_path, 1);
+ m_path = 0;
+ }
+}
+
+void QQuickNvprMaterialManager::create(QQuickNvprFunctions *nvpr)
+{
+ m_nvpr = nvpr;
+}
+
+void QQuickNvprMaterialManager::releaseResources()
+{
+ QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
+ for (MaterialDesc &mtl : m_materials) {
+ if (mtl.ppl) {
+ f->glDeleteProgramPipelines(1, &mtl.ppl);
+ mtl = MaterialDesc();
+ }
+ }
+}
+
+QQuickNvprMaterialManager::MaterialDesc *QQuickNvprMaterialManager::activateMaterial(Material m)
+{
+ QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
+ MaterialDesc &mtl(m_materials[m]);
+
+ if (!mtl.ppl) {
+ if (m == MatSolid) {
+ static const char *fragSrc =
+ "#version 310 es\n"
+ "precision highp float;\n"
+ "out vec4 fragColor;\n"
+ "uniform vec4 color;\n"
+ "uniform float opacity;\n"
+ "void main() {\n"
+ " fragColor = color * opacity;\n"
+ "}\n";
+ if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) {
+ qWarning("NVPR: Failed to create shader pipeline for solid fill");
+ return nullptr;
+ }
+ Q_ASSERT(mtl.ppl && mtl.prg);
+ mtl.uniLoc[0] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "color");
+ Q_ASSERT(mtl.uniLoc[0] >= 0);
+ mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity");
+ Q_ASSERT(mtl.uniLoc[1] >= 0);
+ } else if (m == MatLinearGradient) {
+ static const char *fragSrc =
+ "#version 310 es\n"
+ "precision highp float;\n"
+ "layout(location = 0) in vec2 uv;"
+ "uniform float opacity;\n"
+ "uniform sampler2D gradTab;\n"
+ "uniform vec2 gradStart;\n"
+ "uniform vec2 gradEnd;\n"
+ "out vec4 fragColor;\n"
+ "void main() {\n"
+ " vec2 gradVec = gradEnd - gradStart;\n"
+ " float gradTabIndex = dot(gradVec, uv - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);\n"
+ " fragColor = texture(gradTab, vec2(gradTabIndex, 0.5)) * opacity;\n"
+ "}\n";
+ if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) {
+ qWarning("NVPR: Failed to create shader pipeline for linear gradient");
+ return nullptr;
+ }
+ Q_ASSERT(mtl.ppl && mtl.prg);
+ mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity");
+ Q_ASSERT(mtl.uniLoc[1] >= 0);
+ mtl.uniLoc[2] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "gradStart");
+ Q_ASSERT(mtl.uniLoc[2] >= 0);
+ mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "gradEnd");
+ Q_ASSERT(mtl.uniLoc[3] >= 0);
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ f->glBindProgramPipeline(mtl.ppl);
+
+ return &mtl;
+}
+
+void QQuickPathItemNvprRenderNode::updatePath()
+{
+ if (m_dirty & QQuickPathItemNvprRenderer::DirtyPath) {
+ if (!m_path) {
+ m_path = nvpr.genPaths(1);
+ Q_ASSERT(m_path != 0);
+ }
+ nvpr.pathCommands(m_path, m_source.cmd.count(), m_source.cmd.constData(),
+ m_source.coord.count(), GL_FLOAT, m_source.coord.constData());
+ }
+
+ if (m_dirty & QQuickPathItemNvprRenderer::DirtyStyle) {
+ nvpr.pathParameterf(m_path, GL_PATH_STROKE_WIDTH_NV, m_strokeWidth);
+ nvpr.pathParameteri(m_path, GL_PATH_JOIN_STYLE_NV, m_joinStyle);
+ nvpr.pathParameteri(m_path, GL_PATH_MITER_LIMIT_NV, m_miterLimit);
+ nvpr.pathParameteri(m_path, GL_PATH_END_CAPS_NV, m_capStyle);
+ nvpr.pathParameteri(m_path, GL_PATH_DASH_CAPS_NV, m_capStyle);
+ }
+
+ if (m_dirty & QQuickPathItemNvprRenderer::DirtyDash) {
+ nvpr.pathParameterf(m_path, GL_PATH_DASH_OFFSET_NV, m_dashOffset);
+ // count == 0 -> no dash
+ nvpr.pathDashArray(m_path, m_dashPattern.count(), m_dashPattern.constData());
+ }
+}
+
+void QQuickPathItemNvprRenderNode::render(const RenderState *state)
+{
+ if (!nvprInited) {
+ if (!nvpr.create()) {
+ qWarning("NVPR init failed");
+ return;
+ }
+ mtlmgr.create(&nvpr);
+ nvprInited = true;
+ }
+
+ updatePath();
+
+ QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
+ f->glUseProgram(0);
+ QQuickNvprMaterialManager::MaterialDesc *mtl;
+ if (m_fillGradientActive)
+ mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatLinearGradient);
+ else
+ mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid);
+ if (!mtl)
+ return;
+
+ // Assume stencil buffer is cleared to 0 for each frame.
+ // Within the frame dppass=GL_ZERO for glStencilOp ensures stencil is reset and so no need to clear.
+ f->glStencilMask(~0);
+ f->glEnable(GL_STENCIL_TEST);
+ f->glStencilFunc(GL_NOTEQUAL, 0, 0xFF);
+ f->glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
+
+ // Depth test against the opaque batches rendered before.
+ f->glEnable(GL_DEPTH_TEST);
+ f->glDepthFunc(GL_LESS);
+ nvpr.pathCoverDepthFunc(GL_LESS);
+ nvpr.pathStencilDepthOffset(-0.05f, -1);
+
+ nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, matrix()->constData());
+ nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, state->projectionMatrix()->constData());
+
+ if (state->scissorEnabled()) {
+ // scissor rect is already set, just enable scissoring
+ f->glEnable(GL_SCISSOR_TEST);
+ }
+
+ if (!qFuzzyIsNull(m_fillColor.w()) || m_fillGradientActive) {
+ if (m_fillGradientActive) {
+ QSGTexture *tx = QQuickPathItemGradientCache::currentCache()->get(m_fillGradient);
+ tx->bind();
+ // uv = vec2(coeff[0] * x + coeff[1] * y + coeff[2], coeff[3] * x + coeff[4] * y + coeff[5])
+ // where x and y are in path coordinate space, which is just what
+ // we need since the gradient's start and stop are in that space too.
+ GLfloat coeff[6] = { 1, 0, 0,
+ 0, 1, 0 };
+ nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff);
+ f->glProgramUniform2f(mtl->prg, mtl->uniLoc[2], m_fillGradient.start.x(), m_fillGradient.start.y());
+ f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], m_fillGradient.end.x(), m_fillGradient.end.y());
+ } else {
+ f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0],
+ m_fillColor.x(), m_fillColor.y(), m_fillColor.z(), m_fillColor.w());
+ }
+ f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity());
+ nvpr.stencilThenCoverFillPath(m_path, m_fillRule, 0xFF, GL_BOUNDING_BOX_NV);
+ }
+
+ if (!qFuzzyIsNull(m_strokeWidth) && !qFuzzyIsNull(m_strokeColor.w())) {
+ if (m_fillGradientActive)
+ mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid);
+ f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0],
+ m_strokeColor.x(), m_strokeColor.y(), m_strokeColor.z(), m_strokeColor.w());
+ f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity());
+ nvpr.stencilThenCoverStrokePath(m_path, 0x1, ~0, GL_CONVEX_HULL_NV);
+ }
+
+ f->glBindProgramPipeline(0);
+
+ m_dirty = 0;
+}
+
+QSGRenderNode::StateFlags QQuickPathItemNvprRenderNode::changedStates() const
+{
+ return BlendState | StencilState | DepthState | ScissorState;
+}
+
+QSGRenderNode::RenderingFlags QQuickPathItemNvprRenderNode::flags() const
+{
+ return DepthAwareRendering; // avoid hitting the less optimal no-opaque-batch path in the renderer
+}
+
+QRectF QQuickPathItemNvprRenderNode::rect() const
+{
+ return QRect(0, 0, m_item->width(), m_item->height());
+}
+
+bool QQuickPathItemNvprRenderNode::isSupported()
+{
+ static const bool nvprDisabled = qEnvironmentVariableIntValue("QT_NO_NVPR") != 0;
+ return !nvprDisabled && QQuickNvprFunctions::isSupported();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickpathitemnvprrenderer_p.h b/src/quick/items/qquickpathitemnvprrenderer_p.h
new file mode 100644
index 0000000000..0075572324
--- /dev/null
+++ b/src/quick/items/qquickpathitemnvprrenderer_p.h
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** 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 QQUICKPATHITEMNVPRRENDERER_P_H
+#define QQUICKPATHITEMNVPRRENDERER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickpathitem_p_p.h"
+#include <qsgrendernode.h>
+#include <private/qquicknvprfunctions_p.h>
+#include <QColor>
+#include <QVector4D>
+#include <QDebug>
+
+#ifndef QT_NO_OPENGL
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPathItemNvprRenderNode;
+
+class QQuickPathItemNvprRenderer : public QQuickAbstractPathRenderer
+{
+public:
+ enum Dirty {
+ DirtyPath = 0x01,
+ DirtyStyle = 0x02,
+ DirtyFillRule = 0x04,
+ DirtyDash = 0x08,
+ DirtyFillGradient = 0x10,
+
+ DirtyAll = 0xFF
+ };
+
+ void beginSync() override;
+ void setPath(const QQuickPath *path) override;
+ void setStrokeColor(const QColor &color) override;
+ void setStrokeWidth(qreal w) override;
+ void setFillColor(const QColor &color) override;
+ void setFillRule(QQuickPathItem::FillRule fillRule) override;
+ void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) override;
+ void setCapStyle(QQuickPathItem::CapStyle capStyle) override;
+ void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern) override;
+ void setFillGradient(QQuickPathGradient *gradient) override;
+ void endSync() override;
+ void updatePathRenderNode() override;
+
+ void setNode(QQuickPathItemNvprRenderNode *node);
+
+ struct NvprPath {
+ QVector<GLubyte> cmd;
+ QVector<GLfloat> coord;
+ };
+
+private:
+ void convertPath(const QQuickPath *path);
+
+ QQuickPathItemNvprRenderNode *m_node = nullptr;
+ int m_dirty = 0;
+
+ NvprPath m_path;
+ qreal m_strokeWidth;
+ QColor m_strokeColor;
+ QColor m_fillColor;
+ QQuickPathItem::JoinStyle m_joinStyle;
+ int m_miterLimit;
+ QQuickPathItem::CapStyle m_capStyle;
+ QQuickPathItem::FillRule m_fillRule;
+ bool m_dashActive;
+ qreal m_dashOffset;
+ QVector<qreal> m_dashPattern;
+ bool m_fillGradientActive;
+ QQuickPathItemGradientCache::GradientDesc m_fillGradient;
+};
+
+QDebug operator<<(QDebug debug, const QQuickPathItemNvprRenderer::NvprPath &path);
+
+class QQuickNvprMaterialManager
+{
+public:
+ enum Material {
+ MatSolid,
+ MatLinearGradient,
+
+ NMaterials
+ };
+
+ struct MaterialDesc {
+ GLuint ppl = 0;
+ GLuint prg = 0;
+ int uniLoc[4];
+ };
+
+ void create(QQuickNvprFunctions *nvpr);
+ MaterialDesc *activateMaterial(Material m);
+ void releaseResources();
+
+private:
+ QQuickNvprFunctions *m_nvpr;
+ MaterialDesc m_materials[NMaterials];
+};
+
+class QQuickPathItemNvprRenderNode : public QSGRenderNode
+{
+public:
+ QQuickPathItemNvprRenderNode(QQuickPathItem *item);
+ ~QQuickPathItemNvprRenderNode();
+
+ void render(const RenderState *state) override;
+ void releaseResources() override;
+ StateFlags changedStates() const override;
+ RenderingFlags flags() const override;
+ QRectF rect() const override;
+
+ static bool isSupported();
+
+private:
+ void updatePath();
+
+ static bool nvprInited;
+ static QQuickNvprFunctions nvpr;
+ static QQuickNvprMaterialManager mtlmgr;
+
+ QQuickPathItem *m_item;
+ GLuint m_path = 0;
+ int m_dirty = 0;
+
+ QQuickPathItemNvprRenderer::NvprPath m_source;
+ GLfloat m_strokeWidth;
+ QVector4D m_strokeColor;
+ QVector4D m_fillColor;
+ GLenum m_joinStyle;
+ GLint m_miterLimit;
+ GLenum m_capStyle;
+ GLenum m_fillRule;
+ GLfloat m_dashOffset;
+ QVector<GLfloat> m_dashPattern;
+ bool m_fillGradientActive;
+ QQuickPathItemGradientCache::GradientDesc m_fillGradient;
+
+ friend class QQuickPathItemNvprRenderer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_OPENGL
+
+#endif // QQUICKPATHITEMNVPRRENDERER_P_H
diff --git a/src/quick/items/qquickpathitemsoftwarerenderer.cpp b/src/quick/items/qquickpathitemsoftwarerenderer.cpp
new file mode 100644
index 0000000000..40732e4bf9
--- /dev/null
+++ b/src/quick/items/qquickpathitemsoftwarerenderer.cpp
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** 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 "qquickpathitemsoftwarerenderer_p.h"
+#include <private/qquickpath_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickPathItemSoftwareRenderer::beginSync()
+{
+ // nothing to do here
+}
+
+void QQuickPathItemSoftwareRenderer::setPath(const QQuickPath *path)
+{
+ m_path = path ? path->path() : QPainterPath();
+ m_dirty |= DirtyPath;
+}
+
+void QQuickPathItemSoftwareRenderer::setStrokeColor(const QColor &color)
+{
+ m_pen.setColor(color);
+ m_dirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setStrokeWidth(qreal w)
+{
+ m_pen.setWidthF(w);
+ m_dirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setFillColor(const QColor &color)
+{
+ m_fillColor = color;
+ m_brush.setColor(m_fillColor);
+ m_dirty |= DirtyBrush;
+}
+
+void QQuickPathItemSoftwareRenderer::setFillRule(QQuickPathItem::FillRule fillRule)
+{
+ m_fillRule = Qt::FillRule(fillRule);
+ m_dirty |= DirtyFillRule;
+}
+
+void QQuickPathItemSoftwareRenderer::setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit)
+{
+ m_pen.setJoinStyle(Qt::PenJoinStyle(joinStyle));
+ m_pen.setMiterLimit(miterLimit);
+ m_dirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setCapStyle(QQuickPathItem::CapStyle capStyle)
+{
+ m_pen.setCapStyle(Qt::PenCapStyle(capStyle));
+ m_dirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern)
+{
+ switch (strokeStyle) {
+ case QQuickPathItem::SolidLine:
+ m_pen.setStyle(Qt::SolidLine);
+ break;
+ case QQuickPathItem::DashLine:
+ m_pen.setStyle(Qt::CustomDashLine);
+ m_pen.setDashPattern(dashPattern);
+ m_pen.setDashOffset(dashOffset);
+ break;
+ default:
+ break;
+ }
+ m_dirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setFillGradient(QQuickPathGradient *gradient)
+{
+ if (QQuickPathLinearGradient *linearGradient = qobject_cast<QQuickPathLinearGradient *>(gradient)) {
+ QLinearGradient painterGradient(linearGradient->x1(), linearGradient->y1(),
+ linearGradient->x2(), linearGradient->y2());
+ painterGradient.setStops(linearGradient->sortedGradientStops());
+ switch (gradient->spread()) {
+ case QQuickPathGradient::PadSpread:
+ painterGradient.setSpread(QGradient::PadSpread);
+ break;
+ case QQuickPathGradient::RepeatSpread:
+ painterGradient.setSpread(QGradient::RepeatSpread);
+ break;
+ case QQuickPathGradient::ReflectSpread:
+ painterGradient.setSpread(QGradient::ReflectSpread);
+ break;
+ default:
+ break;
+ }
+ m_brush = QBrush(painterGradient);
+ } else {
+ m_brush = QBrush(m_fillColor);
+ }
+ m_dirty |= DirtyBrush;
+}
+
+void QQuickPathItemSoftwareRenderer::endSync()
+{
+ // nothing to do here
+}
+
+void QQuickPathItemSoftwareRenderer::setNode(QQuickPathItemSoftwareRenderNode *node)
+{
+ if (m_node != node) {
+ m_node = node;
+ // Scenegraph nodes can be destroyed and then replaced by new ones over
+ // time; hence it is important to mark everything dirty for
+ // updatePathRenderNode(). We can assume the renderer has a full sync
+ // of the data at this point.
+ m_dirty = DirtyAll;
+ }
+}
+
+void QQuickPathItemSoftwareRenderer::updatePathRenderNode()
+{
+ if (!m_dirty)
+ return;
+
+ // updatePathRenderNode() can be called several times with different dirty
+ // state before render() gets invoked. So accumulate.
+ m_node->m_dirty |= m_dirty;
+
+ if (m_dirty & DirtyPath) {
+ m_node->m_path = m_path;
+ m_node->m_path.setFillRule(m_fillRule);
+ }
+
+ if (m_dirty & DirtyFillRule)
+ m_node->m_path.setFillRule(m_fillRule);
+
+ if (m_dirty & DirtyPen)
+ m_node->m_pen = m_pen;
+
+ if (m_dirty & DirtyBrush)
+ m_node->m_brush = m_brush;
+
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ m_dirty = 0;
+}
+
+QQuickPathItemSoftwareRenderNode::QQuickPathItemSoftwareRenderNode(QQuickPathItem *item)
+ : m_item(item)
+{
+}
+
+QQuickPathItemSoftwareRenderNode::~QQuickPathItemSoftwareRenderNode()
+{
+ releaseResources();
+}
+
+void QQuickPathItemSoftwareRenderNode::releaseResources()
+{
+}
+
+void QQuickPathItemSoftwareRenderNode::render(const RenderState *state)
+{
+ if (m_path.isEmpty())
+ return;
+
+ QSGRendererInterface *rif = m_item->window()->rendererInterface();
+ QPainter *p = static_cast<QPainter *>(rif->getResource(m_item->window(), QSGRendererInterface::PainterResource));
+ Q_ASSERT(p);
+
+ p->setTransform(matrix()->toTransform());
+ p->setOpacity(inheritedOpacity());
+
+ const QRegion *clipRegion = state->clipRegion();
+ if (clipRegion && !clipRegion->isEmpty())
+ p->setClipRegion(*clipRegion, Qt::IntersectClip);
+
+ p->setPen(!qFuzzyIsNull(m_pen.widthF()) && m_pen.color() != Qt::transparent ? m_pen : Qt::NoPen);
+ p->setBrush(m_brush.color() != Qt::transparent ? m_brush : Qt::NoBrush);
+ p->drawPath(m_path);
+
+ m_dirty = 0;
+}
+
+QSGRenderNode::StateFlags QQuickPathItemSoftwareRenderNode::changedStates() const
+{
+ return 0;
+}
+
+QSGRenderNode::RenderingFlags QQuickPathItemSoftwareRenderNode::flags() const
+{
+ return BoundedRectRendering; // avoid fullscreen updates by saying we won't draw outside rect()
+}
+
+QRectF QQuickPathItemSoftwareRenderNode::rect() const
+{
+ return QRect(0, 0, m_item->width(), m_item->height());
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickpathitemsoftwarerenderer_p.h b/src/quick/items/qquickpathitemsoftwarerenderer_p.h
new file mode 100644
index 0000000000..584771425d
--- /dev/null
+++ b/src/quick/items/qquickpathitemsoftwarerenderer_p.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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 QQUICKPATHITEMSOFTWARERENDERER_P_H
+#define QQUICKPATHITEMSOFTWARERENDERER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickpathitem_p_p.h"
+#include <qsgrendernode.h>
+#include <QPen>
+#include <QBrush>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPathItemSoftwareRenderNode;
+
+class QQuickPathItemSoftwareRenderer : public QQuickAbstractPathRenderer
+{
+public:
+ enum Dirty {
+ DirtyPath = 0x01,
+ DirtyPen = 0x02,
+ DirtyFillRule = 0x04,
+ DirtyBrush = 0x08,
+
+ DirtyAll = 0xFF
+ };
+
+ void beginSync() override;
+ void setPath(const QQuickPath *path) override;
+ void setStrokeColor(const QColor &color) override;
+ void setStrokeWidth(qreal w) override;
+ void setFillColor(const QColor &color) override;
+ void setFillRule(QQuickPathItem::FillRule fillRule) override;
+ void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) override;
+ void setCapStyle(QQuickPathItem::CapStyle capStyle) override;
+ void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern) override;
+ void setFillGradient(QQuickPathGradient *gradient) override;
+ void endSync() override;
+ void updatePathRenderNode() override;
+
+ void setNode(QQuickPathItemSoftwareRenderNode *node);
+
+private:
+ QQuickPathItemSoftwareRenderNode *m_node = nullptr;
+ int m_dirty = 0;
+
+ QPainterPath m_path;
+ QPen m_pen;
+ QColor m_fillColor;
+ QBrush m_brush;
+ Qt::FillRule m_fillRule;
+};
+
+class QQuickPathItemSoftwareRenderNode : public QSGRenderNode
+{
+public:
+ QQuickPathItemSoftwareRenderNode(QQuickPathItem *item);
+ ~QQuickPathItemSoftwareRenderNode();
+
+ void render(const RenderState *state) override;
+ void releaseResources() override;
+ StateFlags changedStates() const override;
+ RenderingFlags flags() const override;
+ QRectF rect() const override;
+
+private:
+ QQuickPathItem *m_item;
+ int m_dirty = 0;
+
+ QPainterPath m_path;
+ QPen m_pen;
+ QBrush m_brush;
+
+ friend class QQuickPathItemSoftwareRenderer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPATHITEMSOFTWARERENDERER_P_H
diff --git a/src/quick/items/shaders/lineargradient.frag b/src/quick/items/shaders/lineargradient.frag
new file mode 100644
index 0000000000..7f4a739109
--- /dev/null
+++ b/src/quick/items/shaders/lineargradient.frag
@@ -0,0 +1,9 @@
+uniform sampler2D gradTabTexture;
+uniform highp float opacity;
+
+varying highp float gradTabIndex;
+
+void main()
+{
+ gl_FragColor = texture2D(gradTabTexture, vec2(gradTabIndex, 0.5)) * opacity;
+}
diff --git a/src/quick/items/shaders/lineargradient.vert b/src/quick/items/shaders/lineargradient.vert
new file mode 100644
index 0000000000..eb21b8886b
--- /dev/null
+++ b/src/quick/items/shaders/lineargradient.vert
@@ -0,0 +1,15 @@
+attribute vec4 vertexCoord;
+attribute vec4 vertexColor;
+
+uniform mat4 matrix;
+uniform vec2 gradStart;
+uniform vec2 gradEnd;
+
+varying float gradTabIndex;
+
+void main()
+{
+ vec2 gradVec = gradEnd - gradStart;
+ gradTabIndex = dot(gradVec, vertexCoord.xy - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);
+ gl_Position = matrix * vertexCoord;
+}
diff --git a/src/quick/items/shaders/lineargradient_core.frag b/src/quick/items/shaders/lineargradient_core.frag
new file mode 100644
index 0000000000..5908acfa67
--- /dev/null
+++ b/src/quick/items/shaders/lineargradient_core.frag
@@ -0,0 +1,12 @@
+#version 150 core
+
+uniform sampler2D gradTabTexture;
+uniform float opacity;
+
+in float gradTabIndex;
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = texture(gradTabTexture, vec2(gradTabIndex, 0.5)) * opacity;
+}
diff --git a/src/quick/items/shaders/lineargradient_core.vert b/src/quick/items/shaders/lineargradient_core.vert
new file mode 100644
index 0000000000..60b56f38e3
--- /dev/null
+++ b/src/quick/items/shaders/lineargradient_core.vert
@@ -0,0 +1,17 @@
+#version 150 core
+
+in vec4 vertexCoord;
+in vec4 vertexColor;
+
+uniform mat4 matrix;
+uniform vec2 gradStart;
+uniform vec2 gradEnd;
+
+out float gradTabIndex;
+
+void main()
+{
+ vec2 gradVec = gradEnd - gradStart;
+ gradTabIndex = dot(gradVec, vertexCoord.xy - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);
+ gl_Position = matrix * vertexCoord;
+}
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 8de205fc98..b8ed190b33 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -978,6 +978,10 @@ void Renderer::nodeChangedBatchRoot(Node *node, Node *root)
e->root = root;
e->boundsComputed = false;
}
+ } else if (node->type() == QSGNode::RenderNodeType) {
+ RenderNodeElement *e = node->renderNodeElement();
+ if (e)
+ e->root = root;
}
SHADOWNODE_TRAVERSE(node)
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
index 5915d51f2b..1bc0210b72 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
@@ -160,10 +160,7 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const
\list
\li glDepthMask(false)
\li glDisable(GL_DEPTH_TEST)
- \li glStencilMask(0)
- \li glEnable(GL_STENCIL_TEST)/glDisable(GL_STENCIL_TEST) depending on clip
\li glStencilFunc(GL_EQUAL, state.stencilValue, 0xff) depending on clip
- \li glEnable(GL_SCISSOR_TEST)/glDisable(GL_SCISSOR_TEST) depending on clip
\li glScissor(state.scissorRect.x(), state.scissorRect.y(),
state.scissorRect.width(), state.scissorRect.height()) depending on clip
\li glEnable(GL_BLEND)
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index 2c5b4ff5c8..aaf4635c0c 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -260,7 +260,7 @@ void QSGDefaultRenderContext::compileShader(QSGMaterialShader *shader, QSGMateri
if (vertexCode || fragmentCode) {
Q_ASSERT_X((material->flags() & QSGMaterial::CustomCompileStep) == 0,
"QSGRenderContext::compile()",
- "materials with custom compile step cannot have custom vertex/fragment code");
+ "materials with custom compile step cannot have modified vertex or fragment code");
QOpenGLShaderProgram *p = shader->program();
p->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexCode ? vertexCode : shader->vertexShader());
p->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragmentCode ? fragmentCode : shader->fragmentShader());
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index 47248f2f37..d761eac62f 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -251,11 +251,15 @@ static void qt_debug_remove_texture(QSGTexture* texture)
Specifies how the texture should treat texture coordinates.
- \value Repeat Only the factional part of the texture coordiante is
+ \value Repeat Only the fractional part of the texture coordinate is
used, causing values above 1 and below 0 to repeat.
\value ClampToEdge Values above 1 are clamped to 1 and values
below 0 are clamped to 0.
+
+ \value MirroredRepeat When the texture coordinate is even, only the
+ fractional part is used. When odd, the texture coordinate is set to
+ \c{1 - fractional part}. This value has been introduced in Qt 5.10.
*/
/*!
@@ -550,7 +554,9 @@ void QSGTexture::updateBindOptions(bool force)
if (force || d->wrapChanged) {
#ifndef QT_NO_DEBUG
- if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat) {
+ if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat
+ || d->horizontalWrap == MirroredRepeat || d->verticalWrap == MirroredRepeat)
+ {
bool npotSupported = QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::NPOTTextures);
QSize size = textureSize();
bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
@@ -558,8 +564,18 @@ void QSGTexture::updateBindOptions(bool force)
qWarning("Scene Graph: This system does not support the REPEAT wrap mode for non-power-of-two textures.");
}
#endif
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, d->horizontalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, d->verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
+ GLenum wrapS = GL_CLAMP_TO_EDGE;
+ if (d->horizontalWrap == Repeat)
+ wrapS = GL_REPEAT;
+ else if (d->horizontalWrap == MirroredRepeat)
+ wrapS = GL_MIRRORED_REPEAT;
+ GLenum wrapT = GL_CLAMP_TO_EDGE;
+ if (d->verticalWrap == Repeat)
+ wrapT = GL_REPEAT;
+ else if (d->verticalWrap == MirroredRepeat)
+ wrapT = GL_MIRRORED_REPEAT;
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
d->wrapChanged = false;
}
#else
diff --git a/src/quick/scenegraph/util/qsgtexture.h b/src/quick/scenegraph/util/qsgtexture.h
index f0509b58ae..2b29525efd 100644
--- a/src/quick/scenegraph/util/qsgtexture.h
+++ b/src/quick/scenegraph/util/qsgtexture.h
@@ -58,7 +58,8 @@ public:
enum WrapMode {
Repeat,
- ClampToEdge
+ ClampToEdge,
+ MirroredRepeat
};
enum Filtering {
diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h
index b6fcfc31c4..3a10d85b4d 100644
--- a/src/quick/scenegraph/util/qsgtexture_p.h
+++ b/src/quick/scenegraph/util/qsgtexture_p.h
@@ -70,8 +70,8 @@ public:
uint wrapChanged : 1;
uint filteringChanged : 1;
- uint horizontalWrap : 1;
- uint verticalWrap : 1;
+ uint horizontalWrap : 2;
+ uint verticalWrap : 2;
uint mipmapMode : 2;
uint filterMode : 2;
};
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index 9326ea640d..fcafbba6a2 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -278,7 +278,7 @@ void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture)
Returns this material's horizontal wrap mode.
- The default horizontal wrap mode is \c QSGTexutre::ClampToEdge.
+ The default horizontal wrap mode is \c QSGTexture::ClampToEdge.
*/
@@ -299,7 +299,7 @@ void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture)
Returns this material's vertical wrap mode.
- The default vertical wrap mode is \c QSGTexutre::ClampToEdge.
+ The default vertical wrap mode is \c QSGTexture::ClampToEdge.
*/
diff --git a/src/quick/util/qquicknvprfunctions.cpp b/src/quick/util/qquicknvprfunctions.cpp
new file mode 100644
index 0000000000..40eb2bb932
--- /dev/null
+++ b/src/quick/util/qquicknvprfunctions.cpp
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** 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 "qquicknvprfunctions_p.h"
+
+#ifndef QT_NO_OPENGL
+
+#include <QOpenGLContext>
+#include <QOffscreenSurface>
+#include <QOpenGLExtraFunctions>
+#include "qquicknvprfunctions_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQuickNvprFunctions
+
+ \brief Function resolvers and other helpers for GL_NV_path_rendering
+ for both desktop (GL 4.3+) and mobile/embedded (GLES 3.1+) in a manner
+ that does not distract builds that do not have NVPR support either at
+ compile or run time.
+
+ \internal
+ */
+
+QQuickNvprFunctions::QQuickNvprFunctions()
+ : d(new QQuickNvprFunctionsPrivate(this))
+{
+}
+
+QQuickNvprFunctions::~QQuickNvprFunctions()
+{
+ delete d;
+}
+
+/*!
+ \return a recommended QSurfaceFormat suitable for GL_NV_path_rendering on top
+ of OpenGL 4.3 or OpenGL ES 3.1.
+ */
+QSurfaceFormat QQuickNvprFunctions::format()
+{
+ QSurfaceFormat fmt;
+ fmt.setDepthBufferSize(24);
+ fmt.setStencilBufferSize(8);
+ if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
+ fmt.setVersion(4, 3);
+ fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
+ } else if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
+ fmt.setVersion(3, 1);
+ }
+ return fmt;
+}
+
+/*!
+ \return true if GL_NV_path_rendering is supported with the current OpenGL
+ context.
+
+ When there is no current context, a temporary dummy one will be created and
+ made current.
+ */
+bool QQuickNvprFunctions::isSupported()
+{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QScopedPointer<QOpenGLContext> tempContext;
+ QScopedPointer<QOffscreenSurface> tempSurface;
+ if (!ctx) {
+ tempContext.reset(new QOpenGLContext);
+ if (!tempContext->create())
+ return false;
+ ctx = tempContext.data();
+ tempSurface.reset(new QOffscreenSurface);
+ tempSurface->setFormat(ctx->format());
+ tempSurface->create();
+ if (!ctx->makeCurrent(tempSurface.data()))
+ return false;
+ }
+
+ if (!ctx->hasExtension(QByteArrayLiteral("GL_NV_path_rendering")))
+ return false;
+
+ // Do not check for DSA as the string may not be exposed on ES
+ // drivers, yet the functions we need are resolvable.
+#if 0
+ if (!ctx->hasExtension(QByteArrayLiteral("GL_EXT_direct_state_access"))) {
+ qWarning("QtQuickPath/NVPR: GL_EXT_direct_state_access not supported");
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+/*!
+ Initializes using the current OpenGL context.
+
+ \return true when GL_NV_path_rendering is supported and initialization was
+ successful.
+ */
+bool QQuickNvprFunctions::create()
+{
+ return isSupported() && d->resolve();
+}
+
+/*!
+ Creates a program pipeline consisting of a separable fragment shader program.
+
+ This is essential for using NVPR with OpenGL ES 3.1+ since normal,
+ GLES2-style programs would not work without a vertex shader.
+
+ \note \a fragmentShaderSource should be a \c{version 310 es} shader since
+ this works both on desktop and embedded NVIDIA drivers, thus avoiding the
+ need to fight GLSL and GLSL ES differences.
+
+ The pipeline object is stored into \a pipeline, the fragment shader program
+ into \a program.
+
+ Use QOpenGLExtraFunctions to set uniforms, bind the pipeline, etc.
+
+ \return \c false on failure in which case the error log is printed on the
+ debug output. \c true on success.
+ */
+bool QQuickNvprFunctions::createFragmentOnlyPipeline(const char *fragmentShaderSource, GLuint *pipeline, GLuint *program)
+{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (!ctx)
+ return false;
+
+ QOpenGLExtraFunctions *f = ctx->extraFunctions();
+ *program = f->glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragmentShaderSource);
+ GLint status = 0;
+ f->glGetProgramiv(*program, GL_LINK_STATUS, &status);
+ if (!status) {
+ GLint len = 0;
+ f->glGetProgramiv(*program, GL_INFO_LOG_LENGTH, &len);
+ if (len) {
+ QByteArray s;
+ s.resize(len);
+ f->glGetProgramInfoLog(*program, s.count(), nullptr, s.data());
+ qWarning("Failed to create separable shader program:\n%s", s.constData());
+ }
+ return false;
+ }
+
+ f->glGenProgramPipelines(1, pipeline);
+ f->glUseProgramStages(*pipeline, GL_FRAGMENT_SHADER_BIT, *program);
+ f->glActiveShaderProgram(*pipeline, *program);
+
+ f->glValidateProgramPipeline(*pipeline);
+ status = 0;
+ f->glGetProgramPipelineiv(*pipeline, GL_VALIDATE_STATUS, &status);
+ if (!status) {
+ GLint len = 0;
+ f->glGetProgramPipelineiv(*pipeline, GL_INFO_LOG_LENGTH, &len);
+ if (len) {
+ QByteArray s;
+ s.resize(len);
+ f->glGetProgramPipelineInfoLog(*pipeline, s.count(), nullptr, s.data());
+ qWarning("Program pipeline validation failed:\n%s", s.constData());
+ }
+ return false;
+ }
+
+ return true;
+}
+
+#define PROC(type, name) reinterpret_cast<type>(ctx->getProcAddress(#name))
+
+bool QQuickNvprFunctionsPrivate::resolve()
+{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+
+ q->genPaths = PROC(PFNGLGENPATHSNVPROC, glGenPathsNV);
+ q->deletePaths = PROC(PFNGLDELETEPATHSNVPROC, glDeletePathsNV);
+ q->isPath = PROC(PFNGLISPATHNVPROC, glIsPathNV);
+ q->pathCommands = PROC(PFNGLPATHCOMMANDSNVPROC, glPathCommandsNV);
+ q->pathCoords = PROC(PFNGLPATHCOORDSNVPROC, glPathCoordsNV);
+ q->pathSubCommands = PROC(PFNGLPATHSUBCOMMANDSNVPROC, glPathSubCommandsNV);
+ q->pathSubCoords = PROC(PFNGLPATHSUBCOORDSNVPROC, glPathSubCoordsNV);
+ q->pathString = PROC(PFNGLPATHSTRINGNVPROC, glPathStringNV);
+ q->pathGlyphs = PROC(PFNGLPATHGLYPHSNVPROC, glPathGlyphsNV);
+ q->pathGlyphRange = PROC(PFNGLPATHGLYPHRANGENVPROC, glPathGlyphRangeNV);
+ q->weightPaths = PROC(PFNGLWEIGHTPATHSNVPROC, glWeightPathsNV);
+ q->copyPath = PROC(PFNGLCOPYPATHNVPROC, glCopyPathNV);
+ q->interpolatePaths = PROC(PFNGLINTERPOLATEPATHSNVPROC, glInterpolatePathsNV);
+ q->transformPath = PROC(PFNGLTRANSFORMPATHNVPROC, glTransformPathNV);
+ q->pathParameteriv = PROC(PFNGLPATHPARAMETERIVNVPROC, glPathParameterivNV);
+ q->pathParameteri = PROC(PFNGLPATHPARAMETERINVPROC, glPathParameteriNV);
+ q->pathParameterfv = PROC(PFNGLPATHPARAMETERFVNVPROC, glPathParameterfvNV);
+ q->pathParameterf = PROC(PFNGLPATHPARAMETERFNVPROC, glPathParameterfNV);
+ q->pathDashArray = PROC(PFNGLPATHDASHARRAYNVPROC, glPathDashArrayNV);
+ q->pathStencilFunc = PROC(PFNGLPATHSTENCILFUNCNVPROC, glPathStencilFuncNV);
+ q->pathStencilDepthOffset = PROC(PFNGLPATHSTENCILDEPTHOFFSETNVPROC, glPathStencilDepthOffsetNV);
+ q->stencilFillPath = PROC(PFNGLSTENCILFILLPATHNVPROC, glStencilFillPathNV);
+ q->stencilStrokePath = PROC(PFNGLSTENCILSTROKEPATHNVPROC, glStencilStrokePathNV);
+ q->stencilFillPathInstanced = PROC(PFNGLSTENCILFILLPATHINSTANCEDNVPROC, glStencilFillPathInstancedNV);
+ q->stencilStrokePathInstanced = PROC(PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC, glStencilStrokePathInstancedNV);
+ q->pathCoverDepthFunc = PROC(PFNGLPATHCOVERDEPTHFUNCNVPROC, glPathCoverDepthFuncNV);
+ q->pathColorGen = PROC(PFNGLPATHCOLORGENNVPROC, glPathColorGenNV);
+ q->pathTexGen = PROC(PFNGLPATHTEXGENNVPROC, glPathTexGenNV);
+ q->pathFogGen = PROC(PFNGLPATHFOGGENNVPROC, glPathFogGenNV);
+ q->coverFillPath = PROC(PFNGLCOVERFILLPATHNVPROC, glCoverFillPathNV);
+ q->coverStrokePath = PROC(PFNGLCOVERSTROKEPATHNVPROC, glCoverStrokePathNV);
+ q->coverFillPathInstanced = PROC(PFNGLCOVERFILLPATHINSTANCEDNVPROC, glCoverFillPathInstancedNV);
+ q->coverStrokePathInstanced = PROC(PFNGLCOVERSTROKEPATHINSTANCEDNVPROC, glCoverStrokePathInstancedNV);
+ q->getPathParameteriv = PROC(PFNGLGETPATHPARAMETERIVNVPROC, glGetPathParameterivNV);
+ q->getPathParameterfv = PROC(PFNGLGETPATHPARAMETERFVNVPROC, glGetPathParameterfvNV);
+ q->getPathCommands = PROC(PFNGLGETPATHCOMMANDSNVPROC, glGetPathCommandsNV);
+ q->getPathCoords = PROC(PFNGLGETPATHCOORDSNVPROC, glGetPathCoordsNV);
+ q->getPathDashArray = PROC(PFNGLGETPATHDASHARRAYNVPROC, glGetPathDashArrayNV);
+ q->getPathMetrics = PROC(PFNGLGETPATHMETRICSNVPROC, glGetPathMetricsNV);
+ q->getPathMetricRange = PROC(PFNGLGETPATHMETRICRANGENVPROC, glGetPathMetricRangeNV);
+ q->getPathSpacing = PROC(PFNGLGETPATHSPACINGNVPROC, glGetPathSpacingNV);
+ q->getPathColorgeniv = PROC(PFNGLGETPATHCOLORGENIVNVPROC, glGetPathColorGenivNV);
+ q->getPathColorgenfv = PROC(PFNGLGETPATHCOLORGENFVNVPROC, glGetPathColorGenfvNV);
+ q->getPathTexGeniv = PROC(PFNGLGETPATHTEXGENIVNVPROC, glGetPathTexGenivNV);
+ q->getPathTexGenfv = PROC(PFNGLGETPATHTEXGENFVNVPROC, glGetPathTexGenfvNV);
+ q->isPointInFillPath = PROC(PFNGLISPOINTINFILLPATHNVPROC, glIsPointInFillPathNV);
+ q->isPointInStrokePath = PROC(PFNGLISPOINTINSTROKEPATHNVPROC, glIsPointInStrokePathNV);
+ q->getPathLength = PROC(PFNGLGETPATHLENGTHNVPROC, glGetPathLengthNV);
+ q->getPointAlongPath = PROC(PFNGLPOINTALONGPATHNVPROC, glPointAlongPathNV);
+ q->matrixLoad3x2f = PROC(PFNGLMATRIXLOAD3X2FNVPROC, glMatrixLoad3x2fNV);
+ q->matrixLoad3x3f = PROC(PFNGLMATRIXLOAD3X3FNVPROC, glMatrixLoad3x3fNV);
+ q->matrixLoadTranspose3x3f = PROC(PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC, glMatrixLoadTranspose3x3fNV);
+ q->matrixMult3x2f = PROC(PFNGLMATRIXMULT3X2FNVPROC, glMatrixMult3x2fNV);
+ q->matrixMult3x3f = PROC(PFNGLMATRIXMULT3X3FNVPROC, glMatrixMult3x3fNV);
+ q->matrixMultTranspose3x3f = PROC(PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC, glMatrixMultTranspose3x3fNV);
+ q->stencilThenCoverFillPath = PROC(PFNGLSTENCILTHENCOVERFILLPATHNVPROC, glStencilThenCoverFillPathNV);
+ q->stencilThenCoverStrokePath = PROC(PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC, glStencilThenCoverStrokePathNV);
+ q->stencilThenCoverFillPathInstanced = PROC(PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC, glStencilThenCoverFillPathInstancedNV);
+ q->stencilThenCoverStrokePathInstanced = PROC(PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC, glStencilThenCoverStrokePathInstancedNV);
+ q->pathGlyphIndexRange = PROC(PFNGLPATHGLYPHINDEXRANGENVPROC, glPathGlyphIndexRangeNV);
+ q->pathGlyphIndexArray = PROC(PFNGLPATHGLYPHINDEXARRAYNVPROC, glPathGlyphIndexArrayNV);
+ q->pathMemoryGlyphIndexArray = PROC(PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC, glPathMemoryGlyphIndexArrayNV);
+ q->programPathFragmentInputGen = PROC(PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC, glProgramPathFragmentInputGenNV);
+ q->getProgramResourcefv = PROC(PFNGLGETPROGRAMRESOURCEFVNVPROC, glGetProgramResourcefvNV);
+
+ q->matrixLoadf = PROC(PFNGLMATRIXLOADFEXTPROC, glMatrixLoadfEXT);
+ q->matrixLoadIdentity = PROC(PFNGLMATRIXLOADIDENTITYEXTPROC, glMatrixLoadIdentityEXT);
+
+ return q->genPaths != nullptr // base path rendering ext
+ && q->programPathFragmentInputGen != nullptr // updated path rendering ext
+ && q->matrixLoadf != nullptr // direct state access ext
+ && q->matrixLoadIdentity != nullptr;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_OPENGL
diff --git a/src/quick/util/qquicknvprfunctions_p.h b/src/quick/util/qquicknvprfunctions_p.h
new file mode 100644
index 0000000000..7900388305
--- /dev/null
+++ b/src/quick/util/qquicknvprfunctions_p.h
@@ -0,0 +1,406 @@
+/****************************************************************************
+**
+** 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 QQUICKNVPRFUNCTIONS_P_H
+#define QQUICKNVPRFUNCTIONS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qopengl.h>
+#include <QtGui/qsurfaceformat.h>
+
+#ifndef QT_NO_OPENGL
+
+QT_BEGIN_NAMESPACE
+
+#ifndef GL_NV_path_rendering
+#define GL_PATH_FORMAT_SVG_NV 0x9070
+#define GL_PATH_FORMAT_PS_NV 0x9071
+#define GL_STANDARD_FONT_NAME_NV 0x9072
+#define GL_SYSTEM_FONT_NAME_NV 0x9073
+#define GL_FILE_NAME_NV 0x9074
+#define GL_PATH_STROKE_WIDTH_NV 0x9075
+#define GL_PATH_END_CAPS_NV 0x9076
+#define GL_PATH_INITIAL_END_CAP_NV 0x9077
+#define GL_PATH_TERMINAL_END_CAP_NV 0x9078
+#define GL_PATH_JOIN_STYLE_NV 0x9079
+#define GL_PATH_MITER_LIMIT_NV 0x907A
+#define GL_PATH_DASH_CAPS_NV 0x907B
+#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C
+#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D
+#define GL_PATH_DASH_OFFSET_NV 0x907E
+#define GL_PATH_CLIENT_LENGTH_NV 0x907F
+#define GL_PATH_FILL_MODE_NV 0x9080
+#define GL_PATH_FILL_MASK_NV 0x9081
+#define GL_PATH_FILL_COVER_MODE_NV 0x9082
+#define GL_PATH_STROKE_COVER_MODE_NV 0x9083
+#define GL_PATH_STROKE_MASK_NV 0x9084
+#define GL_COUNT_UP_NV 0x9088
+#define GL_COUNT_DOWN_NV 0x9089
+#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A
+#define GL_CONVEX_HULL_NV 0x908B
+#define GL_BOUNDING_BOX_NV 0x908D
+#define GL_TRANSLATE_X_NV 0x908E
+#define GL_TRANSLATE_Y_NV 0x908F
+#define GL_TRANSLATE_2D_NV 0x9090
+#define GL_TRANSLATE_3D_NV 0x9091
+#define GL_AFFINE_2D_NV 0x9092
+#define GL_AFFINE_3D_NV 0x9094
+#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096
+#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098
+#define GL_UTF8_NV 0x909A
+#define GL_UTF16_NV 0x909B
+#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C
+#define GL_PATH_COMMAND_COUNT_NV 0x909D
+#define GL_PATH_COORD_COUNT_NV 0x909E
+#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F
+#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0
+#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1
+#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2
+#define GL_SQUARE_NV 0x90A3
+#define GL_ROUND_NV 0x90A4
+#define GL_TRIANGULAR_NV 0x90A5
+#define GL_BEVEL_NV 0x90A6
+#define GL_MITER_REVERT_NV 0x90A7
+#define GL_MITER_TRUNCATE_NV 0x90A8
+#define GL_SKIP_MISSING_GLYPH_NV 0x90A9
+#define GL_USE_MISSING_GLYPH_NV 0x90AA
+#define GL_PATH_ERROR_POSITION_NV 0x90AB
+#define GL_PATH_FOG_GEN_MODE_NV 0x90AC
+#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD
+#define GL_ADJACENT_PAIRS_NV 0x90AE
+#define GL_FIRST_TO_REST_NV 0x90AF
+#define GL_PATH_GEN_MODE_NV 0x90B0
+#define GL_PATH_GEN_COEFF_NV 0x90B1
+#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2
+#define GL_PATH_GEN_COMPONENTS_NV 0x90B3
+#define GL_PATH_STENCIL_FUNC_NV 0x90B7
+#define GL_PATH_STENCIL_REF_NV 0x90B8
+#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9
+#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD
+#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE
+#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF
+#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4
+#define GL_MOVE_TO_RESETS_NV 0x90B5
+#define GL_MOVE_TO_CONTINUES_NV 0x90B6
+#define GL_CLOSE_PATH_NV 0x00
+#define GL_MOVE_TO_NV 0x02
+#define GL_RELATIVE_MOVE_TO_NV 0x03
+#define GL_LINE_TO_NV 0x04
+#define GL_RELATIVE_LINE_TO_NV 0x05
+#define GL_HORIZONTAL_LINE_TO_NV 0x06
+#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07
+#define GL_VERTICAL_LINE_TO_NV 0x08
+#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09
+#define GL_QUADRATIC_CURVE_TO_NV 0x0A
+#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B
+#define GL_CUBIC_CURVE_TO_NV 0x0C
+#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D
+#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E
+#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F
+#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10
+#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11
+#define GL_SMALL_CCW_ARC_TO_NV 0x12
+#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13
+#define GL_SMALL_CW_ARC_TO_NV 0x14
+#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15
+#define GL_LARGE_CCW_ARC_TO_NV 0x16
+#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17
+#define GL_LARGE_CW_ARC_TO_NV 0x18
+#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19
+#define GL_RESTART_PATH_NV 0xF0
+#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2
+#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4
+#define GL_RECT_NV 0xF6
+#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8
+#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA
+#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC
+#define GL_ARC_TO_NV 0xFE
+#define GL_RELATIVE_ARC_TO_NV 0xFF
+#define GL_BOLD_BIT_NV 0x01
+#define GL_ITALIC_BIT_NV 0x02
+#define GL_GLYPH_WIDTH_BIT_NV 0x01
+#define GL_GLYPH_HEIGHT_BIT_NV 0x02
+#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04
+#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08
+#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10
+#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20
+#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40
+#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80
+#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100
+#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000
+#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000
+#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000
+#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000
+#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000
+#define GL_FONT_ASCENDER_BIT_NV 0x00200000
+#define GL_FONT_DESCENDER_BIT_NV 0x00400000
+#define GL_FONT_HEIGHT_BIT_NV 0x00800000
+#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000
+#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000
+#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000
+#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000
+#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000
+#define GL_PRIMARY_COLOR_NV 0x852C
+#define GL_SECONDARY_COLOR_NV 0x852D
+#define GL_ROUNDED_RECT_NV 0xE8
+#define GL_RELATIVE_ROUNDED_RECT_NV 0xE9
+#define GL_ROUNDED_RECT2_NV 0xEA
+#define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB
+#define GL_ROUNDED_RECT4_NV 0xEC
+#define GL_RELATIVE_ROUNDED_RECT4_NV 0xED
+#define GL_ROUNDED_RECT8_NV 0xEE
+#define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF
+#define GL_RELATIVE_RECT_NV 0xF7
+#define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368
+#define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369
+#define GL_FONT_UNAVAILABLE_NV 0x936A
+#define GL_FONT_UNINTELLIGIBLE_NV 0x936B
+#define GL_CONIC_CURVE_TO_NV 0x1A
+#define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B
+#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000
+#define GL_STANDARD_FONT_FORMAT_NV 0x936C
+#define GL_2_BYTES_NV 0x1407
+#define GL_3_BYTES_NV 0x1408
+#define GL_4_BYTES_NV 0x1409
+#define GL_EYE_LINEAR_NV 0x2400
+#define GL_OBJECT_LINEAR_NV 0x2401
+#define GL_CONSTANT_NV 0x8576
+#define GL_PATH_PROJECTION_NV 0x1701
+#define GL_PATH_MODELVIEW_NV 0x1700
+#define GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3
+#define GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6
+#define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36
+#define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3
+#define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4
+#define GL_PATH_PROJECTION_MATRIX_NV 0x0BA7
+#define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38
+#define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4
+#define GL_FRAGMENT_INPUT_NV 0x936D
+
+typedef GLuint (QOPENGLF_APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range);
+typedef void (QOPENGLF_APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range);
+typedef GLboolean (QOPENGLF_APIENTRYP PFNGLISPATHNVPROC) (GLuint path);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef void (QOPENGLF_APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights);
+typedef void (QOPENGLF_APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath);
+typedef void (QOPENGLF_APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight);
+typedef void (QOPENGLF_APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units);
+typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask);
+typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask);
+typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs);
+typedef void (QOPENGLF_APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode);
+typedef void (QOPENGLF_APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode);
+typedef void (QOPENGLF_APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode);
+typedef void (QOPENGLF_APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (QOPENGLF_APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value);
+typedef GLboolean (QOPENGLF_APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y);
+typedef GLboolean (QOPENGLF_APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y);
+typedef GLfloat (QOPENGLF_APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments);
+typedef GLboolean (QOPENGLF_APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY);
+typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);
+typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode);
+typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode);
+typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);
+typedef GLenum (QOPENGLF_APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]);
+typedef GLenum (QOPENGLF_APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef GLenum (QOPENGLF_APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);
+typedef void (QOPENGLF_APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs);
+typedef void (QOPENGLF_APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params);
+#endif
+
+#ifndef GL_FLAT
+#define GL_FLAT 0x1D00
+#endif
+
+#ifndef GL_INVERT
+#define GL_INVERT 0x150A
+#endif
+
+#ifndef GL_EXT_direct_state_access
+typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m);
+typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode);
+#endif
+
+// When building on a system with GLES 2.0 or 3.0, we may still compile the NVPR
+// code path even though it's never used. Keep it compiling by defining the
+// necessary ES 3.1 separable program constants.
+#ifndef GL_FRAGMENT_SHADER_BIT
+#define GL_FRAGMENT_SHADER_BIT 0x00000002
+#endif
+#ifndef GL_UNIFORM
+#define GL_UNIFORM 0x92E1
+#endif
+
+class QQuickNvprFunctionsPrivate;
+
+class QQuickNvprFunctions
+{
+public:
+ QQuickNvprFunctions();
+ ~QQuickNvprFunctions();
+
+ static QSurfaceFormat format();
+ static bool isSupported();
+
+ bool create();
+
+ bool createFragmentOnlyPipeline(const char *fragmentShaderSource, GLuint *pipeline, GLuint *program);
+
+ PFNGLGENPATHSNVPROC genPaths = nullptr;
+ PFNGLDELETEPATHSNVPROC deletePaths = nullptr;
+ PFNGLISPATHNVPROC isPath = nullptr;
+ PFNGLPATHCOMMANDSNVPROC pathCommands = nullptr;
+ PFNGLPATHCOORDSNVPROC pathCoords = nullptr;
+ PFNGLPATHSUBCOMMANDSNVPROC pathSubCommands = nullptr;
+ PFNGLPATHSUBCOORDSNVPROC pathSubCoords = nullptr;
+ PFNGLPATHSTRINGNVPROC pathString = nullptr;
+ PFNGLPATHGLYPHSNVPROC pathGlyphs = nullptr;
+ PFNGLPATHGLYPHRANGENVPROC pathGlyphRange = nullptr;
+ PFNGLWEIGHTPATHSNVPROC weightPaths = nullptr;
+ PFNGLCOPYPATHNVPROC copyPath = nullptr;
+ PFNGLINTERPOLATEPATHSNVPROC interpolatePaths = nullptr;
+ PFNGLTRANSFORMPATHNVPROC transformPath = nullptr;
+ PFNGLPATHPARAMETERIVNVPROC pathParameteriv = nullptr;
+ PFNGLPATHPARAMETERINVPROC pathParameteri = nullptr;
+ PFNGLPATHPARAMETERFVNVPROC pathParameterfv = nullptr;
+ PFNGLPATHPARAMETERFNVPROC pathParameterf = nullptr;
+ PFNGLPATHDASHARRAYNVPROC pathDashArray = nullptr;
+ PFNGLPATHSTENCILFUNCNVPROC pathStencilFunc = nullptr;
+ PFNGLPATHSTENCILDEPTHOFFSETNVPROC pathStencilDepthOffset = nullptr;
+ PFNGLSTENCILFILLPATHNVPROC stencilFillPath = nullptr;
+ PFNGLSTENCILSTROKEPATHNVPROC stencilStrokePath = nullptr;
+ PFNGLSTENCILFILLPATHINSTANCEDNVPROC stencilFillPathInstanced = nullptr;
+ PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC stencilStrokePathInstanced = nullptr;
+ PFNGLPATHCOVERDEPTHFUNCNVPROC pathCoverDepthFunc = nullptr;
+ PFNGLPATHCOLORGENNVPROC pathColorGen = nullptr;
+ PFNGLPATHTEXGENNVPROC pathTexGen = nullptr;
+ PFNGLPATHFOGGENNVPROC pathFogGen = nullptr;
+ PFNGLCOVERFILLPATHNVPROC coverFillPath = nullptr;
+ PFNGLCOVERSTROKEPATHNVPROC coverStrokePath = nullptr;
+ PFNGLCOVERFILLPATHINSTANCEDNVPROC coverFillPathInstanced = nullptr;
+ PFNGLCOVERSTROKEPATHINSTANCEDNVPROC coverStrokePathInstanced = nullptr;
+ PFNGLGETPATHPARAMETERIVNVPROC getPathParameteriv = nullptr;
+ PFNGLGETPATHPARAMETERFVNVPROC getPathParameterfv = nullptr;
+ PFNGLGETPATHCOMMANDSNVPROC getPathCommands = nullptr;
+ PFNGLGETPATHCOORDSNVPROC getPathCoords = nullptr;
+ PFNGLGETPATHDASHARRAYNVPROC getPathDashArray = nullptr;
+ PFNGLGETPATHMETRICSNVPROC getPathMetrics = nullptr;
+ PFNGLGETPATHMETRICRANGENVPROC getPathMetricRange = nullptr;
+ PFNGLGETPATHSPACINGNVPROC getPathSpacing = nullptr;
+ PFNGLGETPATHCOLORGENIVNVPROC getPathColorgeniv = nullptr;
+ PFNGLGETPATHCOLORGENFVNVPROC getPathColorgenfv = nullptr;
+ PFNGLGETPATHTEXGENIVNVPROC getPathTexGeniv = nullptr;
+ PFNGLGETPATHTEXGENFVNVPROC getPathTexGenfv = nullptr;
+ PFNGLISPOINTINFILLPATHNVPROC isPointInFillPath = nullptr;
+ PFNGLISPOINTINSTROKEPATHNVPROC isPointInStrokePath = nullptr;
+ PFNGLGETPATHLENGTHNVPROC getPathLength = nullptr;
+ PFNGLPOINTALONGPATHNVPROC getPointAlongPath = nullptr;
+ PFNGLMATRIXLOAD3X2FNVPROC matrixLoad3x2f = nullptr;
+ PFNGLMATRIXLOAD3X3FNVPROC matrixLoad3x3f = nullptr;
+ PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC matrixLoadTranspose3x3f = nullptr;
+ PFNGLMATRIXMULT3X2FNVPROC matrixMult3x2f = nullptr;
+ PFNGLMATRIXMULT3X3FNVPROC matrixMult3x3f = nullptr;
+ PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC matrixMultTranspose3x3f = nullptr;
+ PFNGLSTENCILTHENCOVERFILLPATHNVPROC stencilThenCoverFillPath = nullptr;
+ PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC stencilThenCoverStrokePath = nullptr;
+ PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC stencilThenCoverFillPathInstanced = nullptr;
+ PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC stencilThenCoverStrokePathInstanced = nullptr;
+ PFNGLPATHGLYPHINDEXRANGENVPROC pathGlyphIndexRange = nullptr;
+ PFNGLPATHGLYPHINDEXARRAYNVPROC pathGlyphIndexArray = nullptr;
+ PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC pathMemoryGlyphIndexArray = nullptr;
+ PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC programPathFragmentInputGen = nullptr;
+ PFNGLGETPROGRAMRESOURCEFVNVPROC getProgramResourcefv = nullptr;
+
+ PFNGLMATRIXLOADFEXTPROC matrixLoadf = nullptr;
+ PFNGLMATRIXLOADIDENTITYEXTPROC matrixLoadIdentity = nullptr;
+
+private:
+ QQuickNvprFunctionsPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_OPENGL
+
+#endif // QQUICKNVPRFUNCTIONS_P_H
diff --git a/src/quick/util/qquicknvprfunctions_p_p.h b/src/quick/util/qquicknvprfunctions_p_p.h
new file mode 100644
index 0000000000..6df20566af
--- /dev/null
+++ b/src/quick/util/qquicknvprfunctions_p_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** 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 QQUICKNVPRFUNCTIONS_P_P_H
+#define QQUICKNVPRFUNCTIONS_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquicknvprfunctions_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickNvprFunctionsPrivate
+{
+public:
+ QQuickNvprFunctionsPrivate(QQuickNvprFunctions *q_ptr) : q(q_ptr) { }
+
+ bool resolve();
+
+ QQuickNvprFunctions *q;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKNVPRFUNCTIONS_P_P_H
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index 25a4433a9b..a6fa21d696 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE
\instantiates QQuickPath
\inqmlmodule QtQuick
\ingroup qtquick-animation-paths
- \brief Defines a path for use by \l PathView
+ \brief Defines a path for use by \l PathView and \l PathItem
A Path is composed of one or more path segments - PathLine, PathQuad,
PathCubic, PathArc, PathCurve, PathSvg.
@@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE
PathAttribute allows named attributes with values to be defined
along the path.
- \sa PathView, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic, PathArc, PathCurve, PathSvg
+ \sa PathView, PathItem, PathAttribute, PathPercent, PathLine, PathMove, PathQuad, PathCubic, PathArc, PathCurve, PathSvg
*/
QQuickPath::QQuickPath(QObject *parent)
: QObject(*(new QQuickPathPrivate), parent)
@@ -1017,7 +1017,7 @@ void QQuickPathAttribute::setValue(qreal value)
}
\endqml
- \sa Path, PathQuad, PathCubic, PathArc, PathCurve, PathSvg
+ \sa Path, PathQuad, PathCubic, PathArc, PathCurve, PathSvg, PathMove
*/
/*!
@@ -1060,6 +1060,66 @@ void QQuickPathLine::addToPath(QPainterPath &path, const QQuickPathData &data)
/****************************************************************************/
/*!
+ \qmltype PathMove
+ \instantiates QQuickPathMove
+ \inqmlmodule QtQuick
+ \ingroup qtquick-animation-paths
+ \brief Moves the Path's position
+
+ While not relevant with PathView, for Path elements used with PathItem it
+ is important to distinguish between the operations of drawing a straight
+ line and moving the path position without drawing anything.
+
+ \note PathMove should not be used in a Path associated with a PathView. Use
+ PathLine instead.
+
+ The example below creates a path consisting of two horizontal lines with
+ some empty space between them. All three segments have a width of 100:
+
+ \qml
+ Path {
+ startX: 0; startY: 100
+ PathLine { relativeX: 100; y: 100 }
+ PathMove { relativeX: 100; y: 100 }
+ PathLine { relativeX: 100; y: 100 }
+ }
+ \endqml
+
+ \sa Path, PathQuad, PathCubic, PathArc, PathCurve, PathSvg, PathLine
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathMove::x
+ \qmlproperty real QtQuick::PathMove::y
+
+ Defines the position to move to.
+
+ \sa relativeX, relativeY
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathMove::relativeX
+ \qmlproperty real QtQuick::PathMove::relativeY
+
+ Defines the position to move to relative to its start.
+
+ If both a relative and absolute end position are specified for a single axis, the relative
+ position will be used.
+
+ Relative and absolute positions can be mixed, for example it is valid to set a relative x
+ and an absolute y.
+
+ \sa x, y
+*/
+
+void QQuickPathMove::addToPath(QPainterPath &path, const QQuickPathData &data)
+{
+ path.moveTo(positionForCurve(data, path.currentPosition()));
+}
+
+/****************************************************************************/
+
+/*!
\qmltype PathQuad
\instantiates QQuickPathQuad
\inqmlmodule QtQuick
@@ -1655,6 +1715,7 @@ void QQuickPathArc::setRadiusX(qreal radius)
_radiusX = radius;
emit radiusXChanged();
+ emit changed();
}
qreal QQuickPathArc::radiusY() const
@@ -1669,6 +1730,7 @@ void QQuickPathArc::setRadiusY(qreal radius)
_radiusY = radius;
emit radiusYChanged();
+ emit changed();
}
/*!
@@ -1702,6 +1764,7 @@ void QQuickPathArc::setUseLargeArc(bool largeArc)
_useLargeArc = largeArc;
emit useLargeArcChanged();
+ emit changed();
}
/*!
@@ -1733,6 +1796,7 @@ void QQuickPathArc::setDirection(ArcDirection direction)
_direction = direction;
emit directionChanged();
+ emit changed();
}
void QQuickPathArc::addToPath(QPainterPath &path, const QQuickPathData &data)
diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h
index 06ad389b49..283283f377 100644
--- a/src/quick/util/qquickpath_p.h
+++ b/src/quick/util/qquickpath_p.h
@@ -159,6 +159,15 @@ public:
void addToPath(QPainterPath &path, const QQuickPathData &) override;
};
+class Q_QUICK_PRIVATE_EXPORT QQuickPathMove : public QQuickCurve
+{
+ Q_OBJECT
+public:
+ QQuickPathMove(QObject *parent=0) : QQuickCurve(parent) {}
+
+ void addToPath(QPainterPath &path, const QQuickPathData &) override;
+};
+
class Q_QUICK_PRIVATE_EXPORT QQuickPathQuad : public QQuickCurve
{
Q_OBJECT
@@ -459,6 +468,7 @@ QML_DECLARE_TYPE(QQuickPathElement)
QML_DECLARE_TYPE(QQuickPathAttribute)
QML_DECLARE_TYPE(QQuickCurve)
QML_DECLARE_TYPE(QQuickPathLine)
+QML_DECLARE_TYPE(QQuickPathMove)
QML_DECLARE_TYPE(QQuickPathQuad)
QML_DECLARE_TYPE(QQuickPathCubic)
QML_DECLARE_TYPE(QQuickPathCatmullRomCurve)
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index 1ef1018a31..22f23f7598 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -74,4 +74,11 @@ qtConfig(quick-path) {
$$PWD/qquickpath_p.h \
$$PWD/qquickpath_p_p.h \
$$PWD/qquickpathinterpolator_p.h
+ qtConfig(opengl) {
+ SOURCES += \
+ $$PWD/qquicknvprfunctions.cpp
+ HEADERS += \
+ $$PWD/qquicknvprfunctions_p.h \
+ $$PWD/qquicknvprfunctions_p_p.h
+ }
}