diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/quick/items/qquickpathitem.cpp | 814 | ||||
-rw-r--r-- | src/quick/items/qquickpathitem_p.h | 7 | ||||
-rw-r--r-- | src/quick/items/qquickpathitem_p_p.h | 103 | ||||
-rw-r--r-- | src/quick/items/qquickpathitemgenericrenderer.cpp | 7 | ||||
-rw-r--r-- | src/quick/items/qquickpathitemgenericrenderer_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickpathitemnvprrenderer.cpp | 84 | ||||
-rw-r--r-- | src/quick/items/qquickpathitemnvprrenderer_p.h | 2 | ||||
-rw-r--r-- | src/quick/items/qquickpathitemsoftwarerenderer.cpp | 8 | ||||
-rw-r--r-- | src/quick/items/qquickpathitemsoftwarerenderer_p.h | 1 |
9 files changed, 938 insertions, 89 deletions
diff --git a/src/quick/items/qquickpathitem.cpp b/src/quick/items/qquickpathitem.cpp index c5ad73e960..61216be9b0 100644 --- a/src/quick/items/qquickpathitem.cpp +++ b/src/quick/items/qquickpathitem.cpp @@ -43,15 +43,20 @@ #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 -QQuickVisualPathPrivate::QQuickVisualPathPrivate() - : path(nullptr), - dirty(DirtyAll), - strokeColor(Qt::white), +QQuickPathItemStrokeFillParams::QQuickPathItemStrokeFillParams() + : strokeColor(Qt::white), strokeWidth(1), fillColor(Qt::white), fillRule(QQuickVisualPath::OddEvenFill), @@ -65,6 +70,56 @@ QQuickVisualPathPrivate::QQuickVisualPathPrivate() 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; +} + +QQuickVisualPathPrivate::QQuickVisualPathPrivate() + : path(nullptr), + dirty(DirtyAll) +{ +} + QQuickVisualPath::QQuickVisualPath(QObject *parent) : QObject(*(new QQuickVisualPathPrivate), parent) { @@ -108,14 +163,14 @@ void QQuickVisualPathPrivate::_q_pathChanged() QColor QQuickVisualPath::strokeColor() const { Q_D(const QQuickVisualPath); - return d->strokeColor; + return d->sfp.strokeColor; } void QQuickVisualPath::setStrokeColor(const QColor &color) { Q_D(QQuickVisualPath); - if (d->strokeColor != color) { - d->strokeColor = color; + if (d->sfp.strokeColor != color) { + d->sfp.strokeColor = color; d->dirty |= QQuickVisualPathPrivate::DirtyStrokeColor; emit strokeColorChanged(); emit changed(); @@ -125,14 +180,14 @@ void QQuickVisualPath::setStrokeColor(const QColor &color) qreal QQuickVisualPath::strokeWidth() const { Q_D(const QQuickVisualPath); - return d->strokeWidth; + return d->sfp.strokeWidth; } void QQuickVisualPath::setStrokeWidth(qreal w) { Q_D(QQuickVisualPath); - if (d->strokeWidth != w) { - d->strokeWidth = w; + if (d->sfp.strokeWidth != w) { + d->sfp.strokeWidth = w; d->dirty |= QQuickVisualPathPrivate::DirtyStrokeWidth; emit strokeWidthChanged(); emit changed(); @@ -142,14 +197,14 @@ void QQuickVisualPath::setStrokeWidth(qreal w) QColor QQuickVisualPath::fillColor() const { Q_D(const QQuickVisualPath); - return d->fillColor; + return d->sfp.fillColor; } void QQuickVisualPath::setFillColor(const QColor &color) { Q_D(QQuickVisualPath); - if (d->fillColor != color) { - d->fillColor = color; + if (d->sfp.fillColor != color) { + d->sfp.fillColor = color; d->dirty |= QQuickVisualPathPrivate::DirtyFillColor; emit fillColorChanged(); emit changed(); @@ -159,14 +214,14 @@ void QQuickVisualPath::setFillColor(const QColor &color) QQuickVisualPath::FillRule QQuickVisualPath::fillRule() const { Q_D(const QQuickVisualPath); - return d->fillRule; + return d->sfp.fillRule; } void QQuickVisualPath::setFillRule(FillRule fillRule) { Q_D(QQuickVisualPath); - if (d->fillRule != fillRule) { - d->fillRule = fillRule; + if (d->sfp.fillRule != fillRule) { + d->sfp.fillRule = fillRule; d->dirty |= QQuickVisualPathPrivate::DirtyFillRule; emit fillRuleChanged(); emit changed(); @@ -176,14 +231,14 @@ void QQuickVisualPath::setFillRule(FillRule fillRule) QQuickVisualPath::JoinStyle QQuickVisualPath::joinStyle() const { Q_D(const QQuickVisualPath); - return d->joinStyle; + return d->sfp.joinStyle; } void QQuickVisualPath::setJoinStyle(JoinStyle style) { Q_D(QQuickVisualPath); - if (d->joinStyle != style) { - d->joinStyle = style; + if (d->sfp.joinStyle != style) { + d->sfp.joinStyle = style; d->dirty |= QQuickVisualPathPrivate::DirtyStyle; emit joinStyleChanged(); emit changed(); @@ -193,14 +248,14 @@ void QQuickVisualPath::setJoinStyle(JoinStyle style) int QQuickVisualPath::miterLimit() const { Q_D(const QQuickVisualPath); - return d->miterLimit; + return d->sfp.miterLimit; } void QQuickVisualPath::setMiterLimit(int limit) { Q_D(QQuickVisualPath); - if (d->miterLimit != limit) { - d->miterLimit = limit; + if (d->sfp.miterLimit != limit) { + d->sfp.miterLimit = limit; d->dirty |= QQuickVisualPathPrivate::DirtyStyle; emit miterLimitChanged(); emit changed(); @@ -210,14 +265,14 @@ void QQuickVisualPath::setMiterLimit(int limit) QQuickVisualPath::CapStyle QQuickVisualPath::capStyle() const { Q_D(const QQuickVisualPath); - return d->capStyle; + return d->sfp.capStyle; } void QQuickVisualPath::setCapStyle(CapStyle style) { Q_D(QQuickVisualPath); - if (d->capStyle != style) { - d->capStyle = style; + if (d->sfp.capStyle != style) { + d->sfp.capStyle = style; d->dirty |= QQuickVisualPathPrivate::DirtyStyle; emit capStyleChanged(); emit changed(); @@ -227,14 +282,14 @@ void QQuickVisualPath::setCapStyle(CapStyle style) QQuickVisualPath::StrokeStyle QQuickVisualPath::strokeStyle() const { Q_D(const QQuickVisualPath); - return d->strokeStyle; + return d->sfp.strokeStyle; } void QQuickVisualPath::setStrokeStyle(StrokeStyle style) { Q_D(QQuickVisualPath); - if (d->strokeStyle != style) { - d->strokeStyle = style; + if (d->sfp.strokeStyle != style) { + d->sfp.strokeStyle = style; d->dirty |= QQuickVisualPathPrivate::DirtyDash; emit strokeStyleChanged(); emit changed(); @@ -244,14 +299,14 @@ void QQuickVisualPath::setStrokeStyle(StrokeStyle style) qreal QQuickVisualPath::dashOffset() const { Q_D(const QQuickVisualPath); - return d->dashOffset; + return d->sfp.dashOffset; } void QQuickVisualPath::setDashOffset(qreal offset) { Q_D(QQuickVisualPath); - if (d->dashOffset != offset) { - d->dashOffset = offset; + if (d->sfp.dashOffset != offset) { + d->sfp.dashOffset = offset; d->dirty |= QQuickVisualPathPrivate::DirtyDash; emit dashOffsetChanged(); emit changed(); @@ -261,14 +316,14 @@ void QQuickVisualPath::setDashOffset(qreal offset) QVector<qreal> QQuickVisualPath::dashPattern() const { Q_D(const QQuickVisualPath); - return d->dashPattern; + return d->sfp.dashPattern; } void QQuickVisualPath::setDashPattern(const QVector<qreal> &array) { Q_D(QQuickVisualPath); - if (d->dashPattern != array) { - d->dashPattern = array; + if (d->sfp.dashPattern != array) { + d->sfp.dashPattern = array; d->dirty |= QQuickVisualPathPrivate::DirtyDash; emit dashPatternChanged(); emit changed(); @@ -278,19 +333,19 @@ void QQuickVisualPath::setDashPattern(const QVector<qreal> &array) QQuickPathGradient *QQuickVisualPath::fillGradient() const { Q_D(const QQuickVisualPath); - return d->fillGradient; + return d->sfp.fillGradient; } void QQuickVisualPath::setFillGradient(QQuickPathGradient *gradient) { Q_D(QQuickVisualPath); - if (d->fillGradient != gradient) { - if (d->fillGradient) - qmlobject_disconnect(d->fillGradient, QQuickPathGradient, SIGNAL(updated()), + if (d->sfp.fillGradient != gradient) { + if (d->sfp.fillGradient) + qmlobject_disconnect(d->sfp.fillGradient, QQuickPathGradient, SIGNAL(updated()), this, QQuickVisualPath, SLOT(_q_fillGradientChanged())); - d->fillGradient = gradient; - if (d->fillGradient) - qmlobject_connect(d->fillGradient, QQuickPathGradient, SIGNAL(updated()), + 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(); @@ -430,14 +485,14 @@ QQuickPathItem::Status QQuickPathItem::status() const static QQuickVisualPath *vpe_at(QQmlListProperty<QQuickVisualPath> *property, int index) { QQuickPathItemPrivate *d = QQuickPathItemPrivate::get(static_cast<QQuickPathItem *>(property->object)); - return d->vp.at(index); + 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->vp.append(obj); + d->qmlData.vp.append(obj); if (d->componentComplete) { QObject::connect(obj, SIGNAL(changed()), item, SLOT(_q_visualPathChanged())); @@ -448,7 +503,7 @@ static void vpe_append(QQmlListProperty<QQuickVisualPath> *property, QQuickVisua static int vpe_count(QQmlListProperty<QQuickVisualPath> *property) { QQuickPathItemPrivate *d = QQuickPathItemPrivate::get(static_cast<QQuickPathItem *>(property->object)); - return d->vp.count(); + return d->qmlData.vp.count(); } static void vpe_clear(QQmlListProperty<QQuickVisualPath> *property) @@ -456,10 +511,10 @@ static void vpe_clear(QQmlListProperty<QQuickVisualPath> *property) QQuickPathItem *item = static_cast<QQuickPathItem *>(property->object); QQuickPathItemPrivate *d = QQuickPathItemPrivate::get(item); - for (QQuickVisualPath *p : d->vp) + for (QQuickVisualPath *p : d->qmlData.vp) QObject::disconnect(p, SIGNAL(changed()), item, SLOT(_q_visualPathChanged())); - d->vp.clear(); + d->qmlData.vp.clear(); if (d->componentComplete) d->_q_visualPathChanged(); @@ -486,7 +541,7 @@ void QQuickPathItem::componentComplete() Q_D(QQuickPathItem); d->componentComplete = true; - for (QQuickVisualPath *p : d->vp) + for (QQuickVisualPath *p : d->qmlData.vp) connect(p, SIGNAL(changed()), this, SLOT(_q_visualPathChanged())); d->_q_visualPathChanged(); @@ -624,36 +679,60 @@ void QQuickPathItemPrivate::sync() renderer->setAsyncCallback(q_asyncPathItemReady, this); } - const int count = vp.count(); - renderer->beginSync(count); - - for (int i = 0; i < count; ++i) { - QQuickVisualPath *p = 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 (!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; } - 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); + renderer->endSync(useAsync); + } if (!useAsync) setStatus(QQuickPathItem::Ready); @@ -935,6 +1014,593 @@ QSGTexture *QQuickPathItemGradientCache::get(const GradientDesc &grad) #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(); +} + +extern 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; +} + +void QQuickPathItemPathObject::clear() +{ + path = QQuickPathItemPath(); +} + +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; +} + +void QQuickPathItem::newPath(QQmlV4Function *args) +{ + QQuickPathItemPathObject *obj = new QQuickPathItemPathObject(this); + obj->setV4Engine(QQmlEnginePrivate::get(qmlEngine(this))->v4engine()); + args->setReturnValue(obj->v4value()); +} + +void QQuickPathItem::newStrokeFillParams(QQmlV4Function *args) +{ + QQuickPathItemStrokeFillParamsObject *obj = new QQuickPathItemStrokeFillParamsObject(this); + obj->setV4Engine(QQmlEnginePrivate::get(qmlEngine(this))->v4engine()); + args->setReturnValue(obj->v4value()); +} + +void QQuickPathItem::clearVisualPaths(QQmlV4Function *args) +{ + Q_UNUSED(args); + Q_D(QQuickPathItem); + d->jsData.paths.clear(); + d->jsData.sfp.clear(); +} + +void QQuickPathItem::commitVisualPaths(QQmlV4Function *args) +{ + Q_UNUSED(args); + Q_D(QQuickPathItem); + d->_q_visualPathChanged(); +} + +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/quick/items/qquickpathitem_p.h b/src/quick/items/qquickpathitem_p.h index 9ca1418d9e..991ab7a2bf 100644 --- a/src/quick/items/qquickpathitem_p.h +++ b/src/quick/items/qquickpathitem_p.h @@ -55,6 +55,7 @@ #include <private/qtquickglobal_p.h> #include <private/qquickpath_p.h> +#include <private/qv8engine_p.h> #include <QGradientStops> QT_REQUIRE_CONFIG(quick_path); @@ -296,6 +297,12 @@ public: 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; diff --git a/src/quick/items/qquickpathitem_p_p.h b/src/quick/items/qquickpathitem_p_p.h index 3c63ec6dc2..091a453c0b 100644 --- a/src/quick/items/qquickpathitem_p_p.h +++ b/src/quick/items/qquickpathitem_p_p.h @@ -62,6 +62,39 @@ 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: @@ -74,7 +107,14 @@ public: // 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; @@ -84,9 +124,6 @@ public: virtual void setStrokeStyle(int index, QQuickVisualPath::StrokeStyle strokeStyle, qreal dashOffset, const QVector<qreal> &dashPattern) = 0; virtual void setFillGradient(int index, QQuickPathGradient *gradient) = 0; - virtual void endSync(bool async) = 0; - virtual void setAsyncCallback(void (*)(void *), void *) { } - virtual Flags flags() const { return 0; } // Render thread, with gui blocked virtual void updateNode() = 0; @@ -121,17 +158,7 @@ public: QQuickPath *path; int dirty; - 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; + QQuickPathItemStrokeFillParams sfp; }; class QQuickPathItemPrivate : public QQuickItemPrivate @@ -157,7 +184,53 @@ public: bool async; QQuickPathItem::Status status; QQuickAbstractPathRenderer *renderer; - QVector<QQuickVisualPath *> vp; + + 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; +}; + +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 diff --git a/src/quick/items/qquickpathitemgenericrenderer.cpp b/src/quick/items/qquickpathitemgenericrenderer.cpp index 3de01a5bc7..a76a5e2b43 100644 --- a/src/quick/items/qquickpathitemgenericrenderer.cpp +++ b/src/quick/items/qquickpathitemgenericrenderer.cpp @@ -178,6 +178,13 @@ void QQuickPathItemGenericRenderer::setPath(int index, const QQuickPath *path) 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]); diff --git a/src/quick/items/qquickpathitemgenericrenderer_p.h b/src/quick/items/qquickpathitemgenericrenderer_p.h index 045c52d610..70a9e88d2f 100644 --- a/src/quick/items/qquickpathitemgenericrenderer_p.h +++ b/src/quick/items/qquickpathitemgenericrenderer_p.h @@ -87,6 +87,7 @@ public: 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; diff --git a/src/quick/items/qquickpathitemnvprrenderer.cpp b/src/quick/items/qquickpathitemnvprrenderer.cpp index 13fab2dc76..f8504f9985 100644 --- a/src/quick/items/qquickpathitemnvprrenderer.cpp +++ b/src/quick/items/qquickpathitemnvprrenderer.cpp @@ -62,6 +62,14 @@ void QQuickPathItemNvprRenderer::setPath(int index, const QQuickPath *path) 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]); @@ -288,6 +296,82 @@ void QQuickPathItemNvprRenderer::convertPath(const QQuickPath *path, VisualPathG 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; diff --git a/src/quick/items/qquickpathitemnvprrenderer_p.h b/src/quick/items/qquickpathitemnvprrenderer_p.h index 61f8b5ebb9..deab9cf7f9 100644 --- a/src/quick/items/qquickpathitemnvprrenderer_p.h +++ b/src/quick/items/qquickpathitemnvprrenderer_p.h @@ -81,6 +81,7 @@ public: 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; @@ -121,6 +122,7 @@ private: }; void convertPath(const QQuickPath *path, VisualPathGuiData *d); + void convertJSPath(const QQuickPathItemPath &path, VisualPathGuiData *d); QQuickPathItemNvprRenderNode *m_node = nullptr; int m_accDirty = 0; diff --git a/src/quick/items/qquickpathitemsoftwarerenderer.cpp b/src/quick/items/qquickpathitemsoftwarerenderer.cpp index 46ebcbfe6d..b7aa93bf65 100644 --- a/src/quick/items/qquickpathitemsoftwarerenderer.cpp +++ b/src/quick/items/qquickpathitemsoftwarerenderer.cpp @@ -58,6 +58,14 @@ void QQuickPathItemSoftwareRenderer::setPath(int index, const QQuickPath *path) 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]); diff --git a/src/quick/items/qquickpathitemsoftwarerenderer_p.h b/src/quick/items/qquickpathitemsoftwarerenderer_p.h index 64280b436e..e76590bdfe 100644 --- a/src/quick/items/qquickpathitemsoftwarerenderer_p.h +++ b/src/quick/items/qquickpathitemsoftwarerenderer_p.h @@ -73,6 +73,7 @@ public: 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; |