aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports
diff options
context:
space:
mode:
Diffstat (limited to 'src/imports')
-rw-r--r--src/imports/imports.pro2
-rw-r--r--src/imports/pathitem/pathitem.pro31
-rw-r--r--src/imports/pathitem/plugin.cpp74
-rw-r--r--src/imports/pathitem/plugins.qmltypes312
-rw-r--r--src/imports/pathitem/qmldir4
-rw-r--r--src/imports/pathitem/qquicknvprfunctions.cpp284
-rw-r--r--src/imports/pathitem/qquicknvprfunctions_p.h406
-rw-r--r--src/imports/pathitem/qquicknvprfunctions_p_p.h70
-rw-r--r--src/imports/pathitem/qquickpathitem.cpp2258
-rw-r--r--src/imports/pathitem/qquickpathitem_p.h333
-rw-r--r--src/imports/pathitem/qquickpathitem_p_p.h282
-rw-r--r--src/imports/pathitem/qquickpathitemgenericrenderer.cpp775
-rw-r--r--src/imports/pathitem/qquickpathitemgenericrenderer_p.h303
-rw-r--r--src/imports/pathitem/qquickpathitemnvprrenderer.cpp923
-rw-r--r--src/imports/pathitem/qquickpathitemnvprrenderer_p.h237
-rw-r--r--src/imports/pathitem/qquickpathitemsoftwarerenderer.cpp277
-rw-r--r--src/imports/pathitem/qquickpathitemsoftwarerenderer_p.h136
17 files changed, 6707 insertions, 0 deletions
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index c03224958c..df0ad01c06 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -22,6 +22,8 @@ qtHaveModule(quick) {
qtConfig(systemsemaphore): SUBDIRS += sharedimage
qtConfig(quick-particles): \
SUBDIRS += particles
+
+ SUBDIRS += pathitem
}
qtHaveModule(xmlpatterns) : SUBDIRS += xmllistmodel
diff --git a/src/imports/pathitem/pathitem.pro b/src/imports/pathitem/pathitem.pro
new file mode 100644
index 0000000000..d70bb6f203
--- /dev/null
+++ b/src/imports/pathitem/pathitem.pro
@@ -0,0 +1,31 @@
+CXX_MODULE = qml
+TARGET = qmlpathitemplugin
+TARGETPATH = Qt/labs/pathitem
+IMPORT_VERSION = 1.0
+
+QT = core gui qml quick quick-private
+
+HEADERS += \
+ qquickpathitem_p.h \
+ qquickpathitem_p_p.h \
+ qquickpathitemgenericrenderer_p.h \
+ qquickpathitemsoftwarerenderer_p.h
+
+SOURCES += \
+ plugin.cpp \
+ qquickpathitem.cpp \
+ qquickpathitemgenericrenderer.cpp \
+ qquickpathitemsoftwarerenderer.cpp
+
+qtConfig(opengl) {
+ HEADERS += \
+ qquicknvprfunctions_p.h \
+ qquicknvprfunctions_p_p.h \
+ qquickpathitemnvprrenderer_p.h
+
+ SOURCES += \
+ qquicknvprfunctions.cpp \
+ qquickpathitemnvprrenderer.cpp
+}
+
+load(qml_plugin)
diff --git a/src/imports/pathitem/plugin.cpp b/src/imports/pathitem/plugin.cpp
new file mode 100644
index 0000000000..6b43e8f398
--- /dev/null
+++ b/src/imports/pathitem/plugin.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
+
+#include "qquickpathitem_p.h"
+
+static void initResources()
+{
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(qmake_Qt_labs_pathitem);
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+class QmlPathItemPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QmlPathItemPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
+ void registerTypes(const char *uri) Q_DECL_OVERRIDE
+ {
+ Q_ASSERT(QByteArray(uri) == QByteArray("Qt.labs.pathitem"));
+ qmlRegisterType<QQuickPathItem>(uri, 1, 0, "PathItem");
+ qmlRegisterType<QQuickVisualPath>(uri, 1, 0, "VisualPath");
+ qmlRegisterType<QQuickPathGradientStop>(uri, 1, 0, "PathGradientStop");
+ qmlRegisterUncreatableType<QQuickPathGradient>(uri, 1, 0, "PathGradient", QQuickPathGradient::tr("PathGradient is an abstract base class"));
+ qmlRegisterType<QQuickPathLinearGradient>(uri, 1, 0, "PathLinearGradient");
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
diff --git a/src/imports/pathitem/plugins.qmltypes b/src/imports/pathitem/plugins.qmltypes
new file mode 100644
index 0000000000..03f26e243c
--- /dev/null
+++ b/src/imports/pathitem/plugins.qmltypes
@@ -0,0 +1,312 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable -noforceqtquick Qt.labs.pathitem 1.0'
+
+Module {
+ dependencies: []
+ Component {
+ name: "QQuickItem"
+ defaultProperty: "data"
+ prototype: "QObject"
+ Enum {
+ name: "TransformOrigin"
+ values: {
+ "TopLeft": 0,
+ "Top": 1,
+ "TopRight": 2,
+ "Left": 3,
+ "Center": 4,
+ "Right": 5,
+ "BottomLeft": 6,
+ "Bottom": 7,
+ "BottomRight": 8
+ }
+ }
+ Property { name: "parent"; type: "QQuickItem"; isPointer: true }
+ Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "resources"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "children"; type: "QQuickItem"; isList: true; isReadonly: true }
+ Property { name: "x"; type: "double" }
+ Property { name: "y"; type: "double" }
+ Property { name: "z"; type: "double" }
+ Property { name: "width"; type: "double" }
+ Property { name: "height"; type: "double" }
+ Property { name: "opacity"; type: "double" }
+ Property { name: "enabled"; type: "bool" }
+ Property { name: "visible"; type: "bool" }
+ Property { name: "visibleChildren"; type: "QQuickItem"; isList: true; isReadonly: true }
+ Property { name: "states"; type: "QQuickState"; isList: true; isReadonly: true }
+ Property { name: "transitions"; type: "QQuickTransition"; isList: true; isReadonly: true }
+ Property { name: "state"; type: "string" }
+ Property { name: "childrenRect"; type: "QRectF"; isReadonly: true }
+ Property { name: "anchors"; type: "QQuickAnchors"; isReadonly: true; isPointer: true }
+ Property { name: "left"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "right"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "horizontalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "top"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "bottom"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "verticalCenter"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "baseline"; type: "QQuickAnchorLine"; isReadonly: true }
+ Property { name: "baselineOffset"; type: "double" }
+ Property { name: "clip"; type: "bool" }
+ Property { name: "focus"; type: "bool" }
+ Property { name: "activeFocus"; type: "bool"; isReadonly: true }
+ Property { name: "activeFocusOnTab"; revision: 1; type: "bool" }
+ Property { name: "rotation"; type: "double" }
+ Property { name: "scale"; type: "double" }
+ Property { name: "transformOrigin"; type: "TransformOrigin" }
+ Property { name: "transformOriginPoint"; type: "QPointF"; isReadonly: true }
+ Property { name: "transform"; type: "QQuickTransform"; isList: true; isReadonly: true }
+ Property { name: "smooth"; type: "bool" }
+ Property { name: "antialiasing"; type: "bool" }
+ Property { name: "implicitWidth"; type: "double" }
+ Property { name: "implicitHeight"; type: "double" }
+ Property { name: "layer"; type: "QQuickItemLayer"; isReadonly: true; isPointer: true }
+ Signal {
+ name: "childrenRectChanged"
+ Parameter { type: "QRectF" }
+ }
+ Signal {
+ name: "baselineOffsetChanged"
+ Parameter { type: "double" }
+ }
+ Signal {
+ name: "stateChanged"
+ Parameter { type: "string" }
+ }
+ Signal {
+ name: "focusChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "activeFocusChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "activeFocusOnTabChanged"
+ revision: 1
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "parentChanged"
+ Parameter { type: "QQuickItem"; isPointer: true }
+ }
+ Signal {
+ name: "transformOriginChanged"
+ Parameter { type: "TransformOrigin" }
+ }
+ Signal {
+ name: "smoothChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "antialiasingChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "clipChanged"
+ Parameter { type: "bool" }
+ }
+ Signal {
+ name: "windowChanged"
+ revision: 1
+ Parameter { name: "window"; type: "QQuickWindow"; isPointer: true }
+ }
+ Method { name: "update" }
+ Method {
+ name: "grabToImage"
+ revision: 2
+ type: "bool"
+ Parameter { name: "callback"; type: "QJSValue" }
+ Parameter { name: "targetSize"; type: "QSize" }
+ }
+ Method {
+ name: "grabToImage"
+ revision: 2
+ type: "bool"
+ Parameter { name: "callback"; type: "QJSValue" }
+ }
+ Method {
+ name: "contains"
+ type: "bool"
+ Parameter { name: "point"; type: "QPointF" }
+ }
+ Method {
+ name: "mapFromItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "mapToItem"
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "mapFromGlobal"
+ revision: 7
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "mapToGlobal"
+ revision: 7
+ Parameter { type: "QQmlV4Function"; isPointer: true }
+ }
+ Method { name: "forceActiveFocus" }
+ Method {
+ name: "forceActiveFocus"
+ Parameter { name: "reason"; type: "Qt::FocusReason" }
+ }
+ Method {
+ name: "nextItemInFocusChain"
+ revision: 1
+ type: "QQuickItem*"
+ Parameter { name: "forward"; type: "bool" }
+ }
+ Method { name: "nextItemInFocusChain"; revision: 1; type: "QQuickItem*" }
+ Method {
+ name: "childAt"
+ type: "QQuickItem*"
+ Parameter { name: "x"; type: "double" }
+ Parameter { name: "y"; type: "double" }
+ }
+ }
+ Component {
+ name: "QQuickPathGradient"
+ defaultProperty: "stops"
+ prototype: "QObject"
+ exports: ["Qt.labs.pathitem/PathGradient 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "SpreadMode"
+ values: {
+ "PadSpread": 0,
+ "RepeatSpread": 1,
+ "ReflectSpread": 2
+ }
+ }
+ Property { name: "stops"; type: "QObject"; isList: true; isReadonly: true }
+ Property { name: "spread"; type: "SpreadMode" }
+ Signal { name: "updated" }
+ }
+ Component {
+ name: "QQuickPathGradientStop"
+ prototype: "QObject"
+ exports: ["Qt.labs.pathitem/PathGradientStop 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "position"; type: "double" }
+ Property { name: "color"; type: "QColor" }
+ }
+ Component {
+ name: "QQuickPathItem"
+ defaultProperty: "elements"
+ prototype: "QQuickItem"
+ exports: ["Qt.labs.pathitem/PathItem 1.0"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "RendererType"
+ values: {
+ "UnknownRenderer": 0,
+ "GeometryRenderer": 1,
+ "NvprRenderer": 2,
+ "SoftwareRenderer": 3
+ }
+ }
+ Enum {
+ name: "Status"
+ values: {
+ "Null": 0,
+ "Ready": 1,
+ "Processing": 2
+ }
+ }
+ Property { name: "renderer"; type: "RendererType"; isReadonly: true }
+ Property { name: "asynchronous"; type: "bool" }
+ Property { name: "enableVendorExtensions"; type: "bool" }
+ Property { name: "status"; type: "Status"; isReadonly: true }
+ Property { name: "elements"; type: "QQuickVisualPath"; isList: true; isReadonly: true }
+ Method {
+ name: "newPath"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "newStrokeFillParams"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "clearVisualPaths"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "commitVisualPaths"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ Method {
+ name: "appendVisualPath"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ }
+ Component {
+ name: "QQuickPathLinearGradient"
+ defaultProperty: "stops"
+ prototype: "QQuickPathGradient"
+ exports: ["Qt.labs.pathitem/PathLinearGradient 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "x1"; type: "double" }
+ Property { name: "y1"; type: "double" }
+ Property { name: "x2"; type: "double" }
+ Property { name: "y2"; type: "double" }
+ }
+ Component {
+ name: "QQuickVisualPath"
+ defaultProperty: "path"
+ prototype: "QObject"
+ exports: ["Qt.labs.pathitem/VisualPath 1.0"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "FillRule"
+ values: {
+ "OddEvenFill": 0,
+ "WindingFill": 1
+ }
+ }
+ Enum {
+ name: "JoinStyle"
+ values: {
+ "MiterJoin": 0,
+ "BevelJoin": 64,
+ "RoundJoin": 128
+ }
+ }
+ Enum {
+ name: "CapStyle"
+ values: {
+ "FlatCap": 0,
+ "SquareCap": 16,
+ "RoundCap": 32
+ }
+ }
+ Enum {
+ name: "StrokeStyle"
+ values: {
+ "SolidLine": 1,
+ "DashLine": 2
+ }
+ }
+ Property { name: "path"; type: "QQuickPath"; isPointer: true }
+ Property { name: "strokeColor"; type: "QColor" }
+ Property { name: "strokeWidth"; type: "double" }
+ Property { name: "fillColor"; type: "QColor" }
+ Property { name: "fillRule"; type: "FillRule" }
+ Property { name: "joinStyle"; type: "JoinStyle" }
+ Property { name: "miterLimit"; type: "int" }
+ Property { name: "capStyle"; type: "CapStyle" }
+ Property { name: "strokeStyle"; type: "StrokeStyle" }
+ Property { name: "dashOffset"; type: "double" }
+ Property { name: "dashPattern"; type: "QVector<qreal>" }
+ Property { name: "fillGradient"; type: "QQuickPathGradient"; isPointer: true }
+ Signal { name: "changed" }
+ }
+}
diff --git a/src/imports/pathitem/qmldir b/src/imports/pathitem/qmldir
new file mode 100644
index 0000000000..277b8a199b
--- /dev/null
+++ b/src/imports/pathitem/qmldir
@@ -0,0 +1,4 @@
+module Qt.labs.pathitem
+plugin qmlpathitemplugin
+classname QmlPathItemPlugin
+typeinfo plugins.qmltypes
diff --git a/src/imports/pathitem/qquicknvprfunctions.cpp b/src/imports/pathitem/qquicknvprfunctions.cpp
new file mode 100644
index 0000000000..40eb2bb932
--- /dev/null
+++ b/src/imports/pathitem/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/imports/pathitem/qquicknvprfunctions_p.h b/src/imports/pathitem/qquicknvprfunctions_p.h
new file mode 100644
index 0000000000..7900388305
--- /dev/null
+++ b/src/imports/pathitem/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/imports/pathitem/qquicknvprfunctions_p_p.h b/src/imports/pathitem/qquicknvprfunctions_p_p.h
new file mode 100644
index 0000000000..6df20566af
--- /dev/null
+++ b/src/imports/pathitem/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/imports/pathitem/qquickpathitem.cpp b/src/imports/pathitem/qquickpathitem.cpp
new file mode 100644
index 0000000000..5255a55798
--- /dev/null
+++ b/src/imports/pathitem/qquickpathitem.cpp
@@ -0,0 +1,2258 @@
+/****************************************************************************
+**
+** 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 <private/qquicksvgparser_p.h>
+#include <QtGui/private/qdrawhelper_p.h>
+#include <QOpenGLFunctions>
+
+#include <private/qv4engine_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4mm_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickPathItemStrokeFillParams::QQuickPathItemStrokeFillParams()
+ : strokeColor(Qt::white),
+ strokeWidth(1),
+ fillColor(Qt::white),
+ fillRule(QQuickVisualPath::OddEvenFill),
+ joinStyle(QQuickVisualPath::BevelJoin),
+ miterLimit(2),
+ capStyle(QQuickVisualPath::SquareCap),
+ strokeStyle(QQuickVisualPath::SolidLine),
+ dashOffset(0),
+ fillGradient(nullptr)
+{
+ dashPattern << 4 << 2; // 4 * strokeWidth dash followed by 2 * strokeWidth space
+}
+
+QPainterPath QQuickPathItemPath::toPainterPath() const
+{
+ QPainterPath p;
+ int coordIdx = 0;
+ for (int i = 0; i < cmd.count(); ++i) {
+ switch (cmd[i]) {
+ case QQuickPathItemPath::MoveTo:
+ p.moveTo(coords[coordIdx], coords[coordIdx + 1]);
+ coordIdx += 2;
+ break;
+ case QQuickPathItemPath::LineTo:
+ p.lineTo(coords[coordIdx], coords[coordIdx + 1]);
+ coordIdx += 2;
+ break;
+ case QQuickPathItemPath::QuadTo:
+ p.quadTo(coords[coordIdx], coords[coordIdx + 1],
+ coords[coordIdx + 2], coords[coordIdx + 3]);
+ coordIdx += 4;
+ break;
+ case QQuickPathItemPath::CubicTo:
+ p.cubicTo(coords[coordIdx], coords[coordIdx + 1],
+ coords[coordIdx + 2], coords[coordIdx + 3],
+ coords[coordIdx + 4], coords[coordIdx + 5]);
+ coordIdx += 6;
+ break;
+ case QQuickPathItemPath::ArcTo:
+ // does not map to the QPainterPath API; reuse the helper code from QQuickSvgParser
+ QQuickSvgParser::pathArc(p,
+ coords[coordIdx], coords[coordIdx + 1], // radius
+ coords[coordIdx + 2], // xAxisRotation
+ !qFuzzyIsNull(coords[coordIdx + 6]), // useLargeArc
+ !qFuzzyIsNull(coords[coordIdx + 5]), // sweep flag
+ coords[coordIdx + 3], coords[coordIdx + 4], // end
+ p.currentPosition().x(), p.currentPosition().y());
+ coordIdx += 7;
+ break;
+ default:
+ qWarning("Unknown JS path command: %d", cmd[i]);
+ break;
+ }
+ }
+ return p;
+}
+
+/*!
+ \qmltype VisualPath
+ \instantiates QQuickVisualPath
+ \inqmlmodule QtQuick
+ \ingroup qtquick-paths
+ \ingroup qtquick-views
+ \inherits Object
+ \brief Describes a Path and associated properties for stroking and filling
+ \since 5.10
+
+ A PathItem contains one or more VisualPath elements. At least one
+ VisualPath is necessary in order to have a PathItem output anything
+ visible. A VisualPath in turn contains a Path and properties describing the
+ stroking and filling parameters, such as the stroke width and color, the
+ fill color or gradient, join and cap styles, and so on. Finally, the Path
+ object contains a list of path elements like PathMove, PathLine, PathCubic,
+ PathQuad, PathArc.
+
+ Any property changes in these data sets will be bubble up and change the
+ output of the PathItem. This means that it is simple and easy to change, or
+ even animate, the starting and ending position, control points, or any
+ stroke or fill parameters using the usual QML bindings and animation types
+ like NumberAnimation.
+
+ In the following example the line join style changes automatically based on
+ the value of joinStyleIndex:
+
+ \code
+ VisualPath {
+ strokeColor: "black"
+ strokeWidth: 16
+ fillColor: "transparent"
+ capStyle: VisualPath.RoundCap
+
+ property int joinStyleIndex: 0
+ property variant styles: [ VisualPath.BevelJoin, VisualPath.MiterJoin, VisualPath.RoundJoin ]
+
+ joinStyle: styles[joinStyleIndex]
+
+ Path {
+ startX: 30
+ startY: 30
+ PathLine { x: 100; y: 100 }
+ PathLine { x: 30; y: 100 }
+ }
+ }
+ \endcode
+
+ Once associated with a PathItem, here is the output with a joinStyleIndex
+ of 2 (VisualPath.RoundJoin):
+
+ \image visualpath-code-example.png
+ */
+
+QQuickVisualPathPrivate::QQuickVisualPathPrivate()
+ : path(nullptr),
+ dirty(DirtyAll)
+{
+}
+
+QQuickVisualPath::QQuickVisualPath(QObject *parent)
+ : QObject(*(new QQuickVisualPathPrivate), parent)
+{
+}
+
+QQuickVisualPath::~QQuickVisualPath()
+{
+}
+
+/*!
+ \qmlproperty Path QtQuick::VisualPath::path
+
+ This property holds the Path object.
+
+ \default
+ */
+
+QQuickPath *QQuickVisualPath::path() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->path;
+}
+
+void QQuickVisualPath::setPath(QQuickPath *path)
+{
+ Q_D(QQuickVisualPath);
+ if (d->path == path)
+ return;
+
+ if (d->path)
+ qmlobject_disconnect(d->path, QQuickPath, SIGNAL(changed()),
+ this, QQuickVisualPath, SLOT(_q_pathChanged()));
+ d->path = path;
+ qmlobject_connect(d->path, QQuickPath, SIGNAL(changed()),
+ this, QQuickVisualPath, SLOT(_q_pathChanged()));
+
+ d->dirty |= QQuickVisualPathPrivate::DirtyPath;
+ emit pathChanged();
+ emit changed();
+}
+
+void QQuickVisualPathPrivate::_q_pathChanged()
+{
+ Q_Q(QQuickVisualPath);
+ dirty |= DirtyPath;
+ emit q->changed();
+}
+
+/*!
+ \qmlproperty color QtQuick::VisualPath::strokeColor
+
+ This property holds the stroking color.
+
+ When set to \c transparent, no stroking occurs.
+
+ The default value is \c white.
+ */
+
+QColor QQuickVisualPath::strokeColor() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.strokeColor;
+}
+
+void QQuickVisualPath::setStrokeColor(const QColor &color)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.strokeColor != color) {
+ d->sfp.strokeColor = color;
+ d->dirty |= QQuickVisualPathPrivate::DirtyStrokeColor;
+ emit strokeColorChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty color QtQuick::VisualPath::strokeWidth
+
+ This property holds the stroke width.
+
+ When set to a negative value, no stroking occurs.
+
+ The default value is 1.
+ */
+
+qreal QQuickVisualPath::strokeWidth() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.strokeWidth;
+}
+
+void QQuickVisualPath::setStrokeWidth(qreal w)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.strokeWidth != w) {
+ d->sfp.strokeWidth = w;
+ d->dirty |= QQuickVisualPathPrivate::DirtyStrokeWidth;
+ emit strokeWidthChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty color QtQuick::VisualPath::fillColor
+
+ This property holds the fill color.
+
+ When set to \c transparent, no filling occurs.
+
+ The default value is \c white.
+ */
+
+QColor QQuickVisualPath::fillColor() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.fillColor;
+}
+
+void QQuickVisualPath::setFillColor(const QColor &color)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.fillColor != color) {
+ d->sfp.fillColor = color;
+ d->dirty |= QQuickVisualPathPrivate::DirtyFillColor;
+ emit fillColorChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::VisualPath::fillRule
+
+ This property holds the fill rule. The default value is
+ VisualPath.OddEvenFill. For an example on fill rules, see
+ QPainterPath::setFillRule().
+
+ \list
+ \li VisualPath.OddEvenFill
+ \li VisualPath.WindingFill
+ \endlist
+ */
+
+QQuickVisualPath::FillRule QQuickVisualPath::fillRule() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.fillRule;
+}
+
+void QQuickVisualPath::setFillRule(FillRule fillRule)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.fillRule != fillRule) {
+ d->sfp.fillRule = fillRule;
+ d->dirty |= QQuickVisualPathPrivate::DirtyFillRule;
+ emit fillRuleChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::VisualPath::joinStyle
+
+ This property defines how joins between two connected lines are drawn. The
+ default value is VisualPath.BevelJoin.
+
+ \list
+ \li VisualPath.MiterJoin - The outer edges of the lines are extended to meet at an angle, and this area is filled.
+ \li VisualPath.BevelJoin - The triangular notch between the two lines is filled.
+ \li VisualPath.RoundJoin - A circular arc between the two lines is filled.
+ \endlist
+ */
+
+QQuickVisualPath::JoinStyle QQuickVisualPath::joinStyle() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.joinStyle;
+}
+
+void QQuickVisualPath::setJoinStyle(JoinStyle style)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.joinStyle != style) {
+ d->sfp.joinStyle = style;
+ d->dirty |= QQuickVisualPathPrivate::DirtyStyle;
+ emit joinStyleChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty int QtQuick::VisualPath::miterLimit
+
+ When VisualPath.joinStyle is set to VisualPath.MiterJoin, this property
+ specifies how far the miter join can extend from the join point.
+
+ The default value is 2.
+ */
+
+int QQuickVisualPath::miterLimit() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.miterLimit;
+}
+
+void QQuickVisualPath::setMiterLimit(int limit)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.miterLimit != limit) {
+ d->sfp.miterLimit = limit;
+ d->dirty |= QQuickVisualPathPrivate::DirtyStyle;
+ emit miterLimitChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::VisualPath::capStyle
+
+ This property defines how the end points of lines are drawn. The
+ default value is VisualPath.SquareCap.
+
+ \list
+ \li VisualPath.FlatCap - A square line end that does not cover the end point of the line.
+ \li VisualPath.SquareCap - A square line end that covers the end point and extends beyond it by half the line width.
+ \li VisualPath.RoundCap - A rounded line end.
+ \endlist
+ */
+
+QQuickVisualPath::CapStyle QQuickVisualPath::capStyle() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.capStyle;
+}
+
+void QQuickVisualPath::setCapStyle(CapStyle style)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.capStyle != style) {
+ d->sfp.capStyle = style;
+ d->dirty |= QQuickVisualPathPrivate::DirtyStyle;
+ emit capStyleChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::VisualPath::strokeStyle
+
+ This property defines the style of stroking. The default value is
+ VisualPath.SolidLine.
+
+ \list
+ \li VisualPath.SolidLine - A plain line.
+ \li VisualPath.DashLine - Dashes separated by a few pixels.
+ \endlist
+ */
+
+QQuickVisualPath::StrokeStyle QQuickVisualPath::strokeStyle() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.strokeStyle;
+}
+
+void QQuickVisualPath::setStrokeStyle(StrokeStyle style)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.strokeStyle != style) {
+ d->sfp.strokeStyle = style;
+ d->dirty |= QQuickVisualPathPrivate::DirtyDash;
+ emit strokeStyleChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick::VisualPath::dashOffset
+
+ This property defines the starting point on the dash pattern, measured in
+ units used to specify the dash pattern.
+
+ The default value is 0.
+
+ \sa QPen::setDashOffset()
+ */
+
+qreal QQuickVisualPath::dashOffset() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.dashOffset;
+}
+
+void QQuickVisualPath::setDashOffset(qreal offset)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.dashOffset != offset) {
+ d->sfp.dashOffset = offset;
+ d->dirty |= QQuickVisualPathPrivate::DirtyDash;
+ emit dashOffsetChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty list<real> QtQuick::VisualPath::dashPattern
+
+ This property defines the dash pattern when VisualPath.strokeStyle is set
+ to VisualPath.DashLine. The pattern must be specified as an even number of
+ positive entries where the entries 1, 3, 5... are the dashes and 2, 4, 6...
+ are the spaces. The pattern is specified in units of the pen's width.
+
+ The default value is (4, 2), meaning a dash of 4 * VisualPath.strokeWidth
+ pixels followed by a space of 2 * VisualPath.strokeWidth pixels.
+
+ \sa QPen::setDashPattern()
+ */
+
+QVector<qreal> QQuickVisualPath::dashPattern() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.dashPattern;
+}
+
+void QQuickVisualPath::setDashPattern(const QVector<qreal> &array)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.dashPattern != array) {
+ d->sfp.dashPattern = array;
+ d->dirty |= QQuickVisualPathPrivate::DirtyDash;
+ emit dashPatternChanged();
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty PathGradient QtQuick::VisualPath::fillGradient
+
+ This property defines the fill gradient. By default no gradient is enabled
+ and the value is \c null. In this case the fill uses a solid color based on
+ the value of VisuaLPath.fillColor.
+
+ When set, VisualPath.fillColor is ignored and filling is done using one of
+ the PathGradient subtypes.
+ */
+
+QQuickPathGradient *QQuickVisualPath::fillGradient() const
+{
+ Q_D(const QQuickVisualPath);
+ return d->sfp.fillGradient;
+}
+
+void QQuickVisualPath::setFillGradient(QQuickPathGradient *gradient)
+{
+ Q_D(QQuickVisualPath);
+ if (d->sfp.fillGradient != gradient) {
+ if (d->sfp.fillGradient)
+ qmlobject_disconnect(d->sfp.fillGradient, QQuickPathGradient, SIGNAL(updated()),
+ this, QQuickVisualPath, SLOT(_q_fillGradientChanged()));
+ d->sfp.fillGradient = gradient;
+ if (d->sfp.fillGradient)
+ qmlobject_connect(d->sfp.fillGradient, QQuickPathGradient, SIGNAL(updated()),
+ this, QQuickVisualPath, SLOT(_q_fillGradientChanged()));
+ d->dirty |= QQuickVisualPathPrivate::DirtyFillGradient;
+ emit changed();
+ }
+}
+
+void QQuickVisualPathPrivate::_q_fillGradientChanged()
+{
+ Q_Q(QQuickVisualPath);
+ dirty |= DirtyFillGradient;
+ emit q->changed();
+}
+
+void QQuickVisualPath::resetFillGradient()
+{
+ setFillGradient(nullptr);
+}
+
+/*!
+ \qmltype PathItem
+ \instantiates QQuickPathItem
+ \inqmlmodule QtQuick
+ \ingroup qtquick-paths
+ \ingroup qtquick-views
+ \inherits Item
+ \brief Renders a path
+ \since 5.10
+
+ Renders a path either by generating geometry via QPainterPath and manual
+ triangulation or by using a GPU vendor 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
+ PathItem is suitable for creating shapes spreading over larger areas of the
+ screen, avoiding the performance penalty for texture uploads or framebuffer
+ blits. In addition, the declarative API allows manipulating, binding to,
+ and even animating the path element properties like starting and ending
+ position, the control points, etc.
+
+ The types for specifying path elements are shared between \l 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, PathSvg.
+
+ See \l Path for a detailed overview of the supported path elements.
+
+ \code
+ PathItem {
+ width: 200
+ height: 150
+ anchors.centerIn: parent
+ VisualPath {
+ strokeWidth: 4
+ strokeColor: "red"
+ fillGradient: PathLinearGradient {
+ x1: 20; y1: 20
+ x2: 180; y2: 130
+ PathGradientStop { position: 0; color: "blue" }
+ PathGradientStop { position: 0.2; color: "green" }
+ PathGradientStop { position: 0.4; color: "red" }
+ PathGradientStop { position: 0.6; color: "yellow" }
+ PathGradientStop { position: 1; color: "cyan" }
+ }
+ strokeStyle: VisualPath.DashLine
+ dashPattern: [ 1, 4 ]
+ Path {
+ startX: 20; startY: 20
+ PathLine { x: 180; y: 130 }
+ PathLine { x: 20; y: 130 }
+ PathLine { x: 20; y: 20 }
+ }
+ }
+ }
+ \endcode
+
+ \image pathitem-code-example.png
+
+ \note 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.
+
+ The following list summarizes the available PathItem rendering approaches:
+
+ \list
+
+ \li When running with the default, OpenGL backend of Qt Quick, both the
+ generic, triangulation-based and the NVIDIA-specific
+ \c{GL_NV_path_rendering} methods are available. The choice is made at
+ runtime, depending on the graphics driver's capabilities. When this is not
+ desired, applications can force using the generic method by setting the
+ PathItem.enableVendorExtensions property to \c false.
+
+ \li The \c software backend is fully supported. The path is rendered via
+ QPainter::strokePath() and QPainter::fillPath() in this case.
+
+ \li The Direct 3D 12 backend is not currently supported.
+
+ \li The OpenVG backend is not currently supported.
+
+ \endlist
+
+ \sa Path, PathMove, PathLine, PathQuad, PathCubic, PathArc, PathSvg
+*/
+
+QQuickPathItemPrivate::QQuickPathItemPrivate()
+ : componentComplete(true),
+ vpChanged(false),
+ rendererType(QQuickPathItem::UnknownRenderer),
+ async(false),
+ status(QQuickPathItem::Null),
+ renderer(nullptr),
+ enableVendorExts(true)
+{
+}
+
+QQuickPathItemPrivate::~QQuickPathItemPrivate()
+{
+ delete renderer;
+}
+
+void QQuickPathItemPrivate::_q_visualPathChanged()
+{
+ Q_Q(QQuickPathItem);
+ vpChanged = true;
+ q->polish();
+}
+
+void QQuickPathItemPrivate::setStatus(QQuickPathItem::Status newStatus)
+{
+ Q_Q(QQuickPathItem);
+ if (status != newStatus) {
+ status = newStatus;
+ emit q->statusChanged();
+ }
+}
+
+QQuickPathItem::QQuickPathItem(QQuickItem *parent)
+ : QQuickItem(*(new QQuickPathItemPrivate), parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QQuickPathItem::~QQuickPathItem()
+{
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::PathItem::rendererType
+
+ This property determines which path rendering backend is active.
+
+ \list
+
+ \li PathItem.UnknownRenderer - The renderer is unknown.
+
+ \li PathItem.GeometryRenderer - The generic, driver independent solution
+ for OpenGL. Uses the same CPU-based triangulation approach as QPainter's
+ OpenGL 2 paint engine. This is the default on non-NVIDIA hardware when the
+ default, OpenGL Qt Quick scenegraph backend is in use.
+
+ \li PathItem.NvprRenderer - Path items are rendered by performing OpenGL
+ calls using the \c{GL_NV_path_rendering} extension. This is the default on
+ NVIDIA hardware when the default, OpenGL Qt Quick scenegraph backend is in
+ use.
+
+ \li PathItem.SoftwareRenderer - Pure QPainter drawing using the raster
+ paint engine. This is the default, and only, option when the Qt Quick
+ scenegraph is running with the \c software backend.
+
+ \endlist
+*/
+
+QQuickPathItem::RendererType QQuickPathItem::rendererType() const
+{
+ Q_D(const QQuickPathItem);
+ return d->rendererType;
+}
+
+/*!
+ \qmlproperty bool QtQuick::PathItem::asynchronous
+
+ When PathItem.rendererType is PathItem.GeometryRenderer, the input path is
+ triangulated on the CPU during the polishing phase of the PathItem. This is
+ potentially expensive. To offload this work to separate worker threads, set
+ this property to \c true.
+
+ When enabled, making a PathItem visible will not wait for the content to
+ become available. Instead, the gui/main thread is not blocked and the
+ results of the path rendering are shown only when all the asynchronous work
+ has been finished.
+
+ The default value is \c false.
+ */
+
+bool QQuickPathItem::asynchronous() const
+{
+ Q_D(const QQuickPathItem);
+ return d->async;
+}
+
+void QQuickPathItem::setAsynchronous(bool async)
+{
+ Q_D(QQuickPathItem);
+ if (d->async != async) {
+ d->async = async;
+ emit asynchronousChanged();
+ if (d->componentComplete)
+ d->_q_visualPathChanged();
+ }
+}
+
+/*!
+ \qmlproperty bool QtQuick::PathItem::enableVendorExtensions
+
+ This property controls the usage of non-standard OpenGL extensions like
+ GL_NV_path_rendering. To disable PathItem.NvprRenderer and force a uniform
+ behavior regardless of the graphics card and drivers, set this property to
+ \c false.
+
+ The default value is \c true.
+ */
+
+bool QQuickPathItem::enableVendorExtensions() const
+{
+ Q_D(const QQuickPathItem);
+ return d->enableVendorExts;
+}
+
+void QQuickPathItem::setEnableVendorExtensions(bool enable)
+{
+ Q_D(QQuickPathItem);
+ if (d->enableVendorExts != enable) {
+ d->enableVendorExts = enable;
+ emit enableVendorExtensionsChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::PathItem::status
+
+ This property determines the status of the PathItem and is relevant when
+ PathItem.asynchronous is set to \c true.
+
+ \list
+
+ \li PathItem.Null - Not yet initialized.
+
+ \li PathItem.Ready - The PathItem has finished processing.
+
+ \li PathItem.Processing - The path is being processed.
+
+ \endlist
+ */
+
+QQuickPathItem::Status QQuickPathItem::status() const
+{
+ Q_D(const QQuickPathItem);
+ return d->status;
+}
+
+static QQuickVisualPath *vpe_at(QQmlListProperty<QQuickVisualPath> *property, int index)
+{
+ QQuickPathItemPrivate *d = QQuickPathItemPrivate::get(static_cast<QQuickPathItem *>(property->object));
+ return d->qmlData.vp.at(index);
+}
+
+static void vpe_append(QQmlListProperty<QQuickVisualPath> *property, QQuickVisualPath *obj)
+{
+ QQuickPathItem *item = static_cast<QQuickPathItem *>(property->object);
+ QQuickPathItemPrivate *d = QQuickPathItemPrivate::get(item);
+ d->qmlData.vp.append(obj);
+
+ if (d->componentComplete) {
+ QObject::connect(obj, SIGNAL(changed()), item, SLOT(_q_visualPathChanged()));
+ d->_q_visualPathChanged();
+ }
+}
+
+static int vpe_count(QQmlListProperty<QQuickVisualPath> *property)
+{
+ QQuickPathItemPrivate *d = QQuickPathItemPrivate::get(static_cast<QQuickPathItem *>(property->object));
+ return d->qmlData.vp.count();
+}
+
+static void vpe_clear(QQmlListProperty<QQuickVisualPath> *property)
+{
+ QQuickPathItem *item = static_cast<QQuickPathItem *>(property->object);
+ QQuickPathItemPrivate *d = QQuickPathItemPrivate::get(item);
+
+ for (QQuickVisualPath *p : d->qmlData.vp)
+ QObject::disconnect(p, SIGNAL(changed()), item, SLOT(_q_visualPathChanged()));
+
+ d->qmlData.vp.clear();
+
+ if (d->componentComplete)
+ d->_q_visualPathChanged();
+}
+
+/*!
+ \qmlproperty list<VisualPath> QtQuick::PathItem::elements
+
+ This property holds the VisualPath objects that define the contents of the
+ PathItem.
+
+ \default
+ */
+
+QQmlListProperty<QQuickVisualPath> QQuickPathItem::elements()
+{
+ return QQmlListProperty<QQuickVisualPath>(this,
+ nullptr,
+ vpe_append,
+ vpe_count,
+ vpe_at,
+ vpe_clear);
+}
+
+void QQuickPathItem::classBegin()
+{
+ Q_D(QQuickPathItem);
+ d->componentComplete = false;
+}
+
+void QQuickPathItem::componentComplete()
+{
+ Q_D(QQuickPathItem);
+ d->componentComplete = true;
+
+ for (QQuickVisualPath *p : d->qmlData.vp)
+ connect(p, SIGNAL(changed()), this, SLOT(_q_visualPathChanged()));
+
+ d->_q_visualPathChanged();
+}
+
+void QQuickPathItem::updatePolish()
+{
+ Q_D(QQuickPathItem);
+
+ if (!d->vpChanged)
+ return;
+
+ d->vpChanged = false;
+
+ if (!d->renderer) {
+ d->createRenderer();
+ if (!d->renderer)
+ return;
+ emit rendererChanged();
+ }
+
+ // endSync() is where expensive calculations may happen (or get kicked off
+ // on worker threads), 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)
+{
+ Q_D(QQuickPathItem);
+
+ // sync may have been deferred; do it now if the item became visible
+ if (change == ItemVisibleHasChanged && data.boolValue)
+ d->_q_visualPathChanged();
+
+ 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->createNode();
+ d->renderer->updateNode();
+ }
+ 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 (enableVendorExts && 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::createNode()
+{
+ Q_Q(QQuickPathItem);
+ QSGNode *node = nullptr;
+ if (!q->window())
+ return node;
+ QSGRendererInterface *ri = q->window()->rendererInterface();
+ if (!ri)
+ return node;
+
+ switch (ri->graphicsApi()) {
+#ifndef QT_NO_OPENGL
+ case QSGRendererInterface::OpenGL:
+ if (enableVendorExts && QQuickPathItemNvprRenderNode::isSupported()) {
+ node = new QQuickPathItemNvprRenderNode;
+ static_cast<QQuickPathItemNvprRenderer *>(renderer)->setNode(
+ static_cast<QQuickPathItemNvprRenderNode *>(node));
+ } else {
+ node = new QQuickPathItemGenericNode;
+ static_cast<QQuickPathItemGenericRenderer *>(renderer)->setRootNode(
+ static_cast<QQuickPathItemGenericNode *>(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;
+}
+
+static void q_asyncPathItemReady(void *data)
+{
+ QQuickPathItemPrivate *self = static_cast<QQuickPathItemPrivate *>(data);
+ self->setStatus(QQuickPathItem::Ready);
+}
+
+void QQuickPathItemPrivate::sync()
+{
+ const bool useAsync = async && renderer->flags().testFlag(QQuickAbstractPathRenderer::SupportsAsync);
+ if (useAsync) {
+ setStatus(QQuickPathItem::Processing);
+ renderer->setAsyncCallback(q_asyncPathItemReady, this);
+ }
+
+ if (!jsData.isValid()) {
+ // Standard route: The path and stroke/fill parameters are provided via
+ // VisualPath and Path.
+ const int count = qmlData.vp.count();
+ renderer->beginSync(count);
+
+ for (int i = 0; i < count; ++i) {
+ QQuickVisualPath *p = qmlData.vp[i];
+ int &dirty(QQuickVisualPathPrivate::get(p)->dirty);
+
+ if (dirty & QQuickVisualPathPrivate::DirtyPath)
+ renderer->setPath(i, p->path());
+ if (dirty & QQuickVisualPathPrivate::DirtyStrokeColor)
+ renderer->setStrokeColor(i, p->strokeColor());
+ if (dirty & QQuickVisualPathPrivate::DirtyStrokeWidth)
+ renderer->setStrokeWidth(i, p->strokeWidth());
+ if (dirty & QQuickVisualPathPrivate::DirtyFillColor)
+ renderer->setFillColor(i, p->fillColor());
+ if (dirty & QQuickVisualPathPrivate::DirtyFillRule)
+ renderer->setFillRule(i, p->fillRule());
+ if (dirty & QQuickVisualPathPrivate::DirtyStyle) {
+ renderer->setJoinStyle(i, p->joinStyle(), p->miterLimit());
+ renderer->setCapStyle(i, p->capStyle());
+ }
+ if (dirty & QQuickVisualPathPrivate::DirtyDash)
+ renderer->setStrokeStyle(i, p->strokeStyle(), p->dashOffset(), p->dashPattern());
+ if (dirty & QQuickVisualPathPrivate::DirtyFillGradient)
+ renderer->setFillGradient(i, p->fillGradient());
+
+ dirty = 0;
+ }
+
+ renderer->endSync(useAsync);
+ } else {
+ // Path and stroke/fill params provided from JavaScript. This avoids
+ // QObjects at the expense of not supporting changes afterwards.
+ const int count = jsData.paths.count();
+ renderer->beginSync(count);
+
+ for (int i = 0; i < count; ++i) {
+ renderer->setJSPath(i, jsData.paths[i]);
+ const QQuickPathItemStrokeFillParams sfp(jsData.sfp[i]);
+ renderer->setStrokeColor(i, sfp.strokeColor);
+ renderer->setStrokeWidth(i, sfp.strokeWidth);
+ renderer->setFillColor(i, sfp.fillColor);
+ renderer->setFillRule(i, sfp.fillRule);
+ renderer->setJoinStyle(i, sfp.joinStyle, sfp.miterLimit);
+ renderer->setCapStyle(i, sfp.capStyle);
+ renderer->setStrokeStyle(i, sfp.strokeStyle, sfp.dashOffset, sfp.dashPattern);
+ renderer->setFillGradient(i, sfp.fillGradient);
+ }
+
+ renderer->endSync(useAsync);
+ }
+
+ if (!useAsync)
+ setStatus(QQuickPathItem::Ready);
+}
+
+// ***** gradient support *****
+
+/*!
+ \qmltype PathGradientStop
+ \instantiates QQuickPathGradientStop
+ \inqmlmodule QtQuick
+ \ingroup qtquick-paths
+ \ingroup qtquick-views
+ \inherits Object
+ \brief Defines a color at a position in a gradient
+ \since 5.10
+ */
+
+QQuickPathGradientStop::QQuickPathGradientStop(QObject *parent)
+ : QObject(parent),
+ m_position(0),
+ m_color(Qt::black)
+{
+}
+
+/*!
+ \qmlproperty real QtQuick::PathGradientStop::position
+
+ The position and color properties describe the color used at a given
+ position in a gradient, as represented by a gradient stop.
+
+ The default value is 0.
+ */
+
+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();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick::PathGradientStop::color
+
+ The position and color properties describe the color used at a given
+ position in a gradient, as represented by a gradient stop.
+
+ The default value is \c black.
+ */
+
+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();
+ }
+}
+
+/*!
+ \qmltype PathGradient
+ \instantiates QQuickPathGradient
+ \inqmlmodule QtQuick
+ \ingroup qtquick-paths
+ \ingroup qtquick-views
+ \inherits Object
+ \brief Base type of PathItem fill gradients
+ \since 5.10
+
+ This is an abstract base class for gradients like PathLinearGradient and
+ cannot be created directly.
+ */
+
+QQuickPathGradient::QQuickPathGradient(QObject *parent)
+ : QObject(parent),
+ m_spread(PadSpread)
+{
+}
+
+int QQuickPathGradient::countStops(QQmlListProperty<QObject> *list)
+{
+ QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(list->object);
+ Q_ASSERT(grad);
+ return grad->m_stops.count();
+}
+
+QObject *QQuickPathGradient::atStop(QQmlListProperty<QObject> *list, int index)
+{
+ QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(list->object);
+ Q_ASSERT(grad);
+ return grad->m_stops.at(index);
+}
+
+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);
+}
+
+/*!
+ \qmlproperty list<Object> QtQuick::PathGradient::stops
+ \default
+
+ The list of PathGradientStop objects defining the colors at given positions
+ in the gradient.
+ */
+
+QQmlListProperty<QObject> QQuickPathGradient::stops()
+{
+ return QQmlListProperty<QObject>(this, nullptr,
+ &QQuickPathGradient::appendStop,
+ &QQuickPathGradient::countStops,
+ &QQuickPathGradient::atStop,
+ 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;
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::PathGradient::spred
+
+ Specifies how the area outside the gradient area should be filled. The
+ default value is PathGradient.PadSpread.
+
+ \list
+ \li PathGradient.PadSpread - The area is filled with the closest stop color.
+ \li PathGradient.RepeatSpread - The gradient is repeated outside the gradient area.
+ \li PathGradient.ReflectSpread - The gradient is reflected outside the gradient area.
+ \endlist
+ */
+
+QQuickPathGradient::SpreadMode QQuickPathGradient::spread() const
+{
+ return m_spread;
+}
+
+void QQuickPathGradient::setSpread(SpreadMode mode)
+{
+ if (m_spread != mode) {
+ m_spread = mode;
+ emit spreadChanged();
+ emit updated();
+ }
+}
+
+/*!
+ \qmltype PathLinearGradient
+ \instantiates QQuickPathLinearGradient
+ \inqmlmodule QtQuick
+ \ingroup qtquick-paths
+ \ingroup qtquick-views
+ \inherits PathGradient
+ \brief Linear gradient
+ \since 5.10
+
+ Linear gradients interpolate colors between start and end points. Outside
+ these points the gradient is either padded, reflected or repeated depending
+ on the spread type.
+
+ \sa QLinearGradient
+ */
+
+QQuickPathLinearGradient::QQuickPathLinearGradient(QObject *parent)
+ : QQuickPathGradient(parent)
+{
+}
+
+/*!
+ \qmlproperty real QtQuick::PathLinearGradient::x1
+ \qmlproperty real QtQuick::PathLinearGradient::y1
+ \qmlproperty real QtQuick::PathLinearGradient::x2
+ \qmlproperty real QtQuick::PathLinearGradient::y2
+
+ These properties define the start and end points between which color
+ interpolation occurs. By default both the stard and end points are set to
+ (0, 0).
+ */
+
+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
+
+// ***** JS-based alternative for creating static paths, (mostly) without QObjects *****
+
+class QQuickPathItemJSEngineData : public QV8Engine::Deletable
+{
+public:
+ QQuickPathItemJSEngineData(QV4::ExecutionEngine *engine);
+
+ QV4::PersistentValue pathProto;
+ QV4::PersistentValue strokeFillParamsProto;
+};
+
+V4_DEFINE_EXTENSION(QQuickPathItemJSEngineData, engineData)
+
+namespace QV4 {
+namespace Heap {
+
+struct QQuickPathItemJSPathPrototype : Object {
+ void init() { Object::init(); }
+};
+
+struct QQuickPathItemJSPath : Object {
+ void init() { Object::init(); }
+ QQuickPathItemPathObject *obj;
+};
+
+struct QQuickPathItemJSStrokeFillParamsPrototype : Object {
+ void init() { Object::init(); }
+};
+
+struct QQuickPathItemJSStrokeFillParams : Object {
+ void init() { Object::init(); }
+ QQuickPathItemStrokeFillParamsObject *obj;
+};
+
+} // namespace Heap
+} // namespace QV4
+
+struct QQuickPathItemJSPathPrototype : public QV4::Object
+{
+ V4_OBJECT2(QQuickPathItemJSPathPrototype, QV4::Object)
+public:
+ static QV4::Heap::QQuickPathItemJSPathPrototype *create(QV4::ExecutionEngine *engine)
+ {
+ QV4::Scope scope(engine);
+ auto obj = engine->memoryManager->allocObject<QQuickPathItemJSPathPrototype>();
+ QV4::Scoped<QQuickPathItemJSPathPrototype> o(scope, obj);
+
+ o->defineDefaultProperty(QStringLiteral("clear"), method_clear, 0);
+ o->defineDefaultProperty(QStringLiteral("moveTo"), method_moveTo, 0);
+ o->defineDefaultProperty(QStringLiteral("lineTo"), method_lineTo, 0);
+ o->defineDefaultProperty(QStringLiteral("quadTo"), method_quadTo, 0);
+ o->defineDefaultProperty(QStringLiteral("cubicTo"), method_cubicTo, 0);
+ o->defineDefaultProperty(QStringLiteral("arcTo"), method_arcTo, 0);
+
+ return o->d();
+ }
+
+ static void method_clear(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_moveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_lineTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_quadTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_cubicTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_arcTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+};
+
+DEFINE_OBJECT_VTABLE(QQuickPathItemJSPathPrototype);
+
+struct QQuickPathItemJSStrokeFillParamsPrototype : public QV4::Object
+{
+ V4_OBJECT2(QQuickPathItemJSStrokeFillParamsPrototype, QV4::Object)
+public:
+ static QV4::Heap::QQuickPathItemJSStrokeFillParamsPrototype *create(QV4::ExecutionEngine *engine)
+ {
+ QV4::Scope scope(engine);
+ auto obj = engine->memoryManager->allocObject<QQuickPathItemJSStrokeFillParamsPrototype>();
+ QV4::Scoped<QQuickPathItemJSStrokeFillParamsPrototype> o(scope, obj);
+
+ o->defineDefaultProperty(QStringLiteral("clear"), method_clear, 0);
+
+ return o->d();
+ }
+
+ static void method_clear(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+};
+
+DEFINE_OBJECT_VTABLE(QQuickPathItemJSStrokeFillParamsPrototype);
+
+struct QQuickPathItemJSPath : public QV4::Object
+{
+ V4_OBJECT2(QQuickPathItemJSPath, QV4::Object)
+};
+
+DEFINE_OBJECT_VTABLE(QQuickPathItemJSPath);
+
+struct QQuickPathItemJSStrokeFillParams : public QV4::Object
+{
+ V4_OBJECT2(QQuickPathItemJSStrokeFillParams, QV4::Object)
+
+ static void method_get_strokeColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_strokeColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_strokeWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_strokeWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_fillColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_fillColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_joinStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_joinStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_capStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_capStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_dashOffset(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_dashOffset(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_dashPattern(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_dashPattern(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_fillGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_fillGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+};
+
+DEFINE_OBJECT_VTABLE(QQuickPathItemJSStrokeFillParams);
+
+void QQuickPathItemJSPathPrototype::method_clear(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSPath> r(scope, callData->thisObject.as<QQuickPathItemJSPath>());
+
+ r->d()->obj->clear();
+
+ scope.result = callData->thisObject.asReturnedValue();
+}
+
+void QQuickPathItemJSPathPrototype::method_moveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSPath> r(scope, callData->thisObject.as<QQuickPathItemJSPath>());
+
+ if (callData->argc >= 2) {
+ QQuickPathItemPathObject *p = r->d()->obj;
+ p->path.cmd.append(QQuickPathItemPath::MoveTo);
+ p->path.coords.append(callData->args[0].toNumber());
+ p->path.coords.append(callData->args[1].toNumber());
+ }
+
+ scope.result = callData->thisObject.asReturnedValue();
+}
+
+void QQuickPathItemJSPathPrototype::method_lineTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSPath> r(scope, callData->thisObject.as<QQuickPathItemJSPath>());
+
+ if (callData->argc >= 2) {
+ QQuickPathItemPathObject *p = r->d()->obj;
+ p->path.cmd.append(QQuickPathItemPath::LineTo);
+ p->path.coords.append(callData->args[0].toNumber());
+ p->path.coords.append(callData->args[1].toNumber());
+ }
+
+ scope.result = callData->thisObject.asReturnedValue();
+}
+
+void QQuickPathItemJSPathPrototype::method_quadTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSPath> r(scope, callData->thisObject.as<QQuickPathItemJSPath>());
+
+ if (callData->argc >= 4) {
+ QQuickPathItemPathObject *p = r->d()->obj;
+ p->path.cmd.append(QQuickPathItemPath::QuadTo);
+ const QV4::Value *v = callData->args;
+ p->path.coords.append(v[0].toNumber()); // cx
+ p->path.coords.append(v[1].toNumber()); // cy
+ p->path.coords.append(v[2].toNumber()); // x
+ p->path.coords.append(v[3].toNumber()); // y
+ }
+
+ scope.result = callData->thisObject.asReturnedValue();
+}
+
+void QQuickPathItemJSPathPrototype::method_cubicTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSPath> r(scope, callData->thisObject.as<QQuickPathItemJSPath>());
+
+ if (callData->argc >= 6) {
+ QQuickPathItemPathObject *p = r->d()->obj;
+ p->path.cmd.append(QQuickPathItemPath::CubicTo);
+ const QV4::Value *v = callData->args;
+ p->path.coords.append(v[0].toNumber()); // c1x
+ p->path.coords.append(v[1].toNumber()); // c1y
+ p->path.coords.append(v[2].toNumber()); // c2x
+ p->path.coords.append(v[3].toNumber()); // c2y
+ p->path.coords.append(v[4].toNumber()); // x
+ p->path.coords.append(v[5].toNumber()); // y
+ }
+
+ scope.result = callData->thisObject.asReturnedValue();
+}
+
+void QQuickPathItemJSPathPrototype::method_arcTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSPath> r(scope, callData->thisObject.as<QQuickPathItemJSPath>());
+
+ if (callData->argc >= 7) {
+ QQuickPathItemPathObject *p = r->d()->obj;
+ p->path.cmd.append(QQuickPathItemPath::ArcTo);
+ const QV4::Value *v = callData->args;
+ p->path.coords.append(v[0].toNumber()); // radiusX
+ p->path.coords.append(v[1].toNumber()); // radiusY
+ p->path.coords.append(v[2].toNumber()); // xAxisRotation
+ p->path.coords.append(v[3].toNumber()); // x
+ p->path.coords.append(v[4].toNumber()); // y
+ p->path.coords.append(v[5].toNumber()); // sweepFlag
+ p->path.coords.append(v[6].toNumber()); // largeArc
+ }
+
+ scope.result = callData->thisObject.asReturnedValue();
+}
+
+void QQuickPathItemJSStrokeFillParamsPrototype::method_clear(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ r->d()->obj->clear();
+
+ scope.result = callData->thisObject.asReturnedValue();
+}
+
+Q_QUICK_PRIVATE_EXPORT QColor qt_color_from_string(const QV4::Value &name); // qquickcontext2d.cpp
+
+static inline QString qt_color_string(const QColor &color)
+{
+ if (color.alpha() == 255)
+ return color.name();
+ QString alphaString = QString::number(color.alphaF(), 'f');
+ while (alphaString.endsWith(QLatin1Char('0')))
+ alphaString.chop(1);
+ if (alphaString.endsWith(QLatin1Char('.')))
+ alphaString += QLatin1Char('0');
+ return QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString);
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_strokeColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = QV4::Encode(scope.engine->newString(qt_color_string(r->d()->obj->sfp.strokeColor)));
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_strokeColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ if (value->isString())
+ r->d()->obj->sfp.strokeColor = qt_color_from_string(value);
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_strokeWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = scope.engine->fromVariant(r->d()->obj->sfp.strokeWidth);
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_strokeWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ r->d()->obj->sfp.strokeWidth = value->toNumber();
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_fillColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = QV4::Encode(scope.engine->newString(qt_color_string(r->d()->obj->sfp.fillColor)));
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_fillColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ if (value->isString())
+ r->d()->obj->sfp.fillColor = qt_color_from_string(value);
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = scope.engine->fromVariant(r->d()->obj->sfp.fillRule);
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ if (value->isInt32())
+ r->d()->obj->sfp.fillRule = QQuickVisualPath::FillRule(value->integerValue());
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_joinStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = scope.engine->fromVariant(r->d()->obj->sfp.joinStyle);
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_joinStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ if (value->isInt32())
+ r->d()->obj->sfp.joinStyle = QQuickVisualPath::JoinStyle(value->integerValue());
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = scope.engine->fromVariant(r->d()->obj->sfp.miterLimit);
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ r->d()->obj->sfp.miterLimit = value->toNumber();
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_capStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = scope.engine->fromVariant(r->d()->obj->sfp.capStyle);
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_capStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ if (value->isInt32())
+ r->d()->obj->sfp.capStyle = QQuickVisualPath::CapStyle(value->integerValue());
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = scope.engine->fromVariant(r->d()->obj->sfp.strokeStyle);
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ if (value->isInt32())
+ r->d()->obj->sfp.strokeStyle = QQuickVisualPath::StrokeStyle(value->integerValue());
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_dashOffset(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = scope.engine->fromVariant(r->d()->obj->sfp.dashOffset);
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_dashOffset(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ r->d()->obj->sfp.dashOffset = value->toNumber();
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_dashPattern(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedArrayObject a(scope, scope.engine->newArrayObject());
+ QQuickPathItemStrokeFillParamsObject *p = r->d()->obj;
+ a->arrayReserve(p->sfp.dashPattern.count());
+ QV4::ScopedValue v(scope);
+ for (int i = 0; i < p->sfp.dashPattern.count(); ++i)
+ a->arrayPut(i, (v = scope.engine->fromVariant(p->sfp.dashPattern[i])));
+ a->setArrayLengthUnchecked(p->sfp.dashPattern.count());
+
+ scope.result = a.asReturnedValue();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_dashPattern(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ if (value->isObject()) {
+ QV4::Scoped<QV4::ArrayObject> ao(scope, value);
+ if (!!ao) {
+ QQuickPathItemStrokeFillParamsObject *p = r->d()->obj;
+ p->sfp.dashPattern.resize(ao->getLength());
+ QV4::ScopedValue val(scope);
+ for (int i = 0; i < p->sfp.dashPattern.count(); ++i) {
+ val = ao->getIndexed(i);
+ p->sfp.dashPattern[i] = val->toNumber();
+ }
+ }
+ }
+
+ scope.result = QV4::Encode::undefined();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_get_fillGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ scope.result = r->d()->obj->v4fillGradient.value();
+}
+
+void QQuickPathItemJSStrokeFillParams::method_set_fillGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
+{
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> r(scope, callData->thisObject.as<QQuickPathItemJSStrokeFillParams>());
+
+ QV4::ScopedValue value(scope, callData->argument(0));
+ QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, value);
+ if (!!qobjectWrapper) {
+ if (QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(qobjectWrapper->object())) {
+ r->d()->obj->v4fillGradient.set(scope.engine, value);
+ r->d()->obj->sfp.fillGradient = grad;
+ }
+ } else {
+ r->d()->obj->v4fillGradient.set(scope.engine, nullptr);
+ r->d()->obj->sfp.fillGradient = nullptr;
+ }
+
+ scope.result = QV4::Encode::undefined();
+}
+
+QQuickPathItemJSEngineData::QQuickPathItemJSEngineData(QV4::ExecutionEngine *v4)
+{
+ QV4::Scope scope(v4);
+
+ QV4::ScopedObject proto(scope, QQuickPathItemJSPathPrototype::create(v4));
+ pathProto = proto;
+
+ proto = QV4::ScopedObject(scope, QQuickPathItemJSStrokeFillParamsPrototype::create(v4));
+
+ proto->defineAccessorProperty(QStringLiteral("strokeColor"),
+ QQuickPathItemJSStrokeFillParams::method_get_strokeColor,
+ QQuickPathItemJSStrokeFillParams::method_set_strokeColor);
+ proto->defineAccessorProperty(QStringLiteral("strokeWidth"),
+ QQuickPathItemJSStrokeFillParams::method_get_strokeWidth,
+ QQuickPathItemJSStrokeFillParams::method_set_strokeWidth);
+ proto->defineAccessorProperty(QStringLiteral("fillColor"),
+ QQuickPathItemJSStrokeFillParams::method_get_fillColor,
+ QQuickPathItemJSStrokeFillParams::method_set_fillColor);
+ proto->defineAccessorProperty(QStringLiteral("fillRule"),
+ QQuickPathItemJSStrokeFillParams::method_get_fillRule,
+ QQuickPathItemJSStrokeFillParams::method_set_fillRule);
+ proto->defineAccessorProperty(QStringLiteral("joinStyle"),
+ QQuickPathItemJSStrokeFillParams::method_get_joinStyle,
+ QQuickPathItemJSStrokeFillParams::method_set_joinStyle);
+ proto->defineAccessorProperty(QStringLiteral("miterLimit"),
+ QQuickPathItemJSStrokeFillParams::method_get_miterLimit,
+ QQuickPathItemJSStrokeFillParams::method_set_miterLimit);
+ proto->defineAccessorProperty(QStringLiteral("capStyle"),
+ QQuickPathItemJSStrokeFillParams::method_get_capStyle,
+ QQuickPathItemJSStrokeFillParams::method_set_capStyle);
+ proto->defineAccessorProperty(QStringLiteral("strokeStyle"),
+ QQuickPathItemJSStrokeFillParams::method_get_strokeStyle,
+ QQuickPathItemJSStrokeFillParams::method_set_strokeStyle);
+ proto->defineAccessorProperty(QStringLiteral("dashOffset"),
+ QQuickPathItemJSStrokeFillParams::method_get_dashOffset,
+ QQuickPathItemJSStrokeFillParams::method_set_dashOffset);
+ proto->defineAccessorProperty(QStringLiteral("dashPattern"),
+ QQuickPathItemJSStrokeFillParams::method_get_dashPattern,
+ QQuickPathItemJSStrokeFillParams::method_set_dashPattern);
+ proto->defineAccessorProperty(QStringLiteral("fillGradient"),
+ QQuickPathItemJSStrokeFillParams::method_get_fillGradient,
+ QQuickPathItemJSStrokeFillParams::method_set_fillGradient);
+
+ strokeFillParamsProto = proto;
+}
+
+void QQuickPathItemPathObject::setV4Engine(QV4::ExecutionEngine *engine)
+{
+ QQuickPathItemJSEngineData *ed = engineData(engine);
+ QV4::Scope scope(engine);
+ QV4::Scoped<QQuickPathItemJSPath> wrapper(scope, engine->memoryManager->allocObject<QQuickPathItemJSPath>());
+ QV4::ScopedObject p(scope, ed->pathProto.value());
+ wrapper->setPrototype(p);
+ wrapper->d()->obj = this;
+ m_v4value = wrapper;
+}
+
+/*!
+ \qmltype JSPath
+ \inqmlmodule QtQuick
+ \ingroup qtquick-path
+ \brief Describes a path via a JavaScript API
+ */
+
+/*!
+ \qmlmethod void QtQuick::JSPath::moveTo(x, y)
+
+ Moves the path's position to the absolute position specified by (\a x, \a y).
+ */
+
+/*!
+ \qmlmethod void QtQuick::JSPath::lineTo(x, y)
+
+ Defines a straight line to the absolute position specified by (\a x, \a y).
+ */
+
+/*!
+ \qmlmethod void QtQuick::JSPath::quadTo(cx, cy, x, y)
+
+ Defines a quadratic Bezier curve with a control point (\a cx, \a cy) and an
+ end point of (\a x, \a y).
+ */
+
+/*!
+ \qmlmethod void QtQuick::JSPath::cubicTo(c1x, c1y, c2x, c2y, x, y)
+
+ Defines a cubic Bezier curve with two control points (\a c1x, \a c1y) and
+ (\a c2x, \a c2y), and an end point of (\a x, \a y).
+ */
+
+/*!
+ \qmlmethod void QtQuick::JSPath::arcTo(radiusX, radiusY, xAxisRotation, x, y, sweepFlag, largeArc)
+
+ Defines an elliptical arc, following the elliptical arc command in SVG. See
+ \l{https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands}{the
+ SVG path specification} for details on the parameters.
+ */
+
+/*!
+ \qmlmethod void QtQuick::JSPath::clear()
+
+ Clears the path object removing all path elements. This is more lightweight
+ than creating a new JSPath object.
+ */
+
+void QQuickPathItemPathObject::clear()
+{
+ path = QQuickPathItemPath();
+}
+
+/*!
+ \qmltype StrokeFillParams
+ \inqmlmodule QtQuick
+ \ingroup qtquick-path
+ \brief Describes stroke and fill parameters via a JavaScript API
+
+ The properties of StrokeFillParams objects correspond 1:1 to VisualPath
+ properties. The possible values for enumerations are the same as well, for
+ example:
+
+ \code
+ sfp.strokeStyle = VisualPath.DashLine;
+ sfp.capStyle = VisualPath.RoundCap;
+ \endcode
+ */
+
+/*!
+ \qmlproperty color QtQuick::StrokeFillParams::strokeColor
+ */
+
+/*!
+ \qmlproperty real QtQuick::StrokeFillParams::strokeWidth
+ */
+
+/*!
+ \qmlproperty color QtQuick::StrokeFillParams::fillColor
+ */
+
+/*!
+ \qmlproperty enumeration QtQuick::StrokeFillParams::fillRule
+ */
+
+/*!
+ \qmlproperty enumeration QtQuick::StrokeFillParams::joinStyle
+ */
+
+/*!
+ \qmlproperty int QtQuick::StrokeFillParams::miterLimit
+ */
+
+/*!
+ \qmlproperty enumeration QtQuick::StrokeFillParams::capStyle
+ */
+
+/*!
+ \qmlproperty enumeration QtQuick::StrokeFillParams::strokeStyle
+ */
+
+/*!
+ \qmlproperty real QtQuick::StrokeFillParams::dashOffset
+ */
+
+/*!
+ \qmlproperty list<real> QtQuick::StrokeFillParams::dashPattern
+
+ The dash pattern can be specified using JavaScript arrays.
+
+ \code
+ sfp.dashPattern = [ 4, 2 ];
+ \endcode
+ */
+
+/*!
+ \qmlproperty object QtQuick::StrokeFillParams::fillGradient
+
+ Sets the fill gradient. The default value is null. Gradients cannot be
+ created from JavaScript. Instead, reference a PathLinearGradient or other
+ item by id.
+
+ \code
+ PathLinearGradient { id: grad; ... }
+ ...
+ sfp.fillGradient = grad;
+ \endcode
+ */
+
+/*!
+ \qmlmethod void QtQuick::StrokeFillParams::clear()
+
+ Resets all values to their defaults. This is more lightweight than creating
+ a new StrokeFillParams object.
+ */
+
+void QQuickPathItemStrokeFillParamsObject::clear()
+{
+ sfp = QQuickPathItemStrokeFillParams();
+ if (!v4fillGradient.isNullOrUndefined())
+ v4fillGradient.set(v4fillGradient.engine(), nullptr);
+}
+
+void QQuickPathItemStrokeFillParamsObject::setV4Engine(QV4::ExecutionEngine *engine)
+{
+ QQuickPathItemJSEngineData *ed = engineData(engine);
+ QV4::Scope scope(engine);
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> wrapper(scope, engine->memoryManager->allocObject<QQuickPathItemJSStrokeFillParams>());
+ QV4::ScopedObject p(scope, ed->strokeFillParamsProto.value());
+ wrapper->setPrototype(p);
+ wrapper->d()->obj = this;
+ m_v4value = wrapper;
+}
+
+/*!
+ \qmlmethod JSPath QtQuick::PathItem::newPath()
+
+ Creates and returns a new object that describes a path and offers a
+ JavaScript API. Paired with a stroke-fill parameter object it is
+ equivalent to a VisualPath.
+
+ The following two snippets are equivalent when it comes to the end result:
+
+ \code
+ var p = pathItem.newPath();
+ var sfp = pathItem.newStrokeFillParams();
+ sfp.fillColor = "white";
+ sfp.strokeColor = "black";
+ sfp.strokeWidth = 0.172;
+ p.moveTo(-122.304, 84.285);
+ p.cubicTo(-122.304, 84.285, -122.203, 86.179, -123.027, 86.16);
+ pathItem.appendVisualPath(p, sfp);
+ \endcode
+
+ \code
+ PathItem {
+ VisualPath {
+ fillColor: "white"
+ strokeColor: "black"
+ strokeWidth: 0.172
+ Path {
+ startX: -122.304; startY: 84.285
+ PathCubic { control1X: -122.304; control1Y: 84.285; control2X: -122.203; control2Y: 86.179; x: -123.027; y: 86.16 }
+ }
+ }
+ }
+ \endcode
+
+ The latter offers a full declarative API, with the possibility to binding
+ to and animating properties, while the former uses less resources due to
+ greatly reducing the number of QObject instances created.
+*/
+
+void QQuickPathItem::newPath(QQmlV4Function *args)
+{
+ QQuickPathItemPathObject *obj = new QQuickPathItemPathObject(this);
+ obj->setV4Engine(QQmlEnginePrivate::get(qmlEngine(this))->v4engine());
+ args->setReturnValue(obj->v4value());
+}
+
+/*!
+ \qmlmethod StrokeFillParams QtQuick::PathItem::newStrokeFillParams()
+
+ Creates and returns a new object that describes stroke and fill parameters
+ and offers a JavaScript API. Paired with a path object it is equivalent to
+ a VisualPath.
+ */
+
+void QQuickPathItem::newStrokeFillParams(QQmlV4Function *args)
+{
+ QQuickPathItemStrokeFillParamsObject *obj = new QQuickPathItemStrokeFillParamsObject(this);
+ obj->setV4Engine(QQmlEnginePrivate::get(qmlEngine(this))->v4engine());
+ args->setReturnValue(obj->v4value());
+}
+
+/*!
+ \qmlmethod void QtQuick::PathItem::clearVisualPaths()
+
+ Clears the list of visual paths.
+
+ \note This applies only to path and stroke-fill parameter objects registered
+ via appendVisualPaths().
+ */
+
+void QQuickPathItem::clearVisualPaths(QQmlV4Function *args)
+{
+ Q_UNUSED(args);
+ Q_D(QQuickPathItem);
+ d->jsData.paths.clear();
+ d->jsData.sfp.clear();
+}
+
+/*!
+ \qmlmethod void QtQuick::PathItem::commitVisualPaths()
+
+ Updates the PathItem.
+
+ In order to avoid rendering a half-prepared PathItem, calling
+ PathItem.appendVisualPath() does not trigger any processing. Instead,
+ applications must call this function when all path and stroke-fill
+ parameter objects are registered.
+ */
+
+void QQuickPathItem::commitVisualPaths(QQmlV4Function *args)
+{
+ Q_UNUSED(args);
+ Q_D(QQuickPathItem);
+ d->_q_visualPathChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick::PathItem::appendVisualPath(object path, object strokeFillParams)
+
+ Adds the visual path compoes of \a path and \a strokeFillParams into the
+ PathItem.
+
+ \note The declarative and imprative (JavaScript) APIs of PathItem use
+ independent data structures. Calling this function has no effect on the
+ PathItem.elements property and vice versa. Once this function is called,
+ the PathItem will only consider the data registered via this function and
+ will ignore the declarative elements property.
+ */
+
+void QQuickPathItem::appendVisualPath(QQmlV4Function *args)
+{
+ if (args->length() < 2)
+ return;
+
+ Q_D(QQuickPathItem);
+ QV4::Scope scope(args->v4engine());
+ QV4::Scoped<QQuickPathItemJSPath> jsp(scope, (*args)[0]);
+ QV4::Scoped<QQuickPathItemJSStrokeFillParams> jssfp(scope, (*args)[1]);
+
+ const QQuickPathItemPath &path(jsp->d()->obj->path);
+ const QQuickPathItemStrokeFillParams &sfp(jssfp->d()->obj->sfp);
+
+ d->jsData.paths.append(path);
+ d->jsData.sfp.append(sfp);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickpathitem_p.cpp"
diff --git a/src/imports/pathitem/qquickpathitem_p.h b/src/imports/pathitem/qquickpathitem_p.h
new file mode 100644
index 0000000000..c7c56fd5d8
--- /dev/null
+++ b/src/imports/pathitem/qquickpathitem_p.h
@@ -0,0 +1,333 @@
+/****************************************************************************
+**
+** 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 <private/qv8engine_p.h>
+#include <QGradientStops>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickVisualPathPrivate;
+class QQuickPathItemPrivate;
+
+class 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 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 int countStops(QQmlListProperty<QObject> *list);
+ static QObject *atStop(QQmlListProperty<QObject> *list, int index);
+ static void appendStop(QQmlListProperty<QObject> *list, QObject *stop);
+
+ QVector<QObject *> m_stops;
+ SpreadMode m_spread;
+};
+
+class 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 QQuickVisualPath : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QQuickPath *path READ path WRITE setPath NOTIFY pathChanged)
+ Q_CLASSINFO("DefaultProperty", "path")
+
+ 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)
+
+ QQuickVisualPath(QObject *parent = nullptr);
+ ~QQuickVisualPath();
+
+ 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();
+
+Q_SIGNALS:
+ void changed();
+ 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(QQuickVisualPath)
+ Q_DECLARE_PRIVATE(QQuickVisualPath)
+ Q_PRIVATE_SLOT(d_func(), void _q_pathChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_fillGradientChanged())
+};
+
+class QQuickPathItem : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(RendererType renderer READ rendererType NOTIFY rendererChanged)
+ Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged)
+ Q_PROPERTY(bool enableVendorExtensions READ enableVendorExtensions WRITE setEnableVendorExtensions NOTIFY enableVendorExtensionsChanged)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QQmlListProperty<QQuickVisualPath> elements READ elements)
+ Q_CLASSINFO("DefaultProperty", "elements")
+
+public:
+ enum RendererType {
+ UnknownRenderer,
+ GeometryRenderer,
+ NvprRenderer,
+ SoftwareRenderer
+ };
+ Q_ENUM(RendererType)
+
+ enum Status {
+ Null,
+ Ready,
+ Processing
+ };
+ Q_ENUM(Status)
+
+ QQuickPathItem(QQuickItem *parent = nullptr);
+ ~QQuickPathItem();
+
+ RendererType rendererType() const;
+
+ bool asynchronous() const;
+ void setAsynchronous(bool async);
+
+ bool enableVendorExtensions() const;
+ void setEnableVendorExtensions(bool enable);
+
+ Status status() const;
+
+ QQmlListProperty<QQuickVisualPath> elements();
+
+ Q_INVOKABLE void newPath(QQmlV4Function *args);
+ Q_INVOKABLE void newStrokeFillParams(QQmlV4Function *args);
+ Q_INVOKABLE void clearVisualPaths(QQmlV4Function *args);
+ Q_INVOKABLE void commitVisualPaths(QQmlV4Function *args);
+ Q_INVOKABLE void appendVisualPath(QQmlV4Function *args);
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override;
+ void updatePolish() override;
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ void componentComplete() override;
+ void classBegin() override;
+
+Q_SIGNALS:
+ void rendererChanged();
+ void asynchronousChanged();
+ void enableVendorExtensionsChanged();
+ void statusChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickPathItem)
+ Q_DECLARE_PRIVATE(QQuickPathItem)
+ Q_PRIVATE_SLOT(d_func(), void _q_visualPathChanged())
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPathItem)
+
+#endif // QQUICKPATHITEM_P_H
diff --git a/src/imports/pathitem/qquickpathitem_p_p.h b/src/imports/pathitem/qquickpathitem_p_p.h
new file mode 100644
index 0000000000..6dde314a30
--- /dev/null
+++ b/src/imports/pathitem/qquickpathitem_p_p.h
@@ -0,0 +1,282 @@
+/****************************************************************************
+**
+** 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 <QtQuick/private/qquickitem_p.h>
+#include <QPainterPath>
+#include <QColor>
+#include <QBrush>
+#include <private/qopenglcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGPlainTexture;
+
+struct QQuickPathItemPath
+{
+ enum Command {
+ MoveTo,
+ LineTo,
+ QuadTo,
+ CubicTo,
+ ArcTo
+ };
+
+ QVector<Command> cmd;
+ QVector<float> coords;
+
+ QPainterPath toPainterPath() const;
+};
+
+struct QQuickPathItemStrokeFillParams
+{
+ QQuickPathItemStrokeFillParams();
+
+ QColor strokeColor;
+ qreal strokeWidth;
+ QColor fillColor;
+ QQuickVisualPath::FillRule fillRule;
+ QQuickVisualPath::JoinStyle joinStyle;
+ int miterLimit;
+ QQuickVisualPath::CapStyle capStyle;
+ QQuickVisualPath::StrokeStyle strokeStyle;
+ qreal dashOffset;
+ QVector<qreal> dashPattern;
+ QQuickPathGradient *fillGradient;
+};
+
+class QQuickAbstractPathRenderer
+{
+public:
+ enum Flag {
+ SupportsAsync = 0x01
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ virtual ~QQuickAbstractPathRenderer() { }
+
+ // Gui thread
+ virtual void beginSync(int totalCount) = 0;
+ virtual void endSync(bool async) = 0;
+ virtual void setAsyncCallback(void (*)(void *), void *) { }
+ virtual Flags flags() const { return 0; }
+ // - QML API
+ virtual void setPath(int index, const QQuickPath *path) = 0;
+ // - JS API
+ virtual void setJSPath(int index, const QQuickPathItemPath &path) = 0;
+ // - stroke/fill parameters
+ virtual void setStrokeColor(int index, const QColor &color) = 0;
+ virtual void setStrokeWidth(int index, qreal w) = 0;
+ virtual void setFillColor(int index, const QColor &color) = 0;
+ virtual void setFillRule(int index, QQuickVisualPath::FillRule fillRule) = 0;
+ virtual void setJoinStyle(int index, QQuickVisualPath::JoinStyle joinStyle, int miterLimit) = 0;
+ virtual void setCapStyle(int index, QQuickVisualPath::CapStyle capStyle) = 0;
+ virtual void setStrokeStyle(int index, QQuickVisualPath::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern) = 0;
+ virtual void setFillGradient(int index, QQuickPathGradient *gradient) = 0;
+
+ // Render thread, with gui blocked
+ virtual void updateNode() = 0;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickAbstractPathRenderer::Flags)
+
+class QQuickVisualPathPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickVisualPath)
+
+public:
+ enum Dirty {
+ DirtyPath = 0x01,
+ DirtyStrokeColor = 0x02,
+ DirtyStrokeWidth = 0x04,
+ DirtyFillColor = 0x08,
+ DirtyFillRule = 0x10,
+ DirtyStyle = 0x20,
+ DirtyDash = 0x40,
+ DirtyFillGradient = 0x80,
+
+ DirtyAll = 0xFF
+ };
+
+ QQuickVisualPathPrivate();
+
+ void _q_pathChanged();
+ void _q_fillGradientChanged();
+
+ static QQuickVisualPathPrivate *get(QQuickVisualPath *p) { return p->d_func(); }
+
+ QQuickPath *path;
+ int dirty;
+ QQuickPathItemStrokeFillParams sfp;
+};
+
+class QQuickPathItemPrivate : public QQuickItemPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPathItem)
+
+public:
+ QQuickPathItemPrivate();
+ ~QQuickPathItemPrivate();
+
+ void createRenderer();
+ QSGNode *createNode();
+ void sync();
+
+ void _q_visualPathChanged();
+ void setStatus(QQuickPathItem::Status newStatus);
+
+ static QQuickPathItemPrivate *get(QQuickPathItem *item) { return item->d_func(); }
+
+ bool componentComplete;
+ bool vpChanged;
+ QQuickPathItem::RendererType rendererType;
+ bool async;
+ QQuickPathItem::Status status;
+ QQuickAbstractPathRenderer *renderer;
+
+ struct {
+ QVector<QQuickVisualPath *> vp;
+ } qmlData;
+
+ struct {
+ bool isValid() const { Q_ASSERT(paths.count() == sfp.count()); return !paths.isEmpty(); }
+ QVector<QQuickPathItemPath> paths;
+ QVector<QQuickPathItemStrokeFillParams> sfp;
+ } jsData;
+
+ bool enableVendorExts;
+};
+
+class QQuickPathItemPathObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ QQuickPathItemPathObject(QObject *parent = nullptr) : QObject(parent) { }
+
+ void setV4Engine(QV4::ExecutionEngine *engine);
+ QV4::ReturnedValue v4value() const { return m_v4value.value(); }
+
+ QQuickPathItemPath path;
+
+ void clear();
+
+private:
+ QV4::PersistentValue m_v4value;
+};
+
+class QQuickPathItemStrokeFillParamsObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ QQuickPathItemStrokeFillParamsObject(QObject *parent = nullptr) : QObject(parent) { }
+
+ void setV4Engine(QV4::ExecutionEngine *engine);
+ QV4::ReturnedValue v4value() const { return m_v4value.value(); }
+
+ QQuickPathItemStrokeFillParams sfp;
+ QV4::PersistentValue v4fillGradient;
+
+ void clear();
+
+private:
+ QV4::PersistentValue m_v4value;
+};
+
+#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/imports/pathitem/qquickpathitemgenericrenderer.cpp b/src/imports/pathitem/qquickpathitemgenericrenderer.cpp
new file mode 100644
index 0000000000..4e8fe55df2
--- /dev/null
+++ b/src/imports/pathitem/qquickpathitemgenericrenderer.cpp
@@ -0,0 +1,775 @@
+/****************************************************************************
+**
+** 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 <QtGui/private/qtriangulatingstroker_p.h>
+#include <QThreadPool>
+
+#ifndef QT_NO_OPENGL
+#include <QSGVertexColorMaterial>
+#include <QOpenGLContext>
+#include <QOffscreenSurface>
+#include <QtGui/private/qopenglextensions_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static const qreal TRI_SCALE = 1;
+
+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;
+}
+
+QQuickPathItemGenericStrokeFillNode::QQuickPathItemGenericStrokeFillNode(QQuickWindow *window)
+ : m_geometry(new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0)),
+ m_window(window),
+ m_material(nullptr)
+{
+ setGeometry(m_geometry);
+ activateMaterial(MatSolidColor);
+#ifdef QSG_RUNTIME_DESCRIPTION
+ qsgnode_set_description(this, QLatin1String("stroke-fill"));
+#endif
+}
+
+QQuickPathItemGenericStrokeFillNode::~QQuickPathItemGenericStrokeFillNode()
+{
+ delete m_geometry;
+}
+
+void QQuickPathItemGenericStrokeFillNode::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);
+}
+
+static bool q_supportsElementIndexUint(QSGRendererInterface::GraphicsApi api)
+{
+ static bool elementIndexUint = true;
+#ifndef QT_NO_OPENGL
+ if (api == QSGRendererInterface::OpenGL) {
+ static bool elementIndexUintChecked = false;
+ if (!elementIndexUintChecked) {
+ elementIndexUintChecked = true;
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ QScopedPointer<QOpenGLContext> dummyContext;
+ QScopedPointer<QOffscreenSurface> dummySurface;
+ bool ok = true;
+ if (!context) {
+ dummyContext.reset(new QOpenGLContext);
+ dummyContext->create();
+ context = dummyContext.data();
+ dummySurface.reset(new QOffscreenSurface);
+ dummySurface->setFormat(context->format());
+ dummySurface->create();
+ ok = context->makeCurrent(dummySurface.data());
+ }
+ if (ok) {
+ elementIndexUint = static_cast<QOpenGLExtensions *>(context->functions())->hasOpenGLExtension(
+ QOpenGLExtensions::ElementIndexUint);
+ }
+ }
+ }
+#else
+ Q_UNUSED(api);
+#endif
+ return elementIndexUint;
+}
+
+QQuickPathItemGenericRenderer::~QQuickPathItemGenericRenderer()
+{
+ for (VisualPathData &d : m_vp) {
+ if (d.pendingFill)
+ d.pendingFill->orphaned = true;
+ if (d.pendingStroke)
+ d.pendingStroke->orphaned = true;
+ }
+}
+
+// sync, and so triangulation too, happens on the gui thread
+// - except when async is set, in which case triangulation is moved to worker threads
+
+void QQuickPathItemGenericRenderer::beginSync(int totalCount)
+{
+ if (m_vp.count() != totalCount) {
+ m_vp.resize(totalCount);
+ m_accDirty |= DirtyList;
+ }
+ for (VisualPathData &d : m_vp)
+ d.syncDirty = 0;
+}
+
+void QQuickPathItemGenericRenderer::setPath(int index, const QQuickPath *path)
+{
+ VisualPathData &d(m_vp[index]);
+ d.path = path ? path->path() : QPainterPath();
+ d.syncDirty |= DirtyFillGeom | DirtyStrokeGeom;
+}
+
+void QQuickPathItemGenericRenderer::setJSPath(int index, const QQuickPathItemPath &path)
+{
+ VisualPathData &d(m_vp[index]);
+ d.path = path.toPainterPath();
+ d.syncDirty |= DirtyFillGeom | DirtyStrokeGeom;
+}
+
+void QQuickPathItemGenericRenderer::setStrokeColor(int index, const QColor &color)
+{
+ VisualPathData &d(m_vp[index]);
+ d.strokeColor = colorToColor4ub(color);
+ d.syncDirty |= DirtyColor;
+}
+
+void QQuickPathItemGenericRenderer::setStrokeWidth(int index, qreal w)
+{
+ VisualPathData &d(m_vp[index]);
+ d.strokeWidth = w;
+ if (w >= 0.0f)
+ d.pen.setWidthF(w);
+ d.syncDirty |= DirtyStrokeGeom;
+}
+
+void QQuickPathItemGenericRenderer::setFillColor(int index, const QColor &color)
+{
+ VisualPathData &d(m_vp[index]);
+ d.fillColor = colorToColor4ub(color);
+ d.syncDirty |= DirtyColor;
+}
+
+void QQuickPathItemGenericRenderer::setFillRule(int index, QQuickVisualPath::FillRule fillRule)
+{
+ VisualPathData &d(m_vp[index]);
+ d.fillRule = Qt::FillRule(fillRule);
+ d.syncDirty |= DirtyFillGeom;
+}
+
+void QQuickPathItemGenericRenderer::setJoinStyle(int index, QQuickVisualPath::JoinStyle joinStyle, int miterLimit)
+{
+ VisualPathData &d(m_vp[index]);
+ d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle));
+ d.pen.setMiterLimit(miterLimit);
+ d.syncDirty |= DirtyStrokeGeom;
+}
+
+void QQuickPathItemGenericRenderer::setCapStyle(int index, QQuickVisualPath::CapStyle capStyle)
+{
+ VisualPathData &d(m_vp[index]);
+ d.pen.setCapStyle(Qt::PenCapStyle(capStyle));
+ d.syncDirty |= DirtyStrokeGeom;
+}
+
+void QQuickPathItemGenericRenderer::setStrokeStyle(int index, QQuickVisualPath::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern)
+{
+ VisualPathData &d(m_vp[index]);
+ d.pen.setStyle(Qt::PenStyle(strokeStyle));
+ if (strokeStyle == QQuickVisualPath::DashLine) {
+ d.pen.setDashPattern(dashPattern);
+ d.pen.setDashOffset(dashOffset);
+ }
+ d.syncDirty |= DirtyStrokeGeom;
+}
+
+void QQuickPathItemGenericRenderer::setFillGradient(int index, QQuickPathGradient *gradient)
+{
+ VisualPathData &d(m_vp[index]);
+ d.fillGradientActive = gradient != nullptr;
+ if (gradient) {
+ d.fillGradient.stops = gradient->sortedGradientStops();
+ d.fillGradient.spread = gradient->spread();
+ if (QQuickPathLinearGradient *g = qobject_cast<QQuickPathLinearGradient *>(gradient)) {
+ d.fillGradient.start = QPointF(g->x1(), g->y1());
+ d.fillGradient.end = QPointF(g->x2(), g->y2());
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+ d.syncDirty |= DirtyFillGradient;
+}
+
+void QQuickPathItemFillRunnable::run()
+{
+ QQuickPathItemGenericRenderer::triangulateFill(path, fillColor, &fillVertices, &fillIndices, &indexType, supportsElementIndexUint);
+ emit done(this);
+}
+
+void QQuickPathItemStrokeRunnable::run()
+{
+ QQuickPathItemGenericRenderer::triangulateStroke(path, pen, strokeColor, &strokeVertices, clipSize);
+ emit done(this);
+}
+
+void QQuickPathItemGenericRenderer::setAsyncCallback(void (*callback)(void *), void *data)
+{
+ m_asyncCallback = callback;
+ m_asyncCallbackData = data;
+}
+
+static QThreadPool *pathWorkThreadPool = nullptr;
+
+static void deletePathWorkThreadPool()
+{
+ delete pathWorkThreadPool;
+ pathWorkThreadPool = nullptr;
+}
+
+void QQuickPathItemGenericRenderer::endSync(bool async)
+{
+ bool didKickOffAsync = false;
+
+ for (int i = 0; i < m_vp.count(); ++i) {
+ VisualPathData &d(m_vp[i]);
+ if (!d.syncDirty)
+ continue;
+
+ m_accDirty |= d.syncDirty;
+
+ // 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 updateNode()
+ // on the render thread (with the gui thread blocked). For our purposes
+ // here syncDirty is still required since geometry regeneration must only
+ // happen when there was an actual change in this particular sync round.
+ d.effectiveDirty |= d.syncDirty;
+
+ if (d.path.isEmpty()) {
+ d.fillVertices.clear();
+ d.fillIndices.clear();
+ d.strokeVertices.clear();
+ continue;
+ }
+
+ if (async && !pathWorkThreadPool) {
+ qAddPostRoutine(deletePathWorkThreadPool);
+ pathWorkThreadPool = new QThreadPool;
+ const int idealCount = QThread::idealThreadCount();
+ pathWorkThreadPool->setMaxThreadCount(idealCount > 0 ? idealCount * 2 : 4);
+ }
+
+ if ((d.syncDirty & DirtyFillGeom) && d.fillColor.a) {
+ d.path.setFillRule(d.fillRule);
+ if (m_api == QSGRendererInterface::Unknown)
+ m_api = m_item->window()->rendererInterface()->graphicsApi();
+ if (async) {
+ QQuickPathItemFillRunnable *r = new QQuickPathItemFillRunnable;
+ r->setAutoDelete(false);
+ if (d.pendingFill)
+ d.pendingFill->orphaned = true;
+ d.pendingFill = r;
+ r->path = d.path;
+ r->fillColor = d.fillColor;
+ r->supportsElementIndexUint = q_supportsElementIndexUint(m_api);
+ // Unlikely in practice but in theory m_vp could be
+ // resized. Therefore, capture 'i' instead of 'd'.
+ QObject::connect(r, &QQuickPathItemFillRunnable::done, qApp, [this, i](QQuickPathItemFillRunnable *r) {
+ // Bail out when orphaned (meaning either another run was
+ // started after this one, or the renderer got destroyed).
+ if (!r->orphaned && i < m_vp.count()) {
+ VisualPathData &d(m_vp[i]);
+ d.fillVertices = r->fillVertices;
+ d.fillIndices = r->fillIndices;
+ d.indexType = r->indexType;
+ d.pendingFill = nullptr;
+ d.effectiveDirty |= DirtyFillGeom;
+ maybeUpdateAsyncItem();
+ }
+ r->deleteLater();
+ });
+ didKickOffAsync = true;
+ pathWorkThreadPool->start(r);
+ } else {
+ triangulateFill(d.path, d.fillColor, &d.fillVertices, &d.fillIndices, &d.indexType, q_supportsElementIndexUint(m_api));
+ }
+ }
+
+ if ((d.syncDirty & DirtyStrokeGeom) && d.strokeWidth >= 0.0f && d.strokeColor.a) {
+ if (async) {
+ QQuickPathItemStrokeRunnable *r = new QQuickPathItemStrokeRunnable;
+ r->setAutoDelete(false);
+ if (d.pendingStroke)
+ d.pendingStroke->orphaned = true;
+ d.pendingStroke = r;
+ r->path = d.path;
+ r->pen = d.pen;
+ r->strokeColor = d.strokeColor;
+ r->clipSize = QSize(m_item->width(), m_item->height());
+ QObject::connect(r, &QQuickPathItemStrokeRunnable::done, qApp, [this, i](QQuickPathItemStrokeRunnable *r) {
+ if (!r->orphaned && i < m_vp.count()) {
+ VisualPathData &d(m_vp[i]);
+ d.strokeVertices = r->strokeVertices;
+ d.pendingStroke = nullptr;
+ d.effectiveDirty |= DirtyStrokeGeom;
+ maybeUpdateAsyncItem();
+ }
+ r->deleteLater();
+ });
+ didKickOffAsync = true;
+ pathWorkThreadPool->start(r);
+ } else {
+ triangulateStroke(d.path, d.pen, d.strokeColor, &d.strokeVertices,
+ QSize(m_item->width(), m_item->height()));
+ }
+ }
+ }
+
+ if (!didKickOffAsync && async && m_asyncCallback)
+ m_asyncCallback(m_asyncCallbackData);
+}
+
+void QQuickPathItemGenericRenderer::maybeUpdateAsyncItem()
+{
+ for (const VisualPathData &d : qAsConst(m_vp)) {
+ if (d.pendingFill || d.pendingStroke)
+ return;
+ }
+ m_accDirty |= DirtyFillGeom | DirtyStrokeGeom;
+ m_item->update();
+ if (m_asyncCallback)
+ m_asyncCallback(m_asyncCallbackData);
+}
+
+// the stroke/fill triangulation functions may be invoked either on the gui
+// thread or some worker thread and must thus be self-contained.
+void QQuickPathItemGenericRenderer::triangulateFill(const QPainterPath &path,
+ const Color4ub &fillColor,
+ VertexContainerType *fillVertices,
+ IndexContainerType *fillIndices,
+ QSGGeometry::Type *indexType,
+ bool supportsElementIndexUint)
+{
+ const QVectorPath &vp = qtVectorPathForPath(path);
+
+ QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(TRI_SCALE, TRI_SCALE), 1, supportsElementIndexUint);
+ const int vertexCount = ts.vertices.count() / 2; // just a qreal vector with x,y hence the / 2
+ fillVertices->resize(vertexCount);
+ ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(fillVertices->data());
+ const qreal *vsrc = ts.vertices.constData();
+ for (int i = 0; i < vertexCount; ++i)
+ vdst[i].set(vsrc[i * 2] / TRI_SCALE, vsrc[i * 2 + 1] / TRI_SCALE, fillColor);
+
+ size_t indexByteSize;
+ if (ts.indices.type() == QVertexIndexVector::UnsignedShort) {
+ *indexType = QSGGeometry::UnsignedShortType;
+ // fillIndices is still QVector<quint32>. Just resize to N/2 and pack
+ // the N quint16s into it.
+ fillIndices->resize(ts.indices.size() / 2);
+ indexByteSize = ts.indices.size() * sizeof(quint16);
+ } else {
+ *indexType = QSGGeometry::UnsignedIntType;
+ fillIndices->resize(ts.indices.size());
+ indexByteSize = ts.indices.size() * sizeof(quint32);
+ }
+ memcpy(fillIndices->data(), ts.indices.data(), indexByteSize);
+}
+
+void QQuickPathItemGenericRenderer::triangulateStroke(const QPainterPath &path,
+ const QPen &pen,
+ const Color4ub &strokeColor,
+ VertexContainerType *strokeVertices,
+ const QSize &clipSize)
+{
+ const QVectorPath &vp = qtVectorPathForPath(path);
+ const QRectF clip(QPointF(0, 0), clipSize);
+ const qreal inverseScale = 1.0 / TRI_SCALE;
+
+ QTriangulatingStroker stroker;
+ stroker.setInvScale(inverseScale);
+
+ if (pen.style() == Qt::SolidLine) {
+ stroker.process(vp, pen, clip, 0);
+ } else {
+ QDashedStrokeProcessor dashStroker;
+ dashStroker.setInvScale(inverseScale);
+ dashStroker.process(vp, pen, clip, 0);
+ QVectorPath dashStroke(dashStroker.points(), dashStroker.elementCount(),
+ dashStroker.elementTypes(), 0);
+ stroker.process(dashStroke, pen, clip, 0);
+ }
+
+ if (!stroker.vertexCount()) {
+ strokeVertices->clear();
+ return;
+ }
+
+ const int vertexCount = stroker.vertexCount() / 2; // just a float vector with x,y hence the / 2
+ strokeVertices->resize(vertexCount);
+ ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(strokeVertices->data());
+ const float *vsrc = stroker.vertices();
+ for (int i = 0; i < vertexCount; ++i)
+ vdst[i].set(vsrc[i * 2], vsrc[i * 2 + 1], strokeColor);
+}
+
+void QQuickPathItemGenericRenderer::setRootNode(QQuickPathItemGenericNode *node)
+{
+ if (m_rootNode != node) {
+ m_rootNode = node;
+ m_accDirty |= DirtyList;
+ }
+}
+
+// on the render thread with gui blocked
+void QQuickPathItemGenericRenderer::updateNode()
+{
+ if (!m_rootNode || !m_accDirty)
+ return;
+
+// [ m_rootNode ]
+// / / /
+// #0 [ fill ] [ stroke ] [ next ]
+// / / |
+// #1 [ fill ] [ stroke ] [ next ]
+// / / |
+// #2 [ fill ] [ stroke ] [ next ]
+// ...
+// ...
+
+ QQuickPathItemGenericNode **nodePtr = &m_rootNode;
+ QQuickPathItemGenericNode *prevNode = nullptr;
+
+ for (VisualPathData &d : m_vp) {
+ if (!*nodePtr) {
+ *nodePtr = new QQuickPathItemGenericNode;
+ prevNode->m_next = *nodePtr;
+ prevNode->appendChildNode(*nodePtr);
+ }
+
+ QQuickPathItemGenericNode *node = *nodePtr;
+
+ if (m_accDirty & DirtyList)
+ d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient;
+
+ if (!d.effectiveDirty) {
+ prevNode = node;
+ nodePtr = &node->m_next;
+ continue;
+ }
+
+ if (d.fillColor.a == 0) {
+ delete node->m_fillNode;
+ node->m_fillNode = nullptr;
+ } else if (!node->m_fillNode) {
+ node->m_fillNode = new QQuickPathItemGenericStrokeFillNode(m_item->window());
+ if (node->m_strokeNode)
+ node->removeChildNode(node->m_strokeNode);
+ node->appendChildNode(node->m_fillNode);
+ if (node->m_strokeNode)
+ node->appendChildNode(node->m_strokeNode);
+ d.effectiveDirty |= DirtyFillGeom;
+ }
+
+ if (d.strokeWidth < 0.0f || d.strokeColor.a == 0) {
+ delete node->m_strokeNode;
+ node->m_strokeNode = nullptr;
+ } else if (!node->m_strokeNode) {
+ node->m_strokeNode = new QQuickPathItemGenericStrokeFillNode(m_item->window());
+ node->appendChildNode(node->m_strokeNode);
+ d.effectiveDirty |= DirtyStrokeGeom;
+ }
+
+ updateFillNode(&d, node);
+ updateStrokeNode(&d, node);
+
+ d.effectiveDirty = 0;
+
+ prevNode = node;
+ nodePtr = &node->m_next;
+ }
+
+ if (*nodePtr && prevNode) {
+ prevNode->removeChildNode(*nodePtr);
+ delete *nodePtr;
+ *nodePtr = nullptr;
+ }
+
+ m_accDirty = 0;
+}
+
+void QQuickPathItemGenericRenderer::updateShadowDataInNode(VisualPathData *d, QQuickPathItemGenericStrokeFillNode *n)
+{
+ if (d->fillGradientActive) {
+ if (d->effectiveDirty & DirtyFillGradient)
+ n->m_fillGradient = d->fillGradient;
+ }
+}
+
+void QQuickPathItemGenericRenderer::updateFillNode(VisualPathData *d, QQuickPathItemGenericNode *node)
+{
+ if (!node->m_fillNode)
+ return;
+ if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient)))
+ return;
+
+ // Make a copy of the data that will be accessed by the material on
+ // the render thread. This must be done even when we bail out below.
+ QQuickPathItemGenericStrokeFillNode *n = node->m_fillNode;
+ updateShadowDataInNode(d, n);
+
+ QSGGeometry *g = n->m_geometry;
+ if (d->fillVertices.isEmpty()) {
+ if (g->vertexCount() || g->indexCount()) {
+ g->allocate(0, 0);
+ n->markDirty(QSGNode::DirtyGeometry);
+ }
+ return;
+ }
+
+ if (d->fillGradientActive) {
+ n->activateMaterial(QQuickPathItemGenericStrokeFillNode::MatLinearGradient);
+ if (d->effectiveDirty & DirtyFillGradient) {
+ // 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 (!(d->effectiveDirty & DirtyFillGeom))
+ return;
+ }
+ } else {
+ n->activateMaterial(QQuickPathItemGenericStrokeFillNode::MatSolidColor);
+ // fast path for updating only color values when no change in vertex positions
+ if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom)) {
+ ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
+ for (int i = 0; i < g->vertexCount(); ++i)
+ vdst[i].set(vdst[i].x, vdst[i].y, d->fillColor);
+ n->markDirty(QSGNode::DirtyGeometry);
+ return;
+ }
+ }
+
+ const int indexCount = d->indexType == QSGGeometry::UnsignedShortType
+ ? d->fillIndices.count() * 2 : d->fillIndices.count();
+ if (g->indexType() != d->indexType) {
+ g = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(),
+ d->fillVertices.count(), indexCount, d->indexType);
+ n->setGeometry(g);
+ delete n->m_geometry;
+ n->m_geometry = g;
+ } else {
+ g->allocate(d->fillVertices.count(), indexCount);
+ }
+ g->setDrawingMode(QSGGeometry::DrawTriangles);
+ memcpy(g->vertexData(), d->fillVertices.constData(), g->vertexCount() * g->sizeOfVertex());
+ memcpy(g->indexData(), d->fillIndices.constData(), g->indexCount() * g->sizeOfIndex());
+
+ n->markDirty(QSGNode::DirtyGeometry);
+}
+
+void QQuickPathItemGenericRenderer::updateStrokeNode(VisualPathData *d, QQuickPathItemGenericNode *node)
+{
+ if (!node->m_strokeNode)
+ return;
+ if (!(d->effectiveDirty & (DirtyStrokeGeom | DirtyColor)))
+ return;
+
+ QQuickPathItemGenericStrokeFillNode *n = node->m_strokeNode;
+ QSGGeometry *g = n->m_geometry;
+ if (d->strokeVertices.isEmpty()) {
+ if (g->vertexCount() || g->indexCount()) {
+ g->allocate(0, 0);
+ n->markDirty(QSGNode::DirtyGeometry);
+ }
+ return;
+ }
+
+ n->markDirty(QSGNode::DirtyGeometry);
+
+ // Async loading runs update once, bails out above, then updates again once
+ // ready. Set the material dirty then. This is in-line with fill where the
+ // first activateMaterial() achieves the same.
+ if (!g->vertexCount())
+ n->markDirty(QSGNode::DirtyMaterial);
+
+ if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyStrokeGeom)) {
+ ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
+ for (int i = 0; i < g->vertexCount(); ++i)
+ vdst[i].set(vdst[i].x, vdst[i].y, d->strokeColor);
+ return;
+ }
+
+ g->allocate(d->strokeVertices.count(), 0);
+ g->setDrawingMode(QSGGeometry::DrawTriangleStrip);
+ memcpy(g->vertexData(), d->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,
+ QQuickPathItemGenericStrokeFillNode *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());
+
+ QQuickPathItemGenericStrokeFillNode *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);
+
+ QQuickPathItemGenericStrokeFillNode *a = node();
+ QQuickPathItemGenericStrokeFillNode *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->spread - gb->spread)
+ return d;
+
+ 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/imports/pathitem/qquickpathitemgenericrenderer_p.h b/src/imports/pathitem/qquickpathitemgenericrenderer_p.h
new file mode 100644
index 0000000000..70a9e88d2f
--- /dev/null
+++ b/src/imports/pathitem/qquickpathitemgenericrenderer_p.h
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** 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 <qsgrendererinterface.h>
+#include <QtCore/qrunnable.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPathItemGenericNode;
+class QQuickPathItemGenericStrokeFillNode;
+class QQuickPathItemFillRunnable;
+class QQuickPathItemStrokeRunnable;
+
+class QQuickPathItemGenericRenderer : public QQuickAbstractPathRenderer
+{
+public:
+ enum Dirty {
+ DirtyFillGeom = 0x01,
+ DirtyStrokeGeom = 0x02,
+ DirtyColor = 0x04,
+ DirtyFillGradient = 0x08,
+ DirtyList = 0x10 // only for accDirty
+ };
+
+ QQuickPathItemGenericRenderer(QQuickItem *item)
+ : m_item(item),
+ m_api(QSGRendererInterface::Unknown),
+ m_rootNode(nullptr),
+ m_accDirty(0),
+ m_asyncCallback(nullptr)
+ { }
+ ~QQuickPathItemGenericRenderer();
+
+ void beginSync(int totalCount) override;
+ void setPath(int index, const QQuickPath *path) override;
+ void setJSPath(int index, const QQuickPathItemPath &path) override;
+ void setStrokeColor(int index, const QColor &color) override;
+ void setStrokeWidth(int index, qreal w) override;
+ void setFillColor(int index, const QColor &color) override;
+ void setFillRule(int index, QQuickVisualPath::FillRule fillRule) override;
+ void setJoinStyle(int index, QQuickVisualPath::JoinStyle joinStyle, int miterLimit) override;
+ void setCapStyle(int index, QQuickVisualPath::CapStyle capStyle) override;
+ void setStrokeStyle(int index, QQuickVisualPath::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern) override;
+ void setFillGradient(int index, QQuickPathGradient *gradient) override;
+ void endSync(bool async) override;
+ void setAsyncCallback(void (*)(void *), void *) override;
+ Flags flags() const override { return SupportsAsync; }
+
+ void updateNode() override;
+
+ void setRootNode(QQuickPathItemGenericNode *node);
+
+ struct Color4ub { unsigned char r, g, b, a; };
+ typedef QVector<QSGGeometry::ColoredPoint2D> VertexContainerType;
+ typedef QVector<quint32> IndexContainerType;
+
+ static void triangulateFill(const QPainterPath &path,
+ const Color4ub &fillColor,
+ VertexContainerType *fillVertices,
+ IndexContainerType *fillIndices,
+ QSGGeometry::Type *indexType,
+ bool supportsElementIndexUint);
+ static void triangulateStroke(const QPainterPath &path,
+ const QPen &pen,
+ const Color4ub &strokeColor,
+ VertexContainerType *strokeVertices,
+ const QSize &clipSize);
+
+private:
+ void maybeUpdateAsyncItem();
+
+ struct VisualPathData {
+ float strokeWidth;
+ QPen pen;
+ Color4ub strokeColor;
+ Color4ub fillColor;
+ Qt::FillRule fillRule;
+ QPainterPath path;
+ bool fillGradientActive;
+ QQuickPathItemGradientCache::GradientDesc fillGradient;
+ VertexContainerType fillVertices;
+ IndexContainerType fillIndices;
+ QSGGeometry::Type indexType;
+ VertexContainerType strokeVertices;
+ int syncDirty;
+ int effectiveDirty = 0;
+ QQuickPathItemFillRunnable *pendingFill = nullptr;
+ QQuickPathItemStrokeRunnable *pendingStroke = nullptr;
+ };
+
+ void updateShadowDataInNode(VisualPathData *d, QQuickPathItemGenericStrokeFillNode *n);
+ void updateFillNode(VisualPathData *d, QQuickPathItemGenericNode *node);
+ void updateStrokeNode(VisualPathData *d, QQuickPathItemGenericNode *node);
+
+ QQuickItem *m_item;
+ QSGRendererInterface::GraphicsApi m_api;
+ QQuickPathItemGenericNode *m_rootNode;
+ QVector<VisualPathData> m_vp;
+ int m_accDirty;
+ void (*m_asyncCallback)(void *);
+ void *m_asyncCallbackData;
+};
+
+class QQuickPathItemFillRunnable : public QObject, public QRunnable
+{
+ Q_OBJECT
+
+public:
+ void run() override;
+
+ bool orphaned = false;
+
+ // input
+ QPainterPath path;
+ QQuickPathItemGenericRenderer::Color4ub fillColor;
+ bool supportsElementIndexUint;
+
+ // output
+ QQuickPathItemGenericRenderer::VertexContainerType fillVertices;
+ QQuickPathItemGenericRenderer::IndexContainerType fillIndices;
+ QSGGeometry::Type indexType;
+
+Q_SIGNALS:
+ void done(QQuickPathItemFillRunnable *self);
+};
+
+class QQuickPathItemStrokeRunnable : public QObject, public QRunnable
+{
+ Q_OBJECT
+
+public:
+ void run() override;
+
+ bool orphaned = false;
+
+ // input
+ QPainterPath path;
+ QPen pen;
+ QQuickPathItemGenericRenderer::Color4ub strokeColor;
+ QSize clipSize;
+
+ // output
+ QQuickPathItemGenericRenderer::VertexContainerType strokeVertices;
+
+Q_SIGNALS:
+ void done(QQuickPathItemStrokeRunnable *self);
+};
+
+class QQuickPathItemGenericStrokeFillNode : public QSGGeometryNode
+{
+public:
+ QQuickPathItemGenericStrokeFillNode(QQuickWindow *window);
+ ~QQuickPathItemGenericStrokeFillNode();
+
+ enum Material {
+ MatSolidColor,
+ MatLinearGradient
+ };
+
+ void activateMaterial(Material m);
+
+ QQuickWindow *window() const { return m_window; }
+
+ // shadow data for custom materials
+ QQuickPathItemGradientCache::GradientDesc m_fillGradient;
+
+private:
+ QSGGeometry *m_geometry;
+ QQuickWindow *m_window;
+ QSGMaterial *m_material;
+ QScopedPointer<QSGMaterial> m_solidColorMaterial;
+ QScopedPointer<QSGMaterial> m_linearGradientMaterial;
+
+ friend class QQuickPathItemGenericRenderer;
+};
+
+class QQuickPathItemGenericNode : public QSGNode
+{
+public:
+ QQuickPathItemGenericStrokeFillNode *m_fillNode = nullptr;
+ QQuickPathItemGenericStrokeFillNode *m_strokeNode = nullptr;
+ QQuickPathItemGenericNode *m_next = nullptr;
+};
+
+class QQuickPathItemGenericMaterialFactory
+{
+public:
+ static QSGMaterial *createVertexColor(QQuickWindow *window);
+ static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickPathItemGenericStrokeFillNode *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(QQuickPathItemGenericStrokeFillNode *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;
+ }
+
+ QQuickPathItemGenericStrokeFillNode *node() const { return m_node; }
+
+private:
+ QQuickPathItemGenericStrokeFillNode *m_node;
+};
+
+#endif // QT_NO_OPENGL
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPATHITEMGENERICRENDERER_P_H
diff --git a/src/imports/pathitem/qquickpathitemnvprrenderer.cpp b/src/imports/pathitem/qquickpathitemnvprrenderer.cpp
new file mode 100644
index 0000000000..f8504f9985
--- /dev/null
+++ b/src/imports/pathitem/qquickpathitemnvprrenderer.cpp
@@ -0,0 +1,923 @@
+/****************************************************************************
+**
+** 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 <QOpenGLFramebufferObject>
+#include <QOpenGLShaderProgram>
+#include <QOpenGLBuffer>
+#include <private/qquickpath_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickPathItemNvprRenderer::beginSync(int totalCount)
+{
+ if (m_vp.count() != totalCount) {
+ m_vp.resize(totalCount);
+ m_accDirty |= DirtyList;
+ }
+}
+
+void QQuickPathItemNvprRenderer::setPath(int index, const QQuickPath *path)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ convertPath(path, &d);
+ d.dirty |= DirtyPath;
+ m_accDirty |= DirtyPath;
+}
+
+void QQuickPathItemNvprRenderer::setJSPath(int index, const QQuickPathItemPath &path)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ convertJSPath(path, &d);
+ d.dirty |= DirtyPath;
+ m_accDirty |= DirtyPath;
+}
+
+void QQuickPathItemNvprRenderer::setStrokeColor(int index, const QColor &color)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.strokeColor = color;
+ d.dirty |= DirtyStyle;
+ m_accDirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setStrokeWidth(int index, qreal w)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.strokeWidth = w;
+ d.dirty |= DirtyStyle;
+ m_accDirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setFillColor(int index, const QColor &color)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.fillColor = color;
+ d.dirty |= DirtyStyle;
+ m_accDirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setFillRule(int index, QQuickVisualPath::FillRule fillRule)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.fillRule = fillRule;
+ d.dirty |= DirtyFillRule;
+ m_accDirty |= DirtyFillRule;
+}
+
+void QQuickPathItemNvprRenderer::setJoinStyle(int index, QQuickVisualPath::JoinStyle joinStyle, int miterLimit)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.joinStyle = joinStyle;
+ d.miterLimit = miterLimit;
+ d.dirty |= DirtyStyle;
+ m_accDirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setCapStyle(int index, QQuickVisualPath::CapStyle capStyle)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.capStyle = capStyle;
+ d.dirty |= DirtyStyle;
+ m_accDirty |= DirtyStyle;
+}
+
+void QQuickPathItemNvprRenderer::setStrokeStyle(int index, QQuickVisualPath::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.dashActive = strokeStyle == QQuickVisualPath::DashLine;
+ d.dashOffset = dashOffset;
+ d.dashPattern = dashPattern;
+ d.dirty |= DirtyDash;
+ m_accDirty |= DirtyDash;
+}
+
+void QQuickPathItemNvprRenderer::setFillGradient(int index, QQuickPathGradient *gradient)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.fillGradientActive = gradient != nullptr;
+ if (gradient) {
+ d.fillGradient.stops = gradient->sortedGradientStops();
+ d.fillGradient.spread = gradient->spread();
+ if (QQuickPathLinearGradient *g = qobject_cast<QQuickPathLinearGradient *>(gradient)) {
+ d.fillGradient.start = QPointF(g->x1(), g->y1());
+ d.fillGradient.end = QPointF(g->x2(), g->y2());
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+ d.dirty |= DirtyFillGradient;
+ m_accDirty |= DirtyFillGradient;
+}
+
+void QQuickPathItemNvprRenderer::endSync(bool)
+{
+}
+
+void QQuickPathItemNvprRenderer::setNode(QQuickPathItemNvprRenderNode *node)
+{
+ if (m_node != node) {
+ m_node = node;
+ m_accDirty |= DirtyList;
+ }
+}
+
+QDebug operator<<(QDebug debug, const QQuickPathItemNvprRenderer::NvprPath &path)
+{
+ QDebugStateSaver saver(debug);
+ debug.space().noquote();
+ if (!path.str.isEmpty()) {
+ debug << "Path with SVG string" << path.str;
+ return debug;
+ }
+ 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, VisualPathGuiData *d)
+{
+ d->path = NvprPath();
+ if (!path)
+ return;
+
+ const QList<QQuickPathElement *> &pp(QQuickPathPrivate::get(path)->_pathElements);
+ if (pp.isEmpty())
+ return;
+
+ QPointF startPos(path->startX(), path->startY());
+ QPointF pos(startPos);
+ if (!qFuzzyIsNull(pos.x()) || !qFuzzyIsNull(pos.y())) {
+ d->path.cmd.append(GL_MOVE_TO_NV);
+ d->path.coord.append(pos.x());
+ d->path.coord.append(pos.y());
+ }
+
+ for (QQuickPathElement *e : pp) {
+ if (QQuickPathMove *o = qobject_cast<QQuickPathMove *>(e)) {
+ d->path.cmd.append(GL_MOVE_TO_NV);
+ appendCoords(&d->path.coord, o, &pos);
+ startPos = pos;
+ } else if (QQuickPathLine *o = qobject_cast<QQuickPathLine *>(e)) {
+ d->path.cmd.append(GL_LINE_TO_NV);
+ appendCoords(&d->path.coord, o, &pos);
+ } else if (QQuickPathQuad *o = qobject_cast<QQuickPathQuad *>(e)) {
+ d->path.cmd.append(GL_QUADRATIC_CURVE_TO_NV);
+ appendControlCoords(&d->path.coord, o, pos);
+ appendCoords(&d->path.coord, o, &pos);
+ } else if (QQuickPathCubic *o = qobject_cast<QQuickPathCubic *>(e)) {
+ d->path.cmd.append(GL_CUBIC_CURVE_TO_NV);
+ appendControl1Coords(&d->path.coord, o, pos);
+ appendControl2Coords(&d->path.coord, o, pos);
+ appendCoords(&d->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;
+ d->path.cmd.append(cmd);
+ d->path.coord.append(o->radiusX());
+ d->path.coord.append(o->radiusY());
+ d->path.coord.append(o->xAxisRotation());
+ appendCoords(&d->path.coord, o, &pos);
+ } else if (QQuickPathSvg *o = qobject_cast<QQuickPathSvg *>(e)) {
+ // PathSvg cannot be combined with other elements. But take at
+ // least startX and startY into account.
+ if (d->path.str.isEmpty())
+ d->path.str = QString(QStringLiteral("M %1 %2 ")).arg(pos.x()).arg(pos.y()).toUtf8();
+ d->path.str.append(o->path().toUtf8());
+ } else {
+ qWarning() << "PathItem/NVPR: unsupported Path element" << e;
+ }
+ }
+
+ // For compatibility with QTriangulatingStroker. SVG and others would not
+ // implicitly close the path when end_pos == start_pos (start_pos being the
+ // last moveTo pos); that would still need an explicit 'z' or similar. We
+ // don't have an explicit close command, so just fake a close when the
+ // positions match.
+ if (pos == startPos)
+ d->path.cmd.append(GL_CLOSE_PATH_NV);
+}
+
+void QQuickPathItemNvprRenderer::convertJSPath(const QQuickPathItemPath &path, VisualPathGuiData *d)
+{
+ d->path = NvprPath();
+ if (path.cmd.isEmpty())
+ return;
+
+ QPointF startPos(0, 0);
+ QPointF pos(startPos);
+ int coordIdx = 0;
+
+ for (QQuickPathItemPath::Command cmd : path.cmd) {
+ switch (cmd) {
+ case QQuickPathItemPath::MoveTo:
+ d->path.cmd.append(GL_MOVE_TO_NV);
+ pos = QPointF(path.coords[coordIdx], path.coords[coordIdx + 1]);
+ startPos = pos;
+ d->path.coord.append(pos.x());
+ d->path.coord.append(pos.y());
+ coordIdx += 2;
+ break;
+ case QQuickPathItemPath::LineTo:
+ d->path.cmd.append(GL_LINE_TO_NV);
+ pos = QPointF(path.coords[coordIdx], path.coords[coordIdx + 1]);
+ d->path.coord.append(pos.x());
+ d->path.coord.append(pos.y());
+ coordIdx += 2;
+ break;
+ case QQuickPathItemPath::QuadTo:
+ d->path.cmd.append(GL_QUADRATIC_CURVE_TO_NV);
+ d->path.coord.append(path.coords[coordIdx]);
+ d->path.coord.append(path.coords[coordIdx + 1]);
+ pos = QPointF(path.coords[coordIdx + 2], path.coords[coordIdx + 3]);
+ d->path.coord.append(pos.x());
+ d->path.coord.append(pos.y());
+ coordIdx += 4;
+ break;
+ case QQuickPathItemPath::CubicTo:
+ d->path.cmd.append(GL_CUBIC_CURVE_TO_NV);
+ d->path.coord.append(path.coords[coordIdx]);
+ d->path.coord.append(path.coords[coordIdx + 1]);
+ d->path.coord.append(path.coords[coordIdx + 2]);
+ d->path.coord.append(path.coords[coordIdx + 3]);
+ pos = QPointF(path.coords[coordIdx + 4], path.coords[coordIdx + 5]);
+ d->path.coord.append(pos.x());
+ d->path.coord.append(pos.y());
+ coordIdx += 6;
+ break;
+ case QQuickPathItemPath::ArcTo:
+ {
+ const bool sweepFlag = !qFuzzyIsNull(path.coords[coordIdx + 5]);
+ const bool useLargeArc = !qFuzzyIsNull(path.coords[coordIdx + 6]);
+ GLenum cmd;
+ if (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;
+ d->path.cmd.append(cmd);
+ d->path.coord.append(path.coords[coordIdx]); // rx
+ d->path.coord.append(path.coords[coordIdx + 1]); // ry
+ d->path.coord.append(path.coords[coordIdx + 2]); // xrot
+ pos = QPointF(path.coords[coordIdx + 3], path.coords[coordIdx + 4]);
+ d->path.coord.append(pos.x());
+ d->path.coord.append(pos.y());
+ coordIdx += 7;
+ }
+ break;
+ default:
+ qWarning("Unknown JS path command: %d", cmd);
+ break;
+ }
+ }
+
+ if (pos == startPos)
+ d->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::updateNode()
+{
+ // Called on the render thread with gui blocked -> update the node with its
+ // own copy of all relevant data.
+
+ if (!m_accDirty)
+ return;
+
+ const int count = m_vp.count();
+ const bool listChanged = m_accDirty & DirtyList;
+ if (listChanged)
+ m_node->m_vp.resize(count);
+
+ for (int i = 0; i < count; ++i) {
+ VisualPathGuiData &src(m_vp[i]);
+ QQuickPathItemNvprRenderNode::VisualPathRenderData &dst(m_node->m_vp[i]);
+
+ int dirty = src.dirty;
+ src.dirty = 0;
+ if (listChanged)
+ dirty |= DirtyPath | DirtyStyle | DirtyFillRule | DirtyDash | DirtyFillGradient;
+
+ // updateNode() can be called several times with different dirty
+ // states before render() gets invoked. So accumulate.
+ dst.dirty |= dirty;
+
+ if (dirty & DirtyPath)
+ dst.source = src.path;
+
+ if (dirty & DirtyStyle) {
+ dst.strokeWidth = src.strokeWidth;
+ dst.strokeColor = qsg_premultiply(src.strokeColor, 1.0f);
+ dst.fillColor = qsg_premultiply(src.fillColor, 1.0f);
+ switch (src.joinStyle) {
+ case QQuickVisualPath::MiterJoin:
+ dst.joinStyle = GL_MITER_TRUNCATE_NV;
+ break;
+ case QQuickVisualPath::BevelJoin:
+ dst.joinStyle = GL_BEVEL_NV;
+ break;
+ case QQuickVisualPath::RoundJoin:
+ dst.joinStyle = GL_ROUND_NV;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ dst.miterLimit = src.miterLimit;
+ switch (src.capStyle) {
+ case QQuickVisualPath::FlatCap:
+ dst.capStyle = GL_FLAT;
+ break;
+ case QQuickVisualPath::SquareCap:
+ dst.capStyle = GL_SQUARE_NV;
+ break;
+ case QQuickVisualPath::RoundCap:
+ dst.capStyle = GL_ROUND_NV;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+
+ if (dirty & DirtyFillRule) {
+ switch (src.fillRule) {
+ case QQuickVisualPath::OddEvenFill:
+ dst.fillRule = GL_INVERT;
+ break;
+ case QQuickVisualPath::WindingFill:
+ dst.fillRule = GL_COUNT_UP_NV;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ }
+
+ if (dirty & DirtyDash) {
+ dst.dashOffset = src.dashOffset;
+ if (src.dashActive) {
+ dst.dashPattern.resize(src.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 < src.dashPattern.count(); ++i)
+ dst.dashPattern[i] = GLfloat(src.dashPattern[i]) * src.strokeWidth;
+ } else {
+ dst.dashPattern.clear();
+ }
+ }
+
+ if (dirty & DirtyFillGradient) {
+ dst.fillGradientActive = src.fillGradientActive;
+ if (src.fillGradientActive)
+ dst.fillGradient = src.fillGradient;
+ }
+ }
+
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ m_accDirty = 0;
+}
+
+bool QQuickPathItemNvprRenderNode::nvprInited = false;
+QQuickNvprFunctions QQuickPathItemNvprRenderNode::nvpr;
+QQuickNvprMaterialManager QQuickPathItemNvprRenderNode::mtlmgr;
+
+QQuickPathItemNvprRenderNode::~QQuickPathItemNvprRenderNode()
+{
+ releaseResources();
+}
+
+void QQuickPathItemNvprRenderNode::releaseResources()
+{
+ for (VisualPathRenderData &d : m_vp) {
+ if (d.path) {
+ nvpr.deletePaths(d.path, 1);
+ d.path = 0;
+ }
+ if (d.fallbackFbo) {
+ delete d.fallbackFbo;
+ d.fallbackFbo = nullptr;
+ }
+ }
+
+ m_fallbackBlitter.destroy();
+}
+
+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(VisualPathRenderData *d)
+{
+ if (d->dirty & QQuickPathItemNvprRenderer::DirtyPath) {
+ if (!d->path) {
+ d->path = nvpr.genPaths(1);
+ Q_ASSERT(d->path != 0);
+ }
+ if (d->source.str.isEmpty()) {
+ nvpr.pathCommands(d->path, d->source.cmd.count(), d->source.cmd.constData(),
+ d->source.coord.count(), GL_FLOAT, d->source.coord.constData());
+ } else {
+ nvpr.pathString(d->path, GL_PATH_FORMAT_SVG_NV, d->source.str.count(), d->source.str.constData());
+ }
+ }
+
+ if (d->dirty & QQuickPathItemNvprRenderer::DirtyStyle) {
+ nvpr.pathParameterf(d->path, GL_PATH_STROKE_WIDTH_NV, d->strokeWidth);
+ nvpr.pathParameteri(d->path, GL_PATH_JOIN_STYLE_NV, d->joinStyle);
+ nvpr.pathParameteri(d->path, GL_PATH_MITER_LIMIT_NV, d->miterLimit);
+ nvpr.pathParameteri(d->path, GL_PATH_END_CAPS_NV, d->capStyle);
+ nvpr.pathParameteri(d->path, GL_PATH_DASH_CAPS_NV, d->capStyle);
+ }
+
+ if (d->dirty & QQuickPathItemNvprRenderer::DirtyDash) {
+ nvpr.pathParameterf(d->path, GL_PATH_DASH_OFFSET_NV, d->dashOffset);
+ // count == 0 -> no dash
+ nvpr.pathDashArray(d->path, d->dashPattern.count(), d->dashPattern.constData());
+ }
+
+ if (d->dirty)
+ d->fallbackValid = false;
+}
+
+void QQuickPathItemNvprRenderNode::renderStroke(VisualPathRenderData *d, int strokeStencilValue, int writeMask)
+{
+ QQuickNvprMaterialManager::MaterialDesc *mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid);
+ f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0],
+ d->strokeColor.x(), d->strokeColor.y(), d->strokeColor.z(), d->strokeColor.w());
+ f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity());
+
+ nvpr.stencilThenCoverStrokePath(d->path, strokeStencilValue, writeMask, GL_CONVEX_HULL_NV);
+}
+
+void QQuickPathItemNvprRenderNode::renderFill(VisualPathRenderData *d)
+{
+ QQuickNvprMaterialManager::MaterialDesc *mtl = nullptr;
+ if (d->fillGradientActive) {
+ mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatLinearGradient);
+ QSGTexture *tx = QQuickPathItemGradientCache::currentCache()->get(d->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], d->fillGradient.start.x(), d->fillGradient.start.y());
+ f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], d->fillGradient.end.x(), d->fillGradient.end.y());
+ } else {
+ mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid);
+ f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0],
+ d->fillColor.x(), d->fillColor.y(), d->fillColor.z(), d->fillColor.w());
+ }
+ f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity());
+
+ const int writeMask = 0xFF;
+ nvpr.stencilThenCoverFillPath(d->path, d->fillRule, writeMask, GL_BOUNDING_BOX_NV);
+}
+
+void QQuickPathItemNvprRenderNode::renderOffscreenFill(VisualPathRenderData *d)
+{
+ if (d->fallbackValid && d->fallbackFbo)
+ return;
+
+ GLfloat bb[4];
+ nvpr.getPathParameterfv(d->path, GL_PATH_STROKE_BOUNDING_BOX_NV, bb);
+ QSize sz = QSizeF(bb[2] - bb[0] + 1, bb[3] - bb[1] + 1).toSize();
+ d->fallbackSize = QSize(qMax(32, sz.width()), qMax(32, sz.height()));
+ d->fallbackTopLeft = QPointF(bb[0], bb[1]);
+
+ if (d->fallbackFbo && d->fallbackFbo->size() != d->fallbackSize) {
+ delete d->fallbackFbo;
+ d->fallbackFbo = nullptr;
+ }
+ if (!d->fallbackFbo)
+ d->fallbackFbo = new QOpenGLFramebufferObject(d->fallbackSize, QOpenGLFramebufferObject::CombinedDepthStencil);
+ if (!d->fallbackFbo->bind())
+ return;
+
+ GLint prevViewport[4];
+ f->glGetIntegerv(GL_VIEWPORT, prevViewport);
+
+ f->glViewport(0, 0, d->fallbackSize.width(), d->fallbackSize.height());
+ f->glDisable(GL_DEPTH_TEST);
+ f->glClearColor(0, 0, 0, 0);
+ f->glClearStencil(0);
+ f->glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ f->glStencilFunc(GL_NOTEQUAL, 0, 0xFF);
+ f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ QMatrix4x4 mv;
+ mv.translate(-d->fallbackTopLeft.x(), -d->fallbackTopLeft.y());
+ nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, mv.constData());
+ QMatrix4x4 proj;
+ proj.ortho(0, d->fallbackSize.width(), d->fallbackSize.height(), 0, 1, -1);
+ nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, proj.constData());
+
+ renderFill(d);
+
+ d->fallbackFbo->release();
+ f->glEnable(GL_DEPTH_TEST);
+ f->glViewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3]);
+
+ d->fallbackValid = true;
+}
+
+void QQuickPathItemNvprRenderNode::setupStencilForCover(bool stencilClip, int sv)
+{
+ if (!stencilClip) {
+ // 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->glStencilFunc(GL_NOTEQUAL, 0, 0xFF);
+ f->glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
+ } else {
+ f->glStencilFunc(GL_LESS, sv, 0xFF); // pass if (sv & 0xFF) < (stencil_value & 0xFF)
+ f->glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // dppass: replace with the original value (clip's stencil ref value)
+ }
+}
+
+void QQuickPathItemNvprRenderNode::render(const RenderState *state)
+{
+ f = QOpenGLContext::currentContext()->extraFunctions();
+
+ if (!nvprInited) {
+ if (!nvpr.create()) {
+ qWarning("NVPR init failed");
+ return;
+ }
+ mtlmgr.create(&nvpr);
+ nvprInited = true;
+ }
+
+ f->glUseProgram(0);
+ f->glStencilMask(~0);
+ f->glEnable(GL_STENCIL_TEST);
+
+ const bool stencilClip = state->stencilEnabled();
+ // when true, the stencil buffer already has a clip path with a ref value of sv
+ const int sv = state->stencilValue();
+ const bool hasScissor = state->scissorEnabled();
+
+ if (hasScissor) {
+ // scissor rect is already set, just enable scissoring
+ f->glEnable(GL_SCISSOR_TEST);
+ }
+
+ // 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);
+
+ bool reloadMatrices = true;
+
+ for (VisualPathRenderData &d : m_vp) {
+ updatePath(&d);
+
+ const bool hasFill = d.hasFill();
+ const bool hasStroke = d.hasStroke();
+
+ if (hasFill && stencilClip) {
+ // Fall back to a texture when complex clipping is in use and we have
+ // to fill. Reconciling glStencilFillPath's and the scenegraph's clip
+ // stencil semantics has not succeeded so far...
+ if (hasScissor)
+ f->glDisable(GL_SCISSOR_TEST);
+ renderOffscreenFill(&d);
+ reloadMatrices = true;
+ if (hasScissor)
+ f->glEnable(GL_SCISSOR_TEST);
+ }
+
+ if (reloadMatrices) {
+ reloadMatrices = false;
+ nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, matrix()->constData());
+ nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, state->projectionMatrix()->constData());
+ }
+
+ // Fill!
+ if (hasFill) {
+ if (!stencilClip) {
+ setupStencilForCover(false, 0);
+ renderFill(&d);
+ } else {
+ if (!m_fallbackBlitter.isCreated())
+ m_fallbackBlitter.create();
+ f->glStencilFunc(GL_EQUAL, sv, 0xFF);
+ f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ QMatrix4x4 mv = *matrix();
+ mv.translate(d.fallbackTopLeft.x(), d.fallbackTopLeft.y());
+ m_fallbackBlitter.texturedQuad(d.fallbackFbo->texture(), d.fallbackFbo->size(),
+ *state->projectionMatrix(), mv,
+ inheritedOpacity());
+ }
+ }
+
+ // Stroke!
+ if (hasStroke) {
+ const int strokeStencilValue = 0x80;
+ const int writeMask = 0x80;
+
+ setupStencilForCover(stencilClip, sv);
+ if (stencilClip) {
+ // for the stencil step (eff. read mask == 0xFF & ~writeMask)
+ nvpr.pathStencilFunc(GL_EQUAL, sv, 0xFF);
+ // With stencilCLip == true the read mask for the stencil test before the stencil step is 0x7F.
+ // This assumes the clip stencil value is <= 127.
+ if (sv >= strokeStencilValue)
+ qWarning("PathItem/NVPR: stencil clip ref value %d too large; expect rendering errors", sv);
+ }
+
+ renderStroke(&d, strokeStencilValue, writeMask);
+ }
+
+ if (stencilClip)
+ nvpr.pathStencilFunc(GL_ALWAYS, 0, ~0);
+
+ d.dirty = 0;
+ }
+
+ f->glBindProgramPipeline(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
+}
+
+bool QQuickPathItemNvprRenderNode::isSupported()
+{
+ static const bool nvprDisabled = qEnvironmentVariableIntValue("QT_NO_NVPR") != 0;
+ return !nvprDisabled && QQuickNvprFunctions::isSupported();
+}
+
+bool QQuickNvprBlitter::create()
+{
+ if (isCreated())
+ destroy();
+
+ m_program = new QOpenGLShaderProgram;
+ if (QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile) {
+ m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/items/shaders/shadereffect_core.vert"));
+ m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/items/shaders/shadereffect_core.frag"));
+ } else {
+ m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/items/shaders/shadereffect.vert"));
+ m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/items/shaders/shadereffect.frag"));
+ }
+ m_program->bindAttributeLocation("qt_Vertex", 0);
+ m_program->bindAttributeLocation("qt_MultiTexCoord0", 1);
+ if (!m_program->link())
+ return false;
+
+ m_matrixLoc = m_program->uniformLocation("qt_Matrix");
+ m_opacityLoc = m_program->uniformLocation("qt_Opacity");
+
+ m_buffer = new QOpenGLBuffer;
+ if (!m_buffer->create())
+ return false;
+ m_buffer->bind();
+ m_buffer->allocate(4 * sizeof(GLfloat) * 6);
+ m_buffer->release();
+
+ return true;
+}
+
+void QQuickNvprBlitter::destroy()
+{
+ if (m_program) {
+ delete m_program;
+ m_program = nullptr;
+ }
+ if (m_buffer) {
+ delete m_buffer;
+ m_buffer = nullptr;
+ }
+}
+
+void QQuickNvprBlitter::texturedQuad(GLuint textureId, const QSize &size,
+ const QMatrix4x4 &proj, const QMatrix4x4 &modelview,
+ float opacity)
+{
+ QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions();
+
+ m_program->bind();
+
+ QMatrix4x4 m = proj * modelview;
+ m_program->setUniformValue(m_matrixLoc, m);
+ m_program->setUniformValue(m_opacityLoc, opacity);
+
+ m_buffer->bind();
+
+ if (size != m_prevSize) {
+ m_prevSize = size;
+
+ QPointF p0(size.width() - 1, size.height() - 1);
+ QPointF p1(0, 0);
+ QPointF p2(0, size.height() - 1);
+ QPointF p3(size.width() - 1, 0);
+
+ GLfloat vertices[6 * 4] = {
+ GLfloat(p0.x()), GLfloat(p0.y()), 1, 0,
+ GLfloat(p1.x()), GLfloat(p1.y()), 0, 1,
+ GLfloat(p2.x()), GLfloat(p2.y()), 0, 0,
+
+ GLfloat(p0.x()), GLfloat(p0.y()), 1, 0,
+ GLfloat(p3.x()), GLfloat(p3.y()), 1, 1,
+ GLfloat(p1.x()), GLfloat(p1.y()), 0, 1,
+ };
+
+ m_buffer->write(0, vertices, sizeof(vertices));
+ }
+
+ m_program->enableAttributeArray(0);
+ m_program->enableAttributeArray(1);
+ f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
+ f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (const void *) (2 * sizeof(GLfloat)));
+
+ f->glBindTexture(GL_TEXTURE_2D, textureId);
+
+ f->glDrawArrays(GL_TRIANGLES, 0, 6);
+
+ f->glBindTexture(GL_TEXTURE_2D, 0);
+ m_buffer->release();
+ m_program->release();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/pathitem/qquickpathitemnvprrenderer_p.h b/src/imports/pathitem/qquickpathitemnvprrenderer_p.h
new file mode 100644
index 0000000000..cfe1c7eab9
--- /dev/null
+++ b/src/imports/pathitem/qquickpathitemnvprrenderer_p.h
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** 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 "qquicknvprfunctions_p.h"
+#include <qsgrendernode.h>
+#include <QColor>
+#include <QVector4D>
+#include <QDebug>
+
+#ifndef QT_NO_OPENGL
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPathItemNvprRenderNode;
+class QOpenGLFramebufferObject;
+class QOpenGLBuffer;
+class QOpenGLExtraFunctions;
+
+class QQuickPathItemNvprRenderer : public QQuickAbstractPathRenderer
+{
+public:
+ enum Dirty {
+ DirtyPath = 0x01,
+ DirtyStyle = 0x02,
+ DirtyFillRule = 0x04,
+ DirtyDash = 0x08,
+ DirtyFillGradient = 0x10,
+ DirtyList = 0x20
+ };
+
+ void beginSync(int totalCount) override;
+ void setPath(int index, const QQuickPath *path) override;
+ void setJSPath(int index, const QQuickPathItemPath &path) override;
+ void setStrokeColor(int index, const QColor &color) override;
+ void setStrokeWidth(int index, qreal w) override;
+ void setFillColor(int index, const QColor &color) override;
+ void setFillRule(int index, QQuickVisualPath::FillRule fillRule) override;
+ void setJoinStyle(int index, QQuickVisualPath::JoinStyle joinStyle, int miterLimit) override;
+ void setCapStyle(int index, QQuickVisualPath::CapStyle capStyle) override;
+ void setStrokeStyle(int index, QQuickVisualPath::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern) override;
+ void setFillGradient(int index, QQuickPathGradient *gradient) override;
+ void endSync(bool async) override;
+
+ void updateNode() override;
+
+ void setNode(QQuickPathItemNvprRenderNode *node);
+
+ struct NvprPath {
+ QVector<GLubyte> cmd;
+ QVector<GLfloat> coord;
+ QByteArray str;
+ };
+
+private:
+ struct VisualPathGuiData {
+ int dirty = 0;
+ NvprPath path;
+ qreal strokeWidth;
+ QColor strokeColor;
+ QColor fillColor;
+ QQuickVisualPath::JoinStyle joinStyle;
+ int miterLimit;
+ QQuickVisualPath::CapStyle capStyle;
+ QQuickVisualPath::FillRule fillRule;
+ bool dashActive;
+ qreal dashOffset;
+ QVector<qreal> dashPattern;
+ bool fillGradientActive;
+ QQuickPathItemGradientCache::GradientDesc fillGradient;
+ };
+
+ void convertPath(const QQuickPath *path, VisualPathGuiData *d);
+ void convertJSPath(const QQuickPathItemPath &path, VisualPathGuiData *d);
+
+ QQuickPathItemNvprRenderNode *m_node = nullptr;
+ int m_accDirty = 0;
+
+ QVector<VisualPathGuiData> m_vp;
+};
+
+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 QQuickNvprBlitter
+{
+public:
+ bool create();
+ void destroy();
+ bool isCreated() const { return m_program != nullptr; }
+ void texturedQuad(GLuint textureId, const QSize &size,
+ const QMatrix4x4 &proj, const QMatrix4x4 &modelview,
+ float opacity);
+
+private:
+ QOpenGLShaderProgram *m_program = nullptr;
+ QOpenGLBuffer *m_buffer = nullptr;
+ int m_matrixLoc;
+ int m_opacityLoc;
+ QSize m_prevSize;
+};
+
+class QQuickPathItemNvprRenderNode : public QSGRenderNode
+{
+public:
+ ~QQuickPathItemNvprRenderNode();
+
+ void render(const RenderState *state) override;
+ void releaseResources() override;
+ StateFlags changedStates() const override;
+ RenderingFlags flags() const override;
+
+ static bool isSupported();
+
+private:
+ struct VisualPathRenderData {
+ GLuint path = 0;
+ int dirty = 0;
+ QQuickPathItemNvprRenderer::NvprPath source;
+ GLfloat strokeWidth;
+ QVector4D strokeColor;
+ QVector4D fillColor;
+ GLenum joinStyle;
+ GLint miterLimit;
+ GLenum capStyle;
+ GLenum fillRule;
+ GLfloat dashOffset;
+ QVector<GLfloat> dashPattern;
+ bool fillGradientActive;
+ QQuickPathItemGradientCache::GradientDesc fillGradient;
+ QOpenGLFramebufferObject *fallbackFbo = nullptr;
+ bool fallbackValid = false;
+ QSize fallbackSize;
+ QPointF fallbackTopLeft;
+
+ bool hasFill() const { return !qFuzzyIsNull(fillColor.w()) || fillGradientActive; }
+ bool hasStroke() const { return strokeWidth >= 0.0f && !qFuzzyIsNull(strokeColor.w()); }
+ };
+
+ void updatePath(VisualPathRenderData *d);
+ void renderStroke(VisualPathRenderData *d, int strokeStencilValue, int writeMask);
+ void renderFill(VisualPathRenderData *d);
+ void renderOffscreenFill(VisualPathRenderData *d);
+ void setupStencilForCover(bool stencilClip, int sv);
+
+ static bool nvprInited;
+ static QQuickNvprFunctions nvpr;
+ static QQuickNvprMaterialManager mtlmgr;
+
+ QQuickNvprBlitter m_fallbackBlitter;
+ QOpenGLExtraFunctions *f = nullptr;
+
+ QVector<VisualPathRenderData> m_vp;
+
+ friend class QQuickPathItemNvprRenderer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_OPENGL
+
+#endif // QQUICKPATHITEMNVPRRENDERER_P_H
diff --git a/src/imports/pathitem/qquickpathitemsoftwarerenderer.cpp b/src/imports/pathitem/qquickpathitemsoftwarerenderer.cpp
new file mode 100644
index 0000000000..b7aa93bf65
--- /dev/null
+++ b/src/imports/pathitem/qquickpathitemsoftwarerenderer.cpp
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** 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(int totalCount)
+{
+ if (m_vp.count() != totalCount) {
+ m_vp.resize(totalCount);
+ m_accDirty |= DirtyList;
+ }
+}
+
+void QQuickPathItemSoftwareRenderer::setPath(int index, const QQuickPath *path)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.path = path ? path->path() : QPainterPath();
+ d.dirty |= DirtyPath;
+ m_accDirty |= DirtyPath;
+}
+
+void QQuickPathItemSoftwareRenderer::setJSPath(int index, const QQuickPathItemPath &path)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.path = path.toPainterPath();
+ d.dirty |= DirtyPath;
+ m_accDirty |= DirtyPath;
+}
+
+void QQuickPathItemSoftwareRenderer::setStrokeColor(int index, const QColor &color)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.pen.setColor(color);
+ d.dirty |= DirtyPen;
+ m_accDirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setStrokeWidth(int index, qreal w)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.strokeWidth = w;
+ if (w >= 0.0f)
+ d.pen.setWidthF(w);
+ d.dirty |= DirtyPen;
+ m_accDirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setFillColor(int index, const QColor &color)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.fillColor = color;
+ d.brush.setColor(color);
+ d.dirty |= DirtyBrush;
+ m_accDirty |= DirtyBrush;
+}
+
+void QQuickPathItemSoftwareRenderer::setFillRule(int index, QQuickVisualPath::FillRule fillRule)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.fillRule = Qt::FillRule(fillRule);
+ d.dirty |= DirtyFillRule;
+ m_accDirty |= DirtyFillRule;
+}
+
+void QQuickPathItemSoftwareRenderer::setJoinStyle(int index, QQuickVisualPath::JoinStyle joinStyle, int miterLimit)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle));
+ d.pen.setMiterLimit(miterLimit);
+ d.dirty |= DirtyPen;
+ m_accDirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setCapStyle(int index, QQuickVisualPath::CapStyle capStyle)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ d.pen.setCapStyle(Qt::PenCapStyle(capStyle));
+ d.dirty |= DirtyPen;
+ m_accDirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setStrokeStyle(int index, QQuickVisualPath::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ switch (strokeStyle) {
+ case QQuickVisualPath::SolidLine:
+ d.pen.setStyle(Qt::SolidLine);
+ break;
+ case QQuickVisualPath::DashLine:
+ d.pen.setStyle(Qt::CustomDashLine);
+ d.pen.setDashPattern(dashPattern);
+ d.pen.setDashOffset(dashOffset);
+ break;
+ default:
+ break;
+ }
+ d.dirty |= DirtyPen;
+ m_accDirty |= DirtyPen;
+}
+
+void QQuickPathItemSoftwareRenderer::setFillGradient(int index, QQuickPathGradient *gradient)
+{
+ VisualPathGuiData &d(m_vp[index]);
+ 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;
+ }
+ d.brush = QBrush(painterGradient);
+ } else {
+ d.brush = QBrush(d.fillColor);
+ }
+ d.dirty |= DirtyBrush;
+ m_accDirty |= DirtyBrush;
+}
+
+void QQuickPathItemSoftwareRenderer::endSync(bool)
+{
+}
+
+void QQuickPathItemSoftwareRenderer::setNode(QQuickPathItemSoftwareRenderNode *node)
+{
+ if (m_node != node) {
+ m_node = node;
+ m_accDirty |= DirtyList;
+ }
+}
+
+void QQuickPathItemSoftwareRenderer::updateNode()
+{
+ if (!m_accDirty)
+ return;
+
+ const int count = m_vp.count();
+ const bool listChanged = m_accDirty & DirtyList;
+ if (listChanged)
+ m_node->m_vp.resize(count);
+
+ m_node->m_boundingRect = QRectF();
+
+ for (int i = 0; i < count; ++i) {
+ VisualPathGuiData &src(m_vp[i]);
+ QQuickPathItemSoftwareRenderNode::VisualPathRenderData &dst(m_node->m_vp[i]);
+
+ if (listChanged || (src.dirty & DirtyPath)) {
+ dst.path = src.path;
+ dst.path.setFillRule(src.fillRule);
+ }
+
+ if (listChanged || (src.dirty & DirtyFillRule))
+ dst.path.setFillRule(src.fillRule);
+
+ if (listChanged || (src.dirty & DirtyPen)) {
+ dst.pen = src.pen;
+ dst.strokeWidth = src.strokeWidth;
+ }
+
+ if (listChanged || (src.dirty & DirtyBrush))
+ dst.brush = src.brush;
+
+ src.dirty = 0;
+
+ QRectF br = dst.path.boundingRect();
+ const float sw = qMax(1.0f, dst.strokeWidth);
+ br.adjust(-sw, -sw, sw, sw);
+ m_node->m_boundingRect |= br;
+ }
+
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ m_accDirty = 0;
+}
+
+QQuickPathItemSoftwareRenderNode::QQuickPathItemSoftwareRenderNode(QQuickPathItem *item)
+ : m_item(item)
+{
+}
+
+QQuickPathItemSoftwareRenderNode::~QQuickPathItemSoftwareRenderNode()
+{
+ releaseResources();
+}
+
+void QQuickPathItemSoftwareRenderNode::releaseResources()
+{
+}
+
+void QQuickPathItemSoftwareRenderNode::render(const RenderState *state)
+{
+ if (m_vp.isEmpty())
+ return;
+
+ QSGRendererInterface *rif = m_item->window()->rendererInterface();
+ QPainter *p = static_cast<QPainter *>(rif->getResource(m_item->window(), QSGRendererInterface::PainterResource));
+ Q_ASSERT(p);
+
+ const QRegion *clipRegion = state->clipRegion();
+ if (clipRegion && !clipRegion->isEmpty())
+ p->setClipRegion(*clipRegion, Qt::ReplaceClip); // must be done before setTransform
+
+ p->setTransform(matrix()->toTransform());
+ p->setOpacity(inheritedOpacity());
+
+ for (const VisualPathRenderData &d : qAsConst(m_vp)) {
+ p->setPen(d.strokeWidth >= 0.0f && d.pen.color() != Qt::transparent ? d.pen : Qt::NoPen);
+ p->setBrush(d.brush.color() != Qt::transparent ? d.brush : Qt::NoBrush);
+ p->drawPath(d.path);
+ }
+}
+
+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 m_boundingRect;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/pathitem/qquickpathitemsoftwarerenderer_p.h b/src/imports/pathitem/qquickpathitemsoftwarerenderer_p.h
new file mode 100644
index 0000000000..e76590bdfe
--- /dev/null
+++ b/src/imports/pathitem/qquickpathitemsoftwarerenderer_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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,
+ DirtyList = 0x10
+ };
+
+ void beginSync(int totalCount) override;
+ void setPath(int index, const QQuickPath *path) override;
+ void setJSPath(int index, const QQuickPathItemPath &path) override;
+ void setStrokeColor(int index, const QColor &color) override;
+ void setStrokeWidth(int index, qreal w) override;
+ void setFillColor(int index, const QColor &color) override;
+ void setFillRule(int index, QQuickVisualPath::FillRule fillRule) override;
+ void setJoinStyle(int index, QQuickVisualPath::JoinStyle joinStyle, int miterLimit) override;
+ void setCapStyle(int index, QQuickVisualPath::CapStyle capStyle) override;
+ void setStrokeStyle(int index, QQuickVisualPath::StrokeStyle strokeStyle,
+ qreal dashOffset, const QVector<qreal> &dashPattern) override;
+ void setFillGradient(int index, QQuickPathGradient *gradient) override;
+ void endSync(bool async) override;
+
+ void updateNode() override;
+
+ void setNode(QQuickPathItemSoftwareRenderNode *node);
+
+private:
+ QQuickPathItemSoftwareRenderNode *m_node = nullptr;
+ int m_accDirty = 0;
+ struct VisualPathGuiData {
+ int dirty = 0;
+ QPainterPath path;
+ QPen pen;
+ float strokeWidth;
+ QColor fillColor;
+ QBrush brush;
+ Qt::FillRule fillRule;
+ };
+ QVector<VisualPathGuiData> m_vp;
+};
+
+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;
+
+ struct VisualPathRenderData {
+ QPainterPath path;
+ QPen pen;
+ float strokeWidth;
+ QBrush brush;
+ };
+ QVector<VisualPathRenderData> m_vp;
+ QRectF m_boundingRect;
+
+ friend class QQuickPathItemSoftwareRenderer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPATHITEMSOFTWARERENDERER_P_H