diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-07-08 15:56:48 +1000 |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-07-08 15:56:48 +1000 |
commit | 26590325b5e9209df4495841b9013d04bbb35515 (patch) | |
tree | 2a4e44ca1e1d4389caf999ee8801a312166bf39c /src/declarative/items | |
parent | 5a705d8951a0b23c725d99a5a3fce7902ec41374 (diff) | |
parent | 438d50d63c48bbbfd185bd7e1a0d6e6174c1791e (diff) |
Merge branch 'v8'
Conflicts:
src/declarative/qml/qdeclarativescarceresourcescriptclass.cpp
src/declarative/qml/qdeclarativescarceresourcescriptclass_p.h
Change-Id: I54e579307cbeafbbad21884218c5e797ba245c8b
Diffstat (limited to 'src/declarative/items')
-rw-r--r-- | src/declarative/items/qsgcanvasitem.cpp | 27 | ||||
-rw-r--r-- | src/declarative/items/qsgcanvasitem_p.h | 9 | ||||
-rw-r--r-- | src/declarative/items/qsgcontext2d.cpp | 2180 | ||||
-rw-r--r-- | src/declarative/items/qsgcontext2d_p.h | 15 | ||||
-rw-r--r-- | src/declarative/items/qsgcontext2d_p_p.h | 13 | ||||
-rw-r--r-- | src/declarative/items/qsgitem.cpp | 74 | ||||
-rw-r--r-- | src/declarative/items/qsgitem.h | 4 |
7 files changed, 1489 insertions, 833 deletions
diff --git a/src/declarative/items/qsgcanvasitem.cpp b/src/declarative/items/qsgcanvasitem.cpp index 9f6e9db56b..f346db4c66 100644 --- a/src/declarative/items/qsgcanvasitem.cpp +++ b/src/declarative/items/qsgcanvasitem.cpp @@ -94,25 +94,40 @@ void QSGCanvasItem::paint(QPainter *painter) Q_D(QSGCanvasItem); if (d->context) { + emit drawRegion(getContext(), QRect(0, 0, width(), height())); d->context->paint(painter); emit canvasUpdated(); } } -QScriptValue QSGCanvasItem::getContext(const QString &contextId) +void QSGCanvasItem::componentComplete() +{ + const QMetaObject *metaObject = this->metaObject(); + int propertyCount = metaObject->propertyCount(); + int requestPaintMethod = metaObject->indexOfMethod("requestPaint()"); + for (int ii = QSGCanvasItem::staticMetaObject.propertyCount(); ii < propertyCount; ++ii) { + QMetaProperty p = metaObject->property(ii); + if (p.hasNotifySignal()) + QMetaObject::connect(this, p.notifySignalIndex(), this, requestPaintMethod, 0, 0); + } + QSGPaintedItem::componentComplete(); +} + + +QDeclarativeV8Handle QSGCanvasItem::getContext(const QString &contextId) { Q_D(QSGCanvasItem); - QScriptEngine* e = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this)); + if (contextId == QLatin1String("2d")) { if (!d->context) { + QV8Engine *e = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this)); d->context = new QSGContext2D(this); - d->context->setScriptEngine(e); + d->context->setV8Engine(e); connect(d->context, SIGNAL(changed()), this, SLOT(requestPaint())); } - return d->context->scriptValue(); + return QDeclarativeV8Handle::fromHandle(d->context->v8value()); } - qDebug("Canvas:requesting unsupported context"); - return e->undefinedValue(); + return QDeclarativeV8Handle::fromHandle(v8::Undefined()); } void QSGCanvasItem::requestPaint() diff --git a/src/declarative/items/qsgcanvasitem_p.h b/src/declarative/items/qsgcanvasitem_p.h index 8f3130c340..71358c4d9e 100644 --- a/src/declarative/items/qsgcanvasitem_p.h +++ b/src/declarative/items/qsgcanvasitem_p.h @@ -43,6 +43,7 @@ #define QSGCANVASITEM_P_H #include "qsgpainteditem.h" +#include <private/qv8engine_p.h> #define QSGCANVASITEM_DEBUG //enable this for just DEBUG purpose! @@ -55,7 +56,6 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QScriptValue; class QSGContext2D; class QSGCanvasItemPrivate; class QSGCanvasItem : public QSGPaintedItem @@ -65,11 +65,13 @@ public: QSGCanvasItem(QSGItem *parent = 0); ~QSGCanvasItem(); -signals: +Q_SIGNALS: void canvasUpdated(); + void drawRegion(QDeclarativeV8Handle context, const QRect ®ion); + public Q_SLOTS: QString toDataURL(const QString& type = QLatin1String("image/png")) const; - QScriptValue getContext(const QString & = QLatin1String("2d")); + QDeclarativeV8Handle getContext(const QString & = QLatin1String("2d")); void requestPaint(); // Save current canvas to disk @@ -77,6 +79,7 @@ public Q_SLOTS: protected: void paint(QPainter *painter); + virtual void componentComplete(); private: Q_DECLARE_PRIVATE(QSGCanvasItem) friend class QSGContext2D; diff --git a/src/declarative/items/qsgcontext2d.cpp b/src/declarative/items/qsgcontext2d.cpp index db23e5bc7b..f3371ed982 100644 --- a/src/declarative/items/qsgcontext2d.cpp +++ b/src/declarative/items/qsgcontext2d.cpp @@ -53,7 +53,9 @@ #include <qdeclarativeinfo.h> #include <QtCore/qmath.h> #include "qdeclarativepixmapcache_p.h" -#include <QtScript/QScriptEngine> + +#include <private/qv8engine_p.h> +#include "qvarlengtharray.h" QT_BEGIN_NAMESPACE @@ -366,547 +368,882 @@ static QString compositeOperatorToString(QPainter::CompositionMode op) return QString(); } +class QV8Context2DResource : public QV8ObjectResource +{ + V8_RESOURCE_TYPE(Context2DType) +public: + QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {} + QDeclarativeGuard<QSGContext2D> context; +}; - #include <QScriptEngine> - -//static QtScript functions -static QScriptValue ctx2d_sync(QScriptContext *c, QScriptEngine* e) +//static script functions +static v8::Handle<v8::Value> ctx2d_sync(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - ctx2d->sync(); - return e->nullValue(); -} + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + r->context->sync(); + return v8::Undefined(); +} // back-reference to the canvas, getter -static QScriptValue ctx2d_canvas(QScriptContext *c, QScriptEngine* e) +static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - return e->newQObject(ctx2d->canvas()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return engine->newQObject(r->context->canvas()); } // state -static QScriptValue ctx2d_restore(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - ctx2d->restore(); - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + r->context->restore(); + + return v8::Undefined(); } -static QScriptValue ctx2d_save(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - ctx2d->save(); - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + r->context->reset(); + + return v8::Undefined(); +} + +static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + r->context->save(); + + return v8::Undefined(); } // transformations -static QScriptValue ctx2d_rotate(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) { - ctx2d->rotate(c->argument(0).toNumber()); - } - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 1) + r->context->rotate(args[0]->NumberValue()); + + return v8::Undefined(); } -static QScriptValue ctx2d_scale(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 2) { - ctx2d->scale(c->argument(0).toNumber(), c->argument(1).toNumber()); - } - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 2) + r->context->scale(args[0]->NumberValue(), args[1]->NumberValue()); + + return v8::Undefined(); } -static QScriptValue ctx2d_setTransform(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 6) { - ctx2d->setTransform(c->argument(0).toNumber() - , c->argument(1).toNumber() - , c->argument(2).toNumber() - , c->argument(3).toNumber() - , c->argument(4).toNumber() - , c->argument(5).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 6) { + r->context->setTransform(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue(), + args[4]->NumberValue(), + args[5]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_transform(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 6) { - ctx2d->transform(c->argument(0).toNumber() - , c->argument(1).toNumber() - , c->argument(2).toNumber() - , c->argument(3).toNumber() - , c->argument(4).toNumber() - , c->argument(5).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 6) { + r->context->transform(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue(), + args[4]->NumberValue(), + args[5]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_translate(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 2) { - ctx2d->translate(c->argument(0).toNumber() - , c->argument(1).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 2) { + r->context->translate(args[0]->NumberValue(), + args[1]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } // compositing // float getter/setter default 1.0 -static QScriptValue ctx2d_globalAlpha(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setGlobalAlpha(c->argument(0).toNumber()); - } - return e->toScriptValue(ctx2d->globalAlpha()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + return v8::Number::New(r->context->globalAlpha()); +} + +static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + r->context->setGlobalAlpha(value->NumberValue()); } // string getter/setter default "source-over" -static QScriptValue ctx2d_globalCompositeOperation(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (ctx2d) { - if (c->argumentCount() == 1) {//setter - ctx2d->setGlobalCompositeOperation(c->argument(0).toString()); - } - return e->toScriptValue(ctx2d->globalCompositeOperation()); - } - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return engine->toString(r->context->globalCompositeOperation()); +} + +static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + r->context->setGlobalCompositeOperation(engine->toString(value)); } // colors and styles // getter/setter -static QScriptValue ctx2d_fillStyle(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setFillStyle(c->argument(0).toVariant()); - } - return e->toScriptValue(ctx2d->fillStyle()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return engine->fromVariant(r->context->fillStyle()); +} + +static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + r->context->setFillStyle(engine->toVariant(value, -1)); } // colors and styles // getter/setter -static QScriptValue ctx2d_fillColor(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_fillColor(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setFillColor(c->argument(0).toVariant().value<QColor>()); - } - return e->toScriptValue(ctx2d->fillColor()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return engine->fromVariant(r->context->fillColor()); } +static void ctx2d_fillColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + r->context->setFillColor(engine->toVariant(value, -1).value<QColor>()); +} //getter/setter -static QScriptValue ctx2d_strokeStyle(QScriptContext *c, QScriptEngine *e) +v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setStrokeStyle(c->argument(0).toVariant()); - } - return e->toScriptValue(ctx2d->strokeStyle()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return engine->fromVariant(r->context->strokeStyle()); +} + +static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + r->context->setStrokeStyle(engine->toVariant(value, -1)); } // colors and styles // getter/setter -static QScriptValue ctx2d_strokeColor(QScriptContext *c, QScriptEngine *e) +v8::Handle<v8::Value> ctx2d_strokeColor(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setStrokeColor(c->argument(0).toVariant().value<QColor>()); - } - return e->toScriptValue(ctx2d->strokeColor()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return engine->fromVariant(r->context->strokeColor()); +} + +static void ctx2d_strokeColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + r->context->setStrokeColor(engine->toVariant(value, -1).value<QColor>()); } -static QScriptValue ctx2d_createLinearGradient(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 4) { - QObject* gradient = ctx2d->createLinearGradient( c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber()); - return e->toScriptValue(gradient); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE(); + + if (args.Length() == 4) { + QObject* gradient = r->context->createLinearGradient(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue()); + return engine->newQObject(gradient); } - return e->nullValue(); + + return v8::Null(); } -static QScriptValue ctx2d_createRadialGradient(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 6) { - QObject* gradient = ctx2d->createRadialGradient( c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber() - ,c->argument(4).toNumber() - ,c->argument(5).toNumber()); - return e->toScriptValue(gradient); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE(); + + if (args.Length() == 6) { + QObject* gradient = r->context->createRadialGradient(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue(), + args[4]->NumberValue(), + args[5]->NumberValue()); + return engine->newQObject(gradient); } - return e->nullValue(); + + return v8::Null(); } -static QScriptValue ctx2d_createPattern(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args) { //TODO - return e->nullValue(); + return v8::Null(); } // line styles // string getter/setter -static QScriptValue ctx2d_lineCap(QScriptContext *c, QScriptEngine *e) +v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setLineCap(c->argument(0).toString()); - } - return e->toScriptValue(ctx2d->lineCap()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return engine->toString(r->context->lineCap()); +} + +static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + r->context->setLineCap(engine->toString(value)); } // string getter/setter -static QScriptValue ctx2d_lineJoin(QScriptContext *c, QScriptEngine *e) +v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setLineJoin(c->argument(0).toString()); - } - return e->toScriptValue(ctx2d->lineJoin()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return engine->toString(r->context->lineJoin()); } + +static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + r->context->setLineJoin(engine->toString(value)); +} + // float getter/setter -static QScriptValue ctx2d_lineWidth(QScriptContext *c, QScriptEngine *e) +v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setLineWidth(c->argument(0).toNumber()); - } - return e->toScriptValue(ctx2d->lineWidth()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + return v8::Number::New(r->context->lineWidth()); } + +static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + r->context->setLineWidth(value->NumberValue()); +} + // float getter/setter -static QScriptValue ctx2d_miterLimit(QScriptContext *c, QScriptEngine *e) +v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setMiterLimit(c->argument(0).toNumber()); - } - return e->toScriptValue(ctx2d->miterLimit()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + return v8::Number::New(r->context->miterLimit()); +} + +static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + r->context->setMiterLimit(value->NumberValue()); } // shadows // float getter/setter -static QScriptValue ctx2d_shadowBlur(QScriptContext *c, QScriptEngine *e) +v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setShadowBlur(c->argument(0).toNumber()); - } - return e->toScriptValue(ctx2d->shadowBlur()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + return v8::Number::New(r->context->shadowBlur()); } -static QScriptValue ctx2d_shadowColor(QScriptContext *c, QScriptEngine *e) + +static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setShadowColor(c->argument(0).toString()); - } - return e->toScriptValue(ctx2d->shadowColor()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + r->context->setShadowBlur(value->NumberValue()); +} + +v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return engine->toString(r->context->shadowColor()); } -static QScriptValue ctx2d_shadowOffsetX(QScriptContext *c, QScriptEngine *e) + +static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setShadowOffsetX(c->argument(0).toNumber()); - } - return e->toScriptValue(ctx2d->shadowOffsetX()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + r->context->setShadowColor(engine->toString(value)); } -static QScriptValue ctx2d_shadowOffsetY(QScriptContext *c, QScriptEngine *e) +v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 1) {//setter - ctx2d->setShadowOffsetY(c->argument(0).toNumber()); - } - return e->toScriptValue(ctx2d->shadowOffsetY()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + return v8::Number::New(r->context->shadowOffsetX()); +} + +static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + r->context->setShadowOffsetX(value->NumberValue()); +} + +v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + return v8::Number::New(r->context->shadowOffsetY()); +} + +static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + r->context->setShadowOffsetY(value->NumberValue()); } //rects -static QScriptValue ctx2d_clearRect(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 4) { - ctx2d->clearRect(c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 4) { + r->context->clearRect(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_fillRect(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 4) { - ctx2d->fillRect(c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 4) { + r->context->fillRect(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_strokeRect(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 4) { - ctx2d->strokeRect(c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 4) { + r->context->strokeRect(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } // Complex shapes (paths) API -static QScriptValue ctx2d_arc(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 6) { - ctx2d->arc(c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber() - ,c->argument(4).toNumber() - ,c->argument(5).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 6) { + r->context->arc(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue(), + args[4]->NumberValue(), + args[5]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_arcTo(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 5) { - ctx2d->arcTo(c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber() - ,c->argument(4).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 5) { + r->context->arcTo(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue(), + args[4]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_beginPath(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - ctx2d->beginPath(); - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + r->context->beginPath(); + + return v8::Undefined(); } -static QScriptValue ctx2d_bezierCurveTo(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 5) { - ctx2d->bezierCurveTo(c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber() - ,c->argument(4).toNumber() - ,c->argument(5).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 5) { + r->context->bezierCurveTo(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue(), + args[4]->NumberValue(), + args[5]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_clip(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - ctx2d->clip(); - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + r->context->clip(); + + return v8::Undefined(); } -static QScriptValue ctx2d_closePath(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - ctx2d->closePath(); - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + r->context->closePath(); + + return v8::Undefined(); } -static QScriptValue ctx2d_fill(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - ctx2d->fill(); - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + r->context->fill(); + + return v8::Undefined(); } -static QScriptValue ctx2d_lineTo(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 2) { - ctx2d->lineTo(c->argument(0).toNumber() - ,c->argument(1).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 2) { + r->context->lineTo(args[0]->NumberValue(), + args[1]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_moveTo(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 2) { - ctx2d->moveTo(c->argument(0).toNumber() - ,c->argument(1).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 2) { + r->context->moveTo(args[0]->NumberValue(), + args[1]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_quadraticCurveTo(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 4) { - ctx2d->quadraticCurveTo(c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 4) { + r->context->quadraticCurveTo(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_rect(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 4) { - ctx2d->rect(c->argument(0).toNumber() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + if (args.Length() == 4) { + r->context->rect(args[0]->NumberValue(), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue()); } - return e->nullValue(); + + return v8::Undefined(); } -static QScriptValue ctx2d_stroke(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - ctx2d->stroke(); - return e->nullValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + r->context->stroke(); + + return v8::Undefined(); } -static QScriptValue ctx2d_isPointInPath(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + bool pointInPath = false; - if (c->argumentCount() == 2) { - pointInPath = ctx2d->isPointInPath(c->argument(0).toNumber() - ,c->argument(1).toNumber()); + if (args.Length() == 2) { + pointInPath = r->context->isPointInPath(args[0]->NumberValue(), + args[1]->NumberValue()); } - return e->toScriptValue(pointInPath); -} -// text -static QScriptValue ctx2d_font(QScriptContext *c, QScriptEngine *e) -{ - return QScriptValue(); -} -static QScriptValue ctx2d_textAlign(QScriptContext *c, QScriptEngine *e) -{ - return QScriptValue(); + return v8::Boolean::New(pointInPath); } -static QScriptValue ctx2d_textBaseline(QScriptContext *c, QScriptEngine *e) -{ - return QScriptValue(); -} -static QScriptValue ctx2d_fillText(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_setPathString(const v8::Arguments &args) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 3) { - ctx2d->fillText(c->argument(0).toString() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber()); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE(); + if (args.Length() == 1) { + r->context->setPathString(engine->toString(args[0])); } - return e->nullValue(); + return v8::Undefined(); } -static QScriptValue ctx2d_strokeText(QScriptContext *c, QScriptEngine *e) + +// text +v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info) { - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 3) { - ctx2d->strokeText(c->argument(0).toString() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber()); - } - return e->nullValue(); -} + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); -// drawing images -static QScriptValue ctx2d_drawImage(QScriptContext *c, QScriptEngine *e) -{ - QSGContext2D* ctx2d = qscriptvalue_cast<QSGContext2D*>(c->thisObject().data()); - if (c->argumentCount() == 3) { - ctx2d->drawImage(c->argument(0).toString() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber()); - } else if (c->argumentCount() == 5) { - ctx2d->drawImage(c->argument(0).toString() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber() - ,c->argument(4).toNumber()); - } else if (c->argumentCount() == 9) { - ctx2d->drawImage(c->argument(0).toString() - ,c->argument(1).toNumber() - ,c->argument(2).toNumber() - ,c->argument(3).toNumber() - ,c->argument(4).toNumber() - ,c->argument(5).toNumber() - ,c->argument(6).toNumber() - ,c->argument(7).toNumber() - ,c->argument(8).toNumber()); - } - return e->nullValue(); + return v8::Undefined(); } -// pixel manipulation -static QScriptValue ctx2d_createImageData(QScriptContext *c, QScriptEngine *e) +static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) { - //#TODO - return QScriptValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + Q_UNUSED(value); } -static QScriptValue ctx2d_getImageData(QScriptContext *c, QScriptEngine *e) + +v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info) { - //#TODO - return QScriptValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + return v8::Undefined(); } -static QScriptValue ctx2d_putImageData(QScriptContext *c, QScriptEngine *e) + +static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) { - //#TODO - return QScriptValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + Q_UNUSED(value); } -//Image Data Interface -static QScriptValue ctx2d_imageData_data(QScriptContext *c, QScriptEngine *e) +v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info) { - //#TODO - return QScriptValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + return v8::Undefined(); } -static QScriptValue ctx2d_imageData_height(QScriptContext *c, QScriptEngine *e) + +static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info) { - //#TODO - return QScriptValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This()); + if (!r || !r->context) + V8THROW_ERROR_SETTER("Not a Context2D object"); + + Q_UNUSED(value); } -static QScriptValue ctx2d_imageData_width(QScriptContext *c, QScriptEngine *e) + +static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args) { - //#TODO - return QScriptValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE(); + + if (args.Length() == 3) { + r->context->fillText(engine->toString(args[0]), + args[1]->NumberValue(), + args[2]->NumberValue()); + } + + return v8::Undefined(); } -//CanvasPixelArray interface -static QScriptValue ctx2d_pixelArray_length(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args) { - //#TODO - return QScriptValue(); + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE(); + + if (args.Length() == 3) { + r->context->strokeText(engine->toString(args[0]), + args[1]->NumberValue(), + args[2]->NumberValue()); + } + + return v8::Undefined(); } -//getter/setter by index how to? -static QScriptValue ctx2d_pixelArray(QScriptContext *c, QScriptEngine *e) + +// drawing images +static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args) +{ + QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This()); + if (!r || !r->context) + V8THROW_ERROR("Not a Context2D object"); + + QV8Engine *engine = V8ENGINE(); + + if (args.Length() == 3) { + r->context->drawImage(engine->toString(args[0]), + args[1]->NumberValue(), + args[2]->NumberValue()); + } else if (args.Length() == 5) { + r->context->drawImage(engine->toString(args[0]), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue(), + args[4]->NumberValue()); + } else if (args.Length() == 9) { + r->context->drawImage(engine->toString(args[0]), + args[1]->NumberValue(), + args[2]->NumberValue(), + args[3]->NumberValue(), + args[4]->NumberValue(), + args[5]->NumberValue(), + args[6]->NumberValue(), + args[7]->NumberValue(), + args[8]->NumberValue()); + } + + return v8::Undefined(); +} + +// pixel manipulation +static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args) { //#TODO - return QScriptValue(); + return v8::Undefined(); } -//CanvasGradient interface -static QScriptValue ctx2d_gradient_addColorStop(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args) { //#TODO - return QScriptValue(); + return v8::Undefined(); } -//TextMetrics -static QScriptValue ctx2d_textMetrics_width(QScriptContext *c, QScriptEngine *e) +static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args) { //#TODO - return QScriptValue(); + return v8::Undefined(); } - bool QSGContext2DPrivate::hasShadow() const { return state.shadowColor.isValid() @@ -2132,6 +2469,593 @@ bool QSGContext2D::isPointInPath(qreal x, qreal y) const return d->path.contains(QPointF(x, y)); } +//copied from QtSvg (qsvghandler.cpp). +Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); +// '0' is 0x30 and '9' is 0x39 +static inline bool isDigit(ushort ch) +{ + static quint16 magic = 0x3ff; + return ((ch >> 4) == 3) && (magic >> (ch & 15)); +} + +static qreal toDouble(const QChar *&str) +{ + const int maxLen = 255;//technically doubles can go til 308+ but whatever + char temp[maxLen+1]; + int pos = 0; + + if (*str == QLatin1Char('-')) { + temp[pos++] = '-'; + ++str; + } else if (*str == QLatin1Char('+')) { + ++str; + } + while (isDigit(str->unicode()) && pos < maxLen) { + temp[pos++] = str->toLatin1(); + ++str; + } + if (*str == QLatin1Char('.') && pos < maxLen) { + temp[pos++] = '.'; + ++str; + } + while (isDigit(str->unicode()) && pos < maxLen) { + temp[pos++] = str->toLatin1(); + ++str; + } + bool exponent = false; + if ((*str == QLatin1Char('e') || *str == QLatin1Char('E')) && pos < maxLen) { + exponent = true; + temp[pos++] = 'e'; + ++str; + if ((*str == QLatin1Char('-') || *str == QLatin1Char('+')) && pos < maxLen) { + temp[pos++] = str->toLatin1(); + ++str; + } + while (isDigit(str->unicode()) && pos < maxLen) { + temp[pos++] = str->toLatin1(); + ++str; + } + } + + temp[pos] = '\0'; + + qreal val; + if (!exponent && pos < 10) { + int ival = 0; + const char *t = temp; + bool neg = false; + if(*t == '-') { + neg = true; + ++t; + } + while(*t && *t != '.') { + ival *= 10; + ival += (*t) - '0'; + ++t; + } + if(*t == '.') { + ++t; + int div = 1; + while(*t) { + ival *= 10; + ival += (*t) - '0'; + div *= 10; + ++t; + } + val = ((qreal)ival)/((qreal)div); + } else { + val = ival; + } + if (neg) + val = -val; + } else { +#if defined(Q_WS_QWS) && !defined(Q_OS_VXWORKS) + if(sizeof(qreal) == sizeof(float)) + val = strtof(temp, 0); + else +#endif + { + bool ok = false; + val = qstrtod(temp, 0, &ok); + } + } + return val; + +} +static qreal toDouble(const QString &str, bool *ok = NULL) +{ + const QChar *c = str.constData(); + qreal res = toDouble(c); + if (ok) { + *ok = ((*c) == QLatin1Char('\0')); + } + return res; +} + +static qreal toDouble(const QStringRef &str, bool *ok = NULL) +{ + const QChar *c = str.constData(); + qreal res = toDouble(c); + if (ok) { + *ok = (c == (str.constData() + str.length())); + } + return res; +} +static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points) +{ + while (str->isSpace()) + ++str; + while (isDigit(str->unicode()) || + *str == QLatin1Char('-') || *str == QLatin1Char('+') || + *str == QLatin1Char('.')) { + + points.append(toDouble(str)); + + while (str->isSpace()) + ++str; + if (*str == QLatin1Char(',')) + ++str; + + //eat the rest of space + while (str->isSpace()) + ++str; + } +} + +static void pathArcSegment(QPainterPath &path, + qreal xc, qreal yc, + qreal th0, qreal th1, + qreal rx, qreal ry, qreal xAxisRotation) +{ + qreal sinTh, cosTh; + qreal a00, a01, a10, a11; + qreal x1, y1, x2, y2, x3, y3; + qreal t; + qreal thHalf; + + sinTh = qSin(xAxisRotation * (Q_PI / 180.0)); + cosTh = qCos(xAxisRotation * (Q_PI / 180.0)); + + a00 = cosTh * rx; + a01 = -sinTh * ry; + a10 = sinTh * rx; + a11 = cosTh * ry; + + thHalf = 0.5 * (th1 - th0); + t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf); + x1 = xc + qCos(th0) - t * qSin(th0); + y1 = yc + qSin(th0) + t * qCos(th0); + x3 = xc + qCos(th1); + y3 = yc + qSin(th1); + x2 = x3 + t * qSin(th1); + y2 = y3 - t * qCos(th1); + + path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, + a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, + a00 * x3 + a01 * y3, a10 * x3 + a11 * y3); +} + +static void pathArc(QPainterPath &path, + qreal rx, + qreal ry, + qreal x_axis_rotation, + int large_arc_flag, + int sweep_flag, + qreal x, + qreal y, + qreal curx, qreal cury) +{ + qreal sin_th, cos_th; + qreal a00, a01, a10, a11; + qreal x0, y0, x1, y1, xc, yc; + qreal d, sfactor, sfactor_sq; + qreal th0, th1, th_arc; + int i, n_segs; + qreal dx, dy, dx1, dy1, Pr1, Pr2, Px, Py, check; + + rx = qAbs(rx); + ry = qAbs(ry); + + sin_th = qSin(x_axis_rotation * (Q_PI / 180.0)); + cos_th = qCos(x_axis_rotation * (Q_PI / 180.0)); + + dx = (curx - x) / 2.0; + dy = (cury - y) / 2.0; + dx1 = cos_th * dx + sin_th * dy; + dy1 = -sin_th * dx + cos_th * dy; + Pr1 = rx * rx; + Pr2 = ry * ry; + Px = dx1 * dx1; + Py = dy1 * dy1; + /* Spec : check if radii are large enough */ + check = Px / Pr1 + Py / Pr2; + if (check > 1) { + rx = rx * qSqrt(check); + ry = ry * qSqrt(check); + } + + a00 = cos_th / rx; + a01 = sin_th / rx; + a10 = -sin_th / ry; + a11 = cos_th / ry; + x0 = a00 * curx + a01 * cury; + y0 = a10 * curx + a11 * cury; + x1 = a00 * x + a01 * y; + y1 = a10 * x + a11 * y; + /* (x0, y0) is current point in transformed coordinate space. + (x1, y1) is new point in transformed coordinate space. + + The arc fits a unit-radius circle in this space. + */ + d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); + sfactor_sq = 1.0 / d - 0.25; + if (sfactor_sq < 0) sfactor_sq = 0; + sfactor = qSqrt(sfactor_sq); + if (sweep_flag == large_arc_flag) sfactor = -sfactor; + xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); + yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); + /* (xc, yc) is center of the circle. */ + + th0 = qAtan2(y0 - yc, x0 - xc); + th1 = qAtan2(y1 - yc, x1 - xc); + + th_arc = th1 - th0; + if (th_arc < 0 && sweep_flag) + th_arc += 2 * Q_PI; + else if (th_arc > 0 && !sweep_flag) + th_arc -= 2 * Q_PI; + + n_segs = qCeil(qAbs(th_arc / (Q_PI * 0.5 + 0.001))); + + for (i = 0; i < n_segs; i++) { + pathArcSegment(path, xc, yc, + th0 + i * th_arc / n_segs, + th0 + (i + 1) * th_arc / n_segs, + rx, ry, x_axis_rotation); + } +} + + +static bool parsePathDataFast(const QString &dataStr, QPainterPath &path) +{ + qreal x0 = 0, y0 = 0; // starting point + qreal x = 0, y = 0; // current point + char lastMode = 0; + QPointF ctrlPt; + const QChar *str = dataStr.constData(); + const QChar *end = str + dataStr.size(); + + while (str != end) { + while (str->isSpace()) + ++str; + QChar pathElem = *str; + ++str; + QChar endc = *end; + *const_cast<QChar *>(end) = 0; // parseNumbersArray requires 0-termination that QStringRef cannot guarantee + QVarLengthArray<qreal, 8> arg; + parseNumbersArray(str, arg); + *const_cast<QChar *>(end) = endc; + if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z')) + arg.append(0);//dummy + const qreal *num = arg.constData(); + int count = arg.count(); + while (count > 0) { + qreal offsetX = x; // correction offsets + qreal offsetY = y; // for relative commands + switch (pathElem.unicode()) { + case 'm': { + if (count < 2) { + num++; + count--; + break; + } + x = x0 = num[0] + offsetX; + y = y0 = num[1] + offsetY; + num += 2; + count -= 2; + path.moveTo(x0, y0); + + // As per 1.2 spec 8.3.2 The "moveto" commands + // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands, + // the subsequent pairs shall be treated as implicit 'lineto' commands. + pathElem = QLatin1Char('l'); + } + break; + case 'M': { + if (count < 2) { + num++; + count--; + break; + } + x = x0 = num[0]; + y = y0 = num[1]; + num += 2; + count -= 2; + path.moveTo(x0, y0); + + // As per 1.2 spec 8.3.2 The "moveto" commands + // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands, + // the subsequent pairs shall be treated as implicit 'lineto' commands. + pathElem = QLatin1Char('L'); + } + break; + case 'z': + case 'Z': { + x = x0; + y = y0; + count--; // skip dummy + num++; + path.closeSubpath(); + } + break; + case 'l': { + if (count < 2) { + num++; + count--; + break; + } + x = num[0] + offsetX; + y = num[1] + offsetY; + num += 2; + count -= 2; + path.lineTo(x, y); + + } + break; + case 'L': { + if (count < 2) { + num++; + count--; + break; + } + x = num[0]; + y = num[1]; + num += 2; + count -= 2; + path.lineTo(x, y); + } + break; + case 'h': { + x = num[0] + offsetX; + num++; + count--; + path.lineTo(x, y); + } + break; + case 'H': { + x = num[0]; + num++; + count--; + path.lineTo(x, y); + } + break; + case 'v': { + y = num[0] + offsetY; + num++; + count--; + path.lineTo(x, y); + } + break; + case 'V': { + y = num[0]; + num++; + count--; + path.lineTo(x, y); + } + break; + case 'c': { + if (count < 6) { + num += count; + count = 0; + break; + } + QPointF c1(num[0] + offsetX, num[1] + offsetY); + QPointF c2(num[2] + offsetX, num[3] + offsetY); + QPointF e(num[4] + offsetX, num[5] + offsetY); + num += 6; + count -= 6; + path.cubicTo(c1, c2, e); + ctrlPt = c2; + x = e.x(); + y = e.y(); + break; + } + case 'C': { + if (count < 6) { + num += count; + count = 0; + break; + } + QPointF c1(num[0], num[1]); + QPointF c2(num[2], num[3]); + QPointF e(num[4], num[5]); + num += 6; + count -= 6; + path.cubicTo(c1, c2, e); + ctrlPt = c2; + x = e.x(); + y = e.y(); + break; + } + case 's': { + if (count < 4) { + num += count; + count = 0; + break; + } + QPointF c1; + if (lastMode == 'c' || lastMode == 'C' || + lastMode == 's' || lastMode == 'S') + c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y()); + else + c1 = QPointF(x, y); + QPointF c2(num[0] + offsetX, num[1] + offsetY); + QPointF e(num[2] + offsetX, num[3] + offsetY); + num += 4; + count -= 4; + path.cubicTo(c1, c2, e); + ctrlPt = c2; + x = e.x(); + y = e.y(); + break; + } + case 'S': { + if (count < 4) { + num += count; + count = 0; + break; + } + QPointF c1; + if (lastMode == 'c' || lastMode == 'C' || + lastMode == 's' || lastMode == 'S') + c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y()); + else + c1 = QPointF(x, y); + QPointF c2(num[0], num[1]); + QPointF e(num[2], num[3]); + num += 4; + count -= 4; + path.cubicTo(c1, c2, e); + ctrlPt = c2; + x = e.x(); + y = e.y(); + break; + } + case 'q': { + if (count < 4) { + num += count; + count = 0; + break; + } + QPointF c(num[0] + offsetX, num[1] + offsetY); + QPointF e(num[2] + offsetX, num[3] + offsetY); + num += 4; + count -= 4; + path.quadTo(c, e); + ctrlPt = c; + x = e.x(); + y = e.y(); + break; + } + case 'Q': { + if (count < 4) { + num += count; + count = 0; + break; + } + QPointF c(num[0], num[1]); + QPointF e(num[2], num[3]); + num += 4; + count -= 4; + path.quadTo(c, e); + ctrlPt = c; + x = e.x(); + y = e.y(); + break; + } + case 't': { + if (count < 2) { + num += count; + count = 0; + break; + } + QPointF e(num[0] + offsetX, num[1] + offsetY); + num += 2; + count -= 2; + QPointF c; + if (lastMode == 'q' || lastMode == 'Q' || + lastMode == 't' || lastMode == 'T') + c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y()); + else + c = QPointF(x, y); + path.quadTo(c, e); + ctrlPt = c; + x = e.x(); + y = e.y(); + break; + } + case 'T': { + if (count < 2) { + num += count; + count = 0; + break; + } + QPointF e(num[0], num[1]); + num += 2; + count -= 2; + QPointF c; + if (lastMode == 'q' || lastMode == 'Q' || + lastMode == 't' || lastMode == 'T') + c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y()); + else + c = QPointF(x, y); + path.quadTo(c, e); + ctrlPt = c; + x = e.x(); + y = e.y(); + break; + } + case 'a': { + if (count < 7) { + num += count; + count = 0; + break; + } + qreal rx = (*num++); + qreal ry = (*num++); + qreal xAxisRotation = (*num++); + qreal largeArcFlag = (*num++); + qreal sweepFlag = (*num++); + qreal ex = (*num++) + offsetX; + qreal ey = (*num++) + offsetY; + count -= 7; + qreal curx = x; + qreal cury = y; + pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag), + int(sweepFlag), ex, ey, curx, cury); + + x = ex; + y = ey; + } + break; + case 'A': { + if (count < 7) { + num += count; + count = 0; + break; + } + qreal rx = (*num++); + qreal ry = (*num++); + qreal xAxisRotation = (*num++); + qreal largeArcFlag = (*num++); + qreal sweepFlag = (*num++); + qreal ex = (*num++); + qreal ey = (*num++); + count -= 7; + qreal curx = x; + qreal cury = y; + pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag), + int(sweepFlag), ex, ey, curx, cury); + + x = ex; + y = ey; + } + break; + default: + return false; + } + lastMode = pathElem.toLatin1(); + } + } + return true; +} + +void QSGContext2D::setPathString(const QString& path) +{ + Q_D(QSGContext2D); + d->path = QPainterPath(); + parsePathDataFast(path, d->path); +} QList<int> QSGContext2D::getImageData(qreal sx, qreal sy, qreal sw, qreal sh) { @@ -2184,78 +3108,110 @@ bool QSGContext2D::isDirty() const return !d->commands.isEmpty(); } -QScriptValue QSGContext2D::scriptValue() const +v8::Handle<v8::Object> QSGContext2D::v8value() const { Q_D(const QSGContext2D); - return d->scriptValue; -} - -void QSGContext2D::setScriptEngine(QScriptEngine *eng) + return d->v8value; +} + +class QSGContext2DEngineData : public QV8Engine::Deletable +{ +public: + QSGContext2DEngineData(QV8Engine *engine); + ~QSGContext2DEngineData(); + + v8::Persistent<v8::Function> constructor; +}; + +QSGContext2DEngineData::QSGContext2DEngineData(QV8Engine *engine) +{ + v8::HandleScope handle_scope; + v8::Context::Scope scope(engine->context()); + + v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); + ft->InstanceTemplate()->SetHasExternalResource(true); + ft->PrototypeTemplate()->Set(v8::String::New("sync"), V8FUNCTION(ctx2d_sync, engine)); + ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine)); + ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("fillColor"), ctx2d_fillColor, ctx2d_fillColor_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeColor"), ctx2d_strokeColor, ctx2d_strokeColor_set, v8::External::Wrap(engine)); + ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine)); + ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("setPathString"), V8FUNCTION(ctx2d_setPathString, engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine)); + ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine)); + ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine)); + // ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine)); + + constructor = qPersistentNew(ft->GetFunction()); +} + +QSGContext2DEngineData::~QSGContext2DEngineData() +{ + qPersistentDispose(constructor); +} + +V8_DEFINE_EXTENSION(QSGContext2DEngineData, engineData); + +void QSGContext2D::setV8Engine(QV8Engine *engine) { Q_D(QSGContext2D); - if (d->scriptEngine != eng) { - d->scriptEngine = eng; - d->scriptValue = eng->newObject(); - d->scriptValue.setData(eng->toScriptValue(this)); - d->scriptValue.setProperty(QLatin1String("sync"), eng->newFunction(ctx2d_sync)); - d->scriptValue.setProperty(QLatin1String("canvas"), eng->newFunction(ctx2d_canvas),QScriptValue::PropertyGetter); - d->scriptValue.setProperty(QLatin1String("restore"), eng->newFunction(ctx2d_restore)); - d->scriptValue.setProperty(QLatin1String("save"), eng->newFunction(ctx2d_save)); - d->scriptValue.setProperty(QLatin1String("rotate"), eng->newFunction(ctx2d_rotate, 1)); - d->scriptValue.setProperty(QLatin1String("scale"), eng->newFunction(ctx2d_scale, 2)); - d->scriptValue.setProperty(QLatin1String("setTransform"), eng->newFunction(ctx2d_setTransform, 6)); - d->scriptValue.setProperty(QLatin1String("transform"), eng->newFunction(ctx2d_transform, 6)); - d->scriptValue.setProperty(QLatin1String("translate"), eng->newFunction(ctx2d_translate, 2)); - d->scriptValue.setProperty(QLatin1String("globalAlpha"), eng->newFunction(ctx2d_globalAlpha), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("globalCompositeOperation"), eng->newFunction(ctx2d_globalCompositeOperation), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("fillStyle"), eng->newFunction(ctx2d_fillStyle), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("strokeStyle"), eng->newFunction(ctx2d_strokeStyle), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("fillColor"), eng->newFunction(ctx2d_fillColor), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("strokeColor"), eng->newFunction(ctx2d_strokeColor), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("createLinearGradient"), eng->newFunction(ctx2d_createLinearGradient, 4)); - d->scriptValue.setProperty(QLatin1String("createRadialGradient"), eng->newFunction(ctx2d_createRadialGradient, 6)); - d->scriptValue.setProperty(QLatin1String("createPattern"), eng->newFunction(ctx2d_createPattern, 2)); - d->scriptValue.setProperty(QLatin1String("lineCap"), eng->newFunction(ctx2d_lineCap), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("lineJoin"), eng->newFunction(ctx2d_lineJoin), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("lineWidth"), eng->newFunction(ctx2d_lineWidth), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("miterLimit"), eng->newFunction(ctx2d_miterLimit), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("shadowBlur"), eng->newFunction(ctx2d_shadowBlur), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("shadowColor"), eng->newFunction(ctx2d_shadowColor), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("shadowOffsetX"), eng->newFunction(ctx2d_shadowOffsetX), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("shadowOffsetY"), eng->newFunction(ctx2d_shadowOffsetY), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("clearRect"), eng->newFunction(ctx2d_clearRect, 4)); - d->scriptValue.setProperty(QLatin1String("fillRect"), eng->newFunction(ctx2d_fillRect, 4)); - d->scriptValue.setProperty(QLatin1String("strokeRect"), eng->newFunction(ctx2d_strokeRect, 4)); - d->scriptValue.setProperty(QLatin1String("arc"), eng->newFunction(ctx2d_arc, 6)); - d->scriptValue.setProperty(QLatin1String("arcTo"), eng->newFunction(ctx2d_arcTo, 5)); - d->scriptValue.setProperty(QLatin1String("beginPath"), eng->newFunction(ctx2d_beginPath)); - d->scriptValue.setProperty(QLatin1String("bezierCurveTo"), eng->newFunction(ctx2d_bezierCurveTo, 6)); - d->scriptValue.setProperty(QLatin1String("clip"), eng->newFunction(ctx2d_clip)); - d->scriptValue.setProperty(QLatin1String("closePath"), eng->newFunction(ctx2d_closePath)); - d->scriptValue.setProperty(QLatin1String("fill"), eng->newFunction(ctx2d_fill)); - d->scriptValue.setProperty(QLatin1String("lineTo"), eng->newFunction(ctx2d_lineTo, 2)); - d->scriptValue.setProperty(QLatin1String("moveTo"), eng->newFunction(ctx2d_moveTo, 2)); - d->scriptValue.setProperty(QLatin1String("quadraticCurveTo"), eng->newFunction(ctx2d_quadraticCurveTo, 4)); - d->scriptValue.setProperty(QLatin1String("rect"), eng->newFunction(ctx2d_rect, 4)); - d->scriptValue.setProperty(QLatin1String("stroke"), eng->newFunction(ctx2d_stroke)); - d->scriptValue.setProperty(QLatin1String("isPointInPath"), eng->newFunction(ctx2d_isPointInPath, 2)); - d->scriptValue.setProperty(QLatin1String("font"), eng->newFunction(ctx2d_font), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("textAlign"), eng->newFunction(ctx2d_textAlign), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("textBaseline"), eng->newFunction(ctx2d_textBaseline), QScriptValue::PropertyGetter | QScriptValue::PropertySetter); - d->scriptValue.setProperty(QLatin1String("fillText"), eng->newFunction(ctx2d_fillText, 4)); - //d->scriptValue.setProperty(QLatin1String("measureText"), eng->newFunction(ctx2d_measureText, 1)); - d->scriptValue.setProperty(QLatin1String("strokeText"), eng->newFunction(ctx2d_strokeText, 4)); - d->scriptValue.setProperty(QLatin1String("drawImage"), eng->newFunction(ctx2d_drawImage, 9)); - d->scriptValue.setProperty(QLatin1String("createImageData"), eng->newFunction(ctx2d_createImageData, 2)); - d->scriptValue.setProperty(QLatin1String("getImageData"), eng->newFunction(ctx2d_getImageData, 4)); - d->scriptValue.setProperty(QLatin1String("putImageData"), eng->newFunction(ctx2d_putImageData, 7)); - } -} - -QScriptEngine *QSGContext2D::scriptEngine() const -{ - Q_D(const QSGContext2D); - return d->scriptEngine; + if (d->v8engine != engine) { + d->v8engine = engine; + + qPersistentDispose(d->v8value); + + if (d->v8engine == 0) + return; + + QSGContext2DEngineData *ed = engineData(engine); + d->v8value = qPersistentNew(ed->constructor->NewInstance()); + QV8Context2DResource *r = new QV8Context2DResource(engine); + r->context = this; + d->v8value->SetExternalResource(r); + } } void QSGContext2D::addref() @@ -2274,353 +3230,6 @@ void QSGContext2D::release() } } - -bool QSGContext2D::inWorkerThread() const -{ - Q_D(const QSGContext2D); - return d->agentData != 0; -} -const QString& QSGContext2D::agentScript() const -{ - static QString script; - if (script.isEmpty()) { - script = QString::fromLatin1( - "function CanvasImageData(w, h, d) {" - " this.width = w;" - " this.height = h;" - " this.data = d;" - "}" - "function Context2DAgent(_ctx2d) {" - " this._ctx = _ctx2d;" - " this._fillColor = '#000000';" - " this._fillStyle = '#000000';" - " this._strokeColor = '#000000';" - " this._strokeStyle = '#000000';" - " this._globalCompositeOperation = \"source-over\";" - " this._commands = [];" - " this.createImageData = function() {" - " var d = null;" - " if (arguments.length == 1 && arguments[0] instanceof CanvasImageData) {" - " d = new CanvasImageData(arguments[0].width," - " arguments[0].height," - " new Array(arguments[0].width * arguments[0].height * 4));" - " } else if (arguments.length == 2) {" - " d = new CanvasImageData(arguments[0], arguments[1], new Array(arguments[0] * arguments[1] * 4));" - " }" - " if (d)" - " for (var i=0; i<d.data.length; i++)" - " d.data[i] = 255;" - " return d;" - " };" - " this.getImageData = function(sx, sy, sw, sh) {" - " var imageData = new CanvasImageData(sw, sh, this._ctx.getImageData(sx, sy, sw, sh));" - " return imageData;" - " };" - " this.sync = function() {" - " this._ctx.processCommands(this._commands);" - " this._commands.length = 0;" - " };"); - - script.append(QString::fromLatin1( - "this.save = function() {" - " this._commands.push([%1]);" - "};").arg(Save)); - - script.append(QString::fromLatin1( - "this.restore = function() {" - " this._commands.push([%1]);" - "};").arg(Restore)); - - script.append(QString::fromLatin1( - "this.scale = function(x, y) {" - " this._commands.push([%1, x, y]);" - "};").arg(Scale)); - - script.append(QString::fromLatin1( - "this.createImage = function(url) {" - " return this._ctx.createImage(url);" - "};")); - - script.append(QString::fromLatin1( - "this.rotate = function(x) {" - " this._commands.push([%1, x]);" - "};").arg(Rotate)); - - script.append(QString::fromLatin1( - "this.translate = function(x, y) {" - " this._commands.push([%1, x, y]);" - "};").arg(Translate)); - - script.append(QString::fromLatin1( - "this.transform = function(a1, a2, a3, a4, a5, a6) {" - " this._commands.push([%1, a1, a2, a3, a4, a5, a6]);" - "};").arg(Transform)); - - script.append(QString::fromLatin1( - "this.setTransform = function(a1, a2, a3, a4, a5, a6) {" - " this._commands.push([%1, a1, a2, a3, a4, a5, a6]);" - "};").arg(SetTransform)); - - script.append(QString::fromLatin1( - "this.clearRect = function(x, y, w, h) {" - " this._commands.push([%1, x, y, w, h]);" - "};").arg(ClearRect)); - - script.append(QString::fromLatin1( - "this.fillRect = function(x, y, w, h) {" - " this._commands.push([%1, x, y, w, h]);" - "};").arg(FillRect)); - - script.append(QString::fromLatin1( - "this.strokeRect = function(x, y, w, h) {" - " this._commands.push([%1, x, y, w, h]);" - "};").arg(StrokeRect)); - - script.append(QString::fromLatin1( - "this.beginPath = function() {" - " this._commands.push([%1]);" - "};").arg(BeginPath)); - - script.append(QString::fromLatin1( - "this.closePath = function() {" - " this._commands.push([%1]);" - "};").arg(ClosePath)); - - script.append(QString::fromLatin1( - "this.moveTo = function(x, y) {" - " this._commands.push([%1, x, y]);" - "};").arg(MoveTo)); - - script.append(QString::fromLatin1( - "this.lineTo = function(x, y) {" - " this._commands.push([%1, x, y]);" - "};").arg(LineTo)); - - script.append(QString::fromLatin1( - "this.quadraticCurveTo = function(a1, a2, a3, a4) {" - " this._commands.push([%1, a1, a2, a3, a4]);" - "};").arg(QuadraticCurveTo)); - - script.append(QString::fromLatin1( - "this.bezierCurveTo = function(a1, a2, a3, a4, a5, a6) {" - " this._commands.push([%1, a1, a2, a3, a4, a5, a6]);" - "};").arg(BezierCurveTo)); - - script.append(QString::fromLatin1( - "this.arcTo = function(x1, y1, x2, y2, radius) {" - " this._commands.push([%1, x1, y1, x2, y2, radius]);" - "};").arg(ArcTo)); - - script.append(QString::fromLatin1( - "this.rect = function(x, y, w, h) {" - " this._commands.push([%1, x, y, w, h]);" - "};").arg(Rect)); - - script.append(QString::fromLatin1( - "this.rect = function(x, y, radius, startAngle, endAngle, anticlockwise) {" - " this._commands.push([%1, x, y, radius, startAngle, endAngle, anticlockwise]);" - "};").arg(Arc)); - - script.append(QString::fromLatin1( - "this.fill = function() {" - " this._commands.push([%1]);" - "};").arg(Fill)); - - script.append(QString::fromLatin1( - "this.stroke = function() {" - " this._commands.push([%1]);" - "};").arg(Stroke)); - - script.append(QString::fromLatin1( - "this.clip = function() {" - " this._commands.push([%1]);" - "};").arg(Clip)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"globalAlpha\", function() {" - " return this._globalAlpha;" - " });" - " this.__defineSetter__(\"globalAlpha\", function(v) {" - " this._globalAlpha = v;" - " this._commands.push([%1, v]);" - " });").arg(GlobalAlpha)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"globalCompositeOperation\", function() {" - " return this._globalCompositeOperation;" - " });" - " this.__defineSetter__(\"globalCompositeOperation\", function(v) {" - " this._globalCompositeOperation = v;" - " this._commands.push([%1, v]);" - " });").arg(GlobalCompositeOperation)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"strokeStyle\", function() {return this._strokeStyle; });" - " this.__defineSetter__(\"strokeStyle\", function(v) {" - " this._commands.push([%1, v]);" - " this._strokeStyle = v;" - " });").arg(StrokeStyle)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"fillStyle\", function() {return this._fillStyle; });" - " this.__defineSetter__(\"fillStyle\", function(v) {" - " this._commands.push([%1, v]);" - " this._fillStyle = v;" - " });").arg(FillStyle)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"strokeColor\", function() {return this._strokeColor; });" - " this.__defineSetter__(\"strokeColor\", function(v) {" - " this._commands.push([%1, v]);" - " this._strokeColor = v;" - " });").arg(StrokeColor)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"fillColor\", function() {return this._fillColor; });" - " this.__defineSetter__(\"fillColor\", function(v) {" - " this._commands.push([%1, v]);" - " this._fillColor = v;" - " });").arg(FillColor)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"lineWidth\", function() {return this._lineWidth; });" - " this.__defineSetter__(\"lineWidth\", function(v) {" - " this._commands.push([%1, v]);" - " this._lineWidth = v;" - " });").arg(LineWidth)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"lineCap\", function() {return this._lineCap; });" - " this.__defineSetter__(\"lineCap\", function(v) {" - " this._commands.push([%1, v]);" - " this._lineCap = v;" - " });").arg(LineCap)); - - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"lineJoin\", function() {return this._lineJoin; });" - " this.__defineSetter__(\"lineJoin\", function(v) {" - " this._commands.push([%1, v]);" - " this._lineJoin = v;" - " });").arg(LineJoin)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"miterLimit\", function() {return this._miterLimit; });" - " this.__defineSetter__(\"miterLimit\", function(v) {" - " this._commands.push([%1, v]);" - " this._miterLimit = v;" - " });").arg(MiterLimit)); - - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"shadowOffsetX\", function() {return this._shadowOffsetX; });" - " this.__defineSetter__(\"shadowOffsetX\", function(v) {" - " this._commands.push([%1, v]);" - " this._shadowOffsetX = v;" - " });").arg(ShadowOffsetX)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"shadowOffsetY\", function() {return this._shadowOffsetY; });" - " this.__defineSetter__(\"shadowOffsetY\", function(v) {" - " this._commands.push([%1, v]);" - " this._shadowOffsetY = v;" - " });").arg(ShadowOffsetY)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"shadowBlur\", function() {return this._shadowBlur; });" - " this.__defineSetter__(\"shadowBlur\", function(v) {" - " this._commands.push([%1, v]);" - " this._shadowBlur = v;" - " });").arg(ShadowBlur)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"shadowColor\", function() {return this._shadowColor; });" - " this.__defineSetter__(\"shadowColor\", function(v) {" - " this._commands.push([%1, v]);" - " this._shadowColor = v;" - " });").arg(ShadowColor)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"font\", function() {return this._font; });" - " this.__defineSetter__(\"font\", function(v) {" - " this._commands.push([%1, v]);" - " this._font = v;" - " });").arg(Font)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"textBaseline\", function() {return this._textBaseline; });" - " this.__defineSetter__(\"textBaseline\", function(v) {" - " this._commands.push([%1, v]);" - " this._textBaseline = v;" - " });").arg(TextBaseline)); - - script.append(QString::fromLatin1( - " this.__defineGetter__(\"textAlign\", function() {return this._textAlign; });" - " this.__defineSetter__(\"textAlign\", function(v) {" - " this._commands.push([%1, v]);" - " this._textAlign = v;" - " });").arg(TextAlign)); - - script.append(QString::fromLatin1( - "this.fillText = function(text, x, y) {" - " this._commands.push([%1, text, x, y]);" - "};").arg(FillText)); - - script.append(QString::fromLatin1( - "this.strokeText = function(text, x, y) {" - " this._commands.push([%1, text, x, y]);" - "};").arg(StrokeText)); - - script.append(QString::fromLatin1( - "this.drawImage = function() {" - " if (arguments.length == 3) {" - " this._commands.push([%1, arguments[0], arguments[1], arguments[2]]);" - " } else if (arguments.length == 5) {" - " this._commands.push([%2, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]]);" - " } else if (arguments.length == 9) {" - " this._commands.push([%3, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7], arguments[8]]);}" - "};").arg(DrawImage1).arg(DrawImage2).arg(DrawImage3)); - - script.append(QString::fromLatin1( - "this.putImageData = function() {" - " var dx = arguments[1];" - " var dy = arguments[2];" - " if (arguments.length == 3) {" - " this._commands.push([%1, arguments[0].data, dx, dy, arguments[0].width, arguments[0].height]);" - " } else if (arguments.length == 7) {" - " var dirtyX = arguments[3];" - " var dirtyY = arguments[4];" - " var dirtyWidth = arguments[5];" - " var dirtyHeight = arguments[6];" - " var width = arguments[0].width;" - " var height = arguments[0].heigh;" - " var filteredData = arguments[0].data.filter(function(element, index, array){" - " var x=index/width;" - " var y=index%width-1;" - " return x >= dirtyX && x < dirtyX+dirtyWidth" - " && y >= dirtyY && y < dirtyY+dirtyHeight;" - " });" - " this._commands.push([%2, filteredData, dx, dy, dirtyWidth, dirtyHeight]);" - " }" - "};").arg(PutImageData).arg(PutImageData)); - script.append(QString::fromLatin1("}")); - } - return script; -} - -QSGContext2D *QSGContext2D::agent() -{ - Q_D(QSGContext2D); - - if (d->agent) - return d->agent; - - d->agent = new QSGContext2D(this, new QSGContext2DWorkerAgent); - connect(this, SIGNAL(painted()), d->agent, SIGNAL(painted())); - d->agent->setSize(size()); - return d->agent; - -} void QSGContext2D::processCommands(const QScriptValue& commands) { #ifdef QSGCANVASITEM_DEBUG @@ -2941,10 +3550,8 @@ void QSGContext2D::paint(QPainter* p) switch (cmd) { case UpdateMatrix: { -// qDebug() << "update matrix from " << d->state.matrix << " to " << d->matrixes[matrix_idx]; - //p->setWorldTransform(transform * QTransform(d->matrixes[matrix_idx++]), false); - //p->setMatrix(d->matrixes[matrix_idx++]); d->state.matrix = d->matrixes[matrix_idx++]; + p->setMatrix(d->state.matrix); break; } case ClearRect: @@ -2962,7 +3569,6 @@ void QSGContext2D::paint(QPainter* p) qreal y = d->reals[real_idx++]; qreal w = d->reals[real_idx++]; qreal h = d->reals[real_idx++]; -// qDebug() << "fillRect(" << x << y << w << h << ")"; if (d->hasShadow()) d->fillRectShadow(p, QRectF(x, y, w, h)); else @@ -2996,6 +3602,7 @@ void QSGContext2D::paint(QPainter* p) case Fill: { QPainterPath path = d->pathes[path_idx++]; + //qDebug() << "fill path:" << path.elementCount(); if (d->hasShadow()) d->fillShadowPath(p,path); else @@ -3004,8 +3611,10 @@ void QSGContext2D::paint(QPainter* p) } case Stroke: { - p->setMatrix(d->state.matrix); - QPainterPath path = d->state.matrix.inverted().map(d->pathes[path_idx++]); + //p->setMatrix(d->state.matrix); + //QPainterPath path = d->state.matrix.inverted().map(d->pathes[path_idx++]); + //qDebug() << "stroke path:" << path.elementCount(); + QPainterPath path = d->pathes[path_idx++]; if (d->hasShadow()) d->strokeShadowPath(p,path); else @@ -3229,9 +3838,6 @@ void QSGContext2D::setCachedImage(const QImage& image) d->waitingForPainting = false; } #endif - if (inWorkerThread()) { - d->agent->setCachedImage(image); - } } void QSGContext2D::clear() diff --git a/src/declarative/items/qsgcontext2d_p.h b/src/declarative/items/qsgcontext2d_p.h index 30af1f1cd6..924c4bf780 100644 --- a/src/declarative/items/qsgcontext2d_p.h +++ b/src/declarative/items/qsgcontext2d_p.h @@ -56,6 +56,7 @@ #include <QtCore/qcoreevent.h> #include <QtCore/qvariant.h> #include <QtScript/qscriptvalue.h> +#include <private/qv8engine_p.h> #include <QMutex> #include <QWaitCondition> #include "qsgimage_p.h" @@ -290,6 +291,10 @@ public slots: void clip(); bool isPointInPath(qreal x, qreal y) const; + //path string parser + //implement the W3C SVG path spec: + //http://www.w3.org/TR/SVG/paths.html + void setPathString(const QString& path); QSGImage *createImage(const QString &url); @@ -309,9 +314,8 @@ signals: void painted(); public: bool isDirty() const; - QScriptValue scriptValue() const; - void setScriptEngine(QScriptEngine *eng); - QScriptEngine *scriptEngine() const; + v8::Handle<v8::Object> v8value() const; + void setV8Engine(QV8Engine *eng); void addref(); void release(); @@ -335,11 +339,6 @@ public: Sync() : QEvent(QEvent::User) {} QSGContext2DWorkerAgent *data; }; - inline bool inWorkerThread() const; - QSGContext2D *agent(); - const QString& agentScript() const; - - struct State { QMatrix matrix; QPainterPath clipPath; diff --git a/src/declarative/items/qsgcontext2d_p_p.h b/src/declarative/items/qsgcontext2d_p_p.h index a412e6638a..4fcf40406e 100644 --- a/src/declarative/items/qsgcontext2d_p_p.h +++ b/src/declarative/items/qsgcontext2d_p_p.h @@ -78,12 +78,17 @@ public: QSGContext2DPrivate() : agent(0) , agentData(0) - , scriptEngine(0) + , v8engine(0) , cachedImage(1,1, QImage::Format_ARGB32) , canvas(0) , waitingForPainting(false) { } + ~QSGContext2DPrivate() + { + qPersistentDispose(v8value); + } + void updateMatrix(const QMatrix& m); void setSize(const QSize &s) @@ -215,8 +220,10 @@ public: //workerscript agent QSGContext2D* agent; QSGContext2DWorkerAgent* agentData; - QScriptEngine* scriptEngine; - QScriptValue scriptValue; + + QV8Engine *v8engine; + v8::Persistent<v8::Object> v8value; + QImage cachedImage; QSGCanvasItem* canvas; bool waitingForPainting; diff --git a/src/declarative/items/qsgitem.cpp b/src/declarative/items/qsgitem.cpp index 5926274dba..2b6f5573aa 100644 --- a/src/declarative/items/qsgitem.cpp +++ b/src/declarative/items/qsgitem.cpp @@ -1837,20 +1837,33 @@ void QSGItem::polish() } } -QScriptValue QSGItem::mapFromItem(const QScriptValue &item, qreal x, qreal y) const +void QSGItem::mapFromItem(QDeclarativeV8Function *args) const { - QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject(); - QSGItem *itemObj = qobject_cast<QSGItem*>(item.toQObject()); - if (!itemObj && !item.isNull()) { - qmlInfo(this) << "mapFromItem() given argument \"" << item.toString() << "\" which is neither null nor an Item"; - return 0; - } + if (args->Length() != 0) { + v8::Local<v8::Value> item = (*args)[0]; + QV8Engine *engine = args->engine(); + + QSGItem *itemObj = 0; + if (!item->IsNull()) + itemObj = qobject_cast<QSGItem*>(engine->toQObject(item)); + + if (!itemObj && !item->IsNull()) { + qmlInfo(this) << "mapFromItem() given argument \"" << engine->toString(item->ToString()) + << "\" which is neither null nor an Item"; + return; + } + + v8::Local<v8::Object> rv = v8::Object::New(); + args->returnValue(rv); + + qreal x = (args->Length() > 1)?(*args)[1]->NumberValue():0; + qreal y = (args->Length() > 2)?(*args)[2]->NumberValue():0; - // If QSGItem::mapFromItem() is called with 0, behaves the same as mapFromScene() - QPointF p = mapFromItem(itemObj, QPointF(x, y)); - sv.setProperty(QLatin1String("x"), p.x()); - sv.setProperty(QLatin1String("y"), p.y()); - return sv; + QPointF p = mapFromItem(itemObj, QPointF(x, y)); + + rv->Set(v8::String::New("x"), v8::Number::New(p.x())); + rv->Set(v8::String::New("y"), v8::Number::New(p.y())); + } } QTransform QSGItem::itemTransform(QSGItem *other, bool *ok) const @@ -1867,20 +1880,33 @@ QTransform QSGItem::itemTransform(QSGItem *other, bool *ok) const return t; } -QScriptValue QSGItem::mapToItem(const QScriptValue &item, qreal x, qreal y) const +void QSGItem::mapToItem(QDeclarativeV8Function *args) const { - QScriptValue sv = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(this))->newObject(); - QSGItem *itemObj = qobject_cast<QSGItem*>(item.toQObject()); - if (!itemObj && !item.isNull()) { - qmlInfo(this) << "mapToItem() given argument \"" << item.toString() << "\" which is neither null nor an Item"; - return 0; - } + if (args->Length() != 0) { + v8::Local<v8::Value> item = (*args)[0]; + QV8Engine *engine = args->engine(); + + QSGItem *itemObj = 0; + if (!item->IsNull()) + itemObj = qobject_cast<QSGItem*>(engine->toQObject(item)); + + if (!itemObj && !item->IsNull()) { + qmlInfo(this) << "mapToItem() given argument \"" << engine->toString(item->ToString()) + << "\" which is neither null nor an Item"; + return; + } + + v8::Local<v8::Object> rv = v8::Object::New(); + args->returnValue(rv); + + qreal x = (args->Length() > 1)?(*args)[1]->NumberValue():0; + qreal y = (args->Length() > 2)?(*args)[2]->NumberValue():0; - // If QSGItem::mapToItem() is called with 0, behaves the same as mapToScene() - QPointF p = mapToItem(itemObj, QPointF(x, y)); - sv.setProperty(QLatin1String("x"), p.x()); - sv.setProperty(QLatin1String("y"), p.y()); - return sv; + QPointF p = mapToItem(itemObj, QPointF(x, y)); + + rv->Set(v8::String::New("x"), v8::Number::New(p.x())); + rv->Set(v8::String::New("y"), v8::Number::New(p.y())); + } } void QSGItem::forceActiveFocus() diff --git a/src/declarative/items/qsgitem.h b/src/declarative/items/qsgitem.h index 425e5bc35c..e7d9d0aa0a 100644 --- a/src/declarative/items/qsgitem.h +++ b/src/declarative/items/qsgitem.h @@ -288,8 +288,8 @@ public: void polish(); - Q_INVOKABLE QScriptValue mapFromItem(const QScriptValue &item, qreal x, qreal y) const; - Q_INVOKABLE QScriptValue mapToItem(const QScriptValue &item, qreal x, qreal y) const; + Q_INVOKABLE void mapFromItem(QDeclarativeV8Function*) const; + Q_INVOKABLE void mapToItem(QDeclarativeV8Function*) const; Q_INVOKABLE void forceActiveFocus(); Q_INVOKABLE QSGItem *childAt(qreal x, qreal y) const; |