From b119220da60453ecf31898f7a57eda9d3c4e9225 Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Tue, 12 Jul 2011 09:21:27 +1000 Subject: Rewrite the canvas item's paint logic. 1. Only allow the context API calls inside onPaint() slot function, makes the context2d handle invalid when out of scope. 2. requestPaint() method supports region parameter 3. Emit paint() signal in updatePolish() function to allow threaded scene graph rendering work properly with context2d api 4. Allow request painting mutiple dirty regions between 2 frames. 5. Add svgpath for context2d Change-Id: I5ec48f7c0eb6820d5c9c16a8d0dcc0aae8d0fd2f Reviewed-on: http://codereview.qt.nokia.com/1465 Reviewed-by: Charles Yin --- examples/declarative/canvas/svgpath/tiger.js | 8 +- examples/declarative/canvas/svgpath/tiger.qml | 86 +++++- src/declarative/items/qsgcanvasitem.cpp | 119 ++++++- src/declarative/items/qsgcanvasitem_p.h | 20 +- src/declarative/items/qsgcontext2d.cpp | 427 +++++++++++++++++--------- src/declarative/items/qsgcontext2d_p.h | 19 ++ src/declarative/items/qsgcontext2d_p_p.h | 4 + 7 files changed, 490 insertions(+), 193 deletions(-) diff --git a/examples/declarative/canvas/svgpath/tiger.js b/examples/declarative/canvas/svgpath/tiger.js index 2695cd52fe..d8657b5abe 100644 --- a/examples/declarative/canvas/svgpath/tiger.js +++ b/examples/declarative/canvas/svgpath/tiger.js @@ -724,6 +724,7 @@ var tiger = [ function draw(ctx, frame) { + var startTime = new Date(); var totalPaths = tiger.length; if (frame > totalPaths) @@ -731,14 +732,12 @@ function draw(ctx, frame) ctx.reset(); ctx.globalCompositeOperation = "source-over"; ctx.fillStyle = "rgba(0,0,0,0)"; - //ctx.fillRect(0, 0, 600, 600); ctx.fillRect(0, 0, 1900, 1200); ctx.strokeColor = Qt.rgba(133, 133, 133,1); ctx.lineWidth = 1; - //ctx.translate(200, 200); ctx.translate(750, 350); - ctx.scale(2,2); + ctx.scale(5,5); for (var i = 0; i < frame; i++) { if (tiger[i].width != undefined) ctx.lineWidth = tiger[i].width; @@ -756,6 +755,9 @@ function draw(ctx, frame) ctx.stroke(); } } + var endTime = new Date(); + console.log("Javascript time:" + (endTime.valueOf() - startTime.valueOf())); + } diff --git a/examples/declarative/canvas/svgpath/tiger.qml b/examples/declarative/canvas/svgpath/tiger.qml index 96d19d3dba..77161e7c46 100644 --- a/examples/declarative/canvas/svgpath/tiger.qml +++ b/examples/declarative/canvas/svgpath/tiger.qml @@ -5,29 +5,81 @@ Canvas { id:canvas width:1900 height:1100 + fillColor:"#000000" + focus:true + renderTarget:PaintedItem.FramebufferObject property int frame:0 - - Timer { - repeat:true - interval:100 - running:true - onTriggered: { + property date paintingTime + Component.onCompleted: { + canvas.frame++; + canvas.requestPaint(); + } + onPainted: { + var endPaintingTime = new Date; + console.log("painting time:" + (endPaintingTime.valueOf() - canvas.paintingTime.valueOf())); canvas.frame++; if (canvas.frame > Tiger.tiger.length) { - canvas.frame = 0; +// canvas.frame = 0; + canvas.frame = Tiger.tiger.length; } else { - Tiger.draw(canvas.getContext(), canvas.frame); + canvas.requestPaint(); } - } } -/* - onDrawRegion:{ + onPaint:{ + canvas.paintingTime = new Date(); Tiger.draw(context, canvas.frame); } -Text { - anchors.top : parent.top - font.pixelSize : 30 - text: "drawing path:" + canvas.frame + "/" + Tiger.tiger.length; -} -*/ + Keys.onPressed : { + if (event.key == Qt.Key_Plus) { + canvas.contentsScale *= 1.5; + } + if (event.key == Qt.Key_Minus) { + canvas.contentsScale *= 0.7; + } + if (event.key == Qt.Key_Left) { + canvas.canvasX +=60; + } + if (event.key == Qt.Key_Right) { + canvas.canvasX -= 60; + } + if (event.key == Qt.Key_Up) { + canvas.canvasY += 40; + } + if (event.key == Qt.Key_Down) { + canvas.canvasY -= 40; + } + + canvas.requestPaint(); + } + Rectangle { + anchors.bottom : parent.bottom + color: "white" + opacity:0.7 + height:50 + width:canvas.width + radius:4 + Text { + anchors.bottom : parent.bottom + font.pixelSize : 30 + text: "drawing path:" + canvas.frame + "/" + Tiger.tiger.length + + " moving to:(" + canvas.canvasX + "," + canvas.canvasY + ")" + + " scale:" + canvas.contentsScale; + } + } + + MouseArea { + id:mouseArea + anchors.fill:parent + property real pressedX; + property real pressedY; + onPressed: { + pressedX = mouseX; + pressedY = mouseY; + } + onPositionChanged : { + canvas.canvasX = mouseX - pressedX; + canvas.canvasY = mouseY - pressedY; + canvas.requestPaint(); + } + } } diff --git a/src/declarative/items/qsgcanvasitem.cpp b/src/declarative/items/qsgcanvasitem.cpp index f346db4c66..0bd9a47d8d 100644 --- a/src/declarative/items/qsgcanvasitem.cpp +++ b/src/declarative/items/qsgcanvasitem.cpp @@ -58,6 +58,10 @@ public: QSGCanvasItemPrivate(); ~QSGCanvasItemPrivate(); QSGContext2D* context; + QList dirtyRegions; + QRect unitedDirtyRegion; + qreal canvasX; + qreal canvasY; }; @@ -67,6 +71,9 @@ public: QSGCanvasItemPrivate::QSGCanvasItemPrivate() : QSGPaintedItemPrivate() , context(0) + , unitedDirtyRegion() + , canvasX(0.) + , canvasY(0.) { } @@ -74,6 +81,40 @@ QSGCanvasItemPrivate::~QSGCanvasItemPrivate() { } + +void QSGCanvasItem::setCanvasX(qreal x) +{ + Q_D(QSGCanvasItem); + if (d->canvasX != x) { + d->canvasX = x; + emit canvasXChanged(); + } +} +void QSGCanvasItem::setCanvasY(qreal y) +{ + Q_D(QSGCanvasItem); + if (d->canvasY != y) { + d->canvasY = y; + emit canvasYChanged(); + } +} + +qreal QSGCanvasItem::canvasX() const +{ + Q_D(const QSGCanvasItem); + return d->canvasX; +} +qreal QSGCanvasItem::canvasY() const +{ + Q_D(const QSGCanvasItem); + return d->canvasY; +} +QPointF QSGCanvasItem::canvasPos() const +{ + Q_D(const QSGCanvasItem); + return QPointF(d->canvasX, d->canvasY); +} + /*! Constructs a QSGCanvasItem with the given \a parent item. */ @@ -92,11 +133,13 @@ QSGCanvasItem::~QSGCanvasItem() void QSGCanvasItem::paint(QPainter *painter) { Q_D(QSGCanvasItem); + if (d->context && d->context->isDirty()) { + painter->setWindow(-d->canvasX, -d->canvasY, d->width, d->height); + painter->setViewport(0, 0, d->width, d->height); + painter->scale(d->contentsScale, d->contentsScale); - if (d->context) { - emit drawRegion(getContext(), QRect(0, 0, width(), height())); d->context->paint(painter); - emit canvasUpdated(); + emit painted(); } } @@ -104,36 +147,59 @@ void QSGCanvasItem::componentComplete() { const QMetaObject *metaObject = this->metaObject(); int propertyCount = metaObject->propertyCount(); - int requestPaintMethod = metaObject->indexOfMethod("requestPaint()"); + int requestPaintMethod = metaObject->indexOfMethod("requestPaint(const QRect&)"); 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); } + + createContext(); + QSGPaintedItem::componentComplete(); } +void QSGCanvasItem::createContext() +{ + Q_D(QSGCanvasItem); + + delete d->context; + + d->context = new QSGContext2D(this); + + QV8Engine *e = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this)); + d->context->setV8Engine(e); +} QDeclarativeV8Handle QSGCanvasItem::getContext(const QString &contextId) { Q_D(QSGCanvasItem); + Q_UNUSED(contextId); - if (contextId == QLatin1String("2d")) { - if (!d->context) { - QV8Engine *e = QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this)); - d->context = new QSGContext2D(this); - d->context->setV8Engine(e); - connect(d->context, SIGNAL(changed()), this, SLOT(requestPaint())); - } - return QDeclarativeV8Handle::fromHandle(d->context->v8value()); - } + if (d->context) + return QDeclarativeV8Handle::fromHandle(d->context->v8value()); return QDeclarativeV8Handle::fromHandle(v8::Undefined()); } -void QSGCanvasItem::requestPaint() +void QSGCanvasItem::requestPaint(const QRect& r) { - //TODO:update(d->context->dirtyRect()); - update(); + Q_D(QSGCanvasItem); + + QRect region; + if (!r.isValid()) + region = QRect(d->canvasX, d->canvasY, d->width, d->height); + else + region = r; + + foreach (const QRect& rect, d->dirtyRegions) { + if (rect.contains(region)) + return; + } + + d->unitedDirtyRegion = d->unitedDirtyRegion.unite(region); + d->dirtyRegions.append(region); + polish(); + update(d->unitedDirtyRegion); } bool QSGCanvasItem::save(const QString &filename) const @@ -147,6 +213,26 @@ bool QSGCanvasItem::save(const QString &filename) const return false; } +void QSGCanvasItem::updatePolish() +{ + Q_D(QSGCanvasItem); + QDeclarativeV8Handle context = QDeclarativeV8Handle::fromHandle(d->context->v8value()); + + d->context->setValid(true); + + // d->context->setTileRect(QRectF(d->canvasX, d->canvasY, d->width, d->height).intersected(QRectF(0, 0, d->width, d->height))); + // d->context->setTileRect(QRectF(d->canvasX, d->canvasY, d->width, d->height)); + + foreach (const QRect& region, d->dirtyRegions) { + emit paint(context, region); + } + d->dirtyRegions.clear(); + + d->context->setValid(false); + + QSGPaintedItem::updatePolish(); +} + QString QSGCanvasItem::toDataURL(const QString& mimeType) const { Q_D(const QSGCanvasItem); @@ -182,5 +268,4 @@ QString QSGCanvasItem::toDataURL(const QString& mimeType) const } return QLatin1String("data:,"); } - QT_END_NAMESPACE diff --git a/src/declarative/items/qsgcanvasitem_p.h b/src/declarative/items/qsgcanvasitem_p.h index 71358c4d9e..9a6ccc27ed 100644 --- a/src/declarative/items/qsgcanvasitem_p.h +++ b/src/declarative/items/qsgcanvasitem_p.h @@ -61,26 +61,36 @@ class QSGCanvasItemPrivate; class QSGCanvasItem : public QSGPaintedItem { Q_OBJECT + Q_PROPERTY(QPointF canvasPos READ canvasPos FINAL) + Q_PROPERTY(qreal canvasX READ canvasX WRITE setCanvasX NOTIFY canvasXChanged FINAL) + Q_PROPERTY(qreal canvasY READ canvasY WRITE setCanvasY NOTIFY canvasYChanged FINAL) public: QSGCanvasItem(QSGItem *parent = 0); ~QSGCanvasItem(); - + void setCanvasX(qreal x); + void setCanvasY(qreal y); + qreal canvasX() const; + qreal canvasY() const; + QPointF canvasPos() const; Q_SIGNALS: - void canvasUpdated(); - void drawRegion(QDeclarativeV8Handle context, const QRect ®ion); - + void painted(); + void paint(QDeclarativeV8Handle context, const QRect ®ion); + void canvasXChanged(); + void canvasYChanged(); public Q_SLOTS: QString toDataURL(const QString& type = QLatin1String("image/png")) const; QDeclarativeV8Handle getContext(const QString & = QLatin1String("2d")); - void requestPaint(); + void requestPaint(const QRect& region = QRect()); // Save current canvas to disk bool save(const QString& filename) const; protected: + void updatePolish(); void paint(QPainter *painter); virtual void componentComplete(); private: + void createContext(); Q_DECLARE_PRIVATE(QSGCanvasItem) friend class QSGContext2D; }; diff --git a/src/declarative/items/qsgcontext2d.cpp b/src/declarative/items/qsgcontext2d.cpp index f3371ed982..6f3b117661 100644 --- a/src/declarative/items/qsgcontext2d.cpp +++ b/src/declarative/items/qsgcontext2d.cpp @@ -82,10 +82,20 @@ void copy_vector(QVector* dst, const QVector& src) // But it really should be considered private API void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0); void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); - +static bool parsePathDataFast(const QString &dataStr, QPainterPath &path); #define DEGREES(t) ((t) * 180.0 / Q_PI) #define qClamp(val, min, max) qMin(qMax(val, min), max) +#define CHECK_CONTEXT(r) if (!r || !r->context) \ + V8THROW_ERROR("Not a Context2D object"); \ + if (!r->context->valid()) \ + V8THROW_ERROR("Context2D object is out of scope, please only access context2d APIs from onPaint method."); + +#define CHECK_CONTEXT_SETTER(r) if (!r || !r->context) \ + V8THROW_ERROR_SETTER("Not a Context2D object"); \ + if (!r->context->valid()) \ + V8THROW_ERROR_SETTER("Context2D object is out of scope, please only access context2d APIs from onPaint method."); + static inline int extractInt(const char **name) { int result = 0; @@ -380,8 +390,8 @@ public: static v8::Handle ctx2d_sync(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + r->context->sync(); @@ -392,8 +402,8 @@ static v8::Handle ctx2d_sync(const v8::Arguments &args) static v8::Handle ctx2d_canvas(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -404,8 +414,8 @@ static v8::Handle ctx2d_canvas(v8::Local, const v8::Acces static v8::Handle ctx2d_restore(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + r->context->restore(); @@ -415,8 +425,8 @@ static v8::Handle ctx2d_restore(const v8::Arguments &args) static v8::Handle ctx2d_reset(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + r->context->reset(); @@ -426,8 +436,8 @@ static v8::Handle ctx2d_reset(const v8::Arguments &args) static v8::Handle ctx2d_save(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + r->context->save(); @@ -438,8 +448,8 @@ static v8::Handle ctx2d_save(const v8::Arguments &args) static v8::Handle ctx2d_rotate(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 1) r->context->rotate(args[0]->NumberValue()); @@ -450,8 +460,8 @@ static v8::Handle ctx2d_rotate(const v8::Arguments &args) static v8::Handle ctx2d_scale(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 2) r->context->scale(args[0]->NumberValue(), args[1]->NumberValue()); @@ -462,8 +472,8 @@ static v8::Handle ctx2d_scale(const v8::Arguments &args) static v8::Handle ctx2d_setTransform(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 6) { r->context->setTransform(args[0]->NumberValue(), @@ -480,8 +490,8 @@ static v8::Handle ctx2d_setTransform(const v8::Arguments &args) static v8::Handle ctx2d_transform(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 6) { r->context->transform(args[0]->NumberValue(), @@ -498,8 +508,8 @@ static v8::Handle ctx2d_transform(const v8::Arguments &args) static v8::Handle ctx2d_translate(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 2) { r->context->translate(args[0]->NumberValue(), @@ -514,8 +524,8 @@ static v8::Handle ctx2d_translate(const v8::Arguments &args) static v8::Handle ctx2d_globalAlpha(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + return v8::Number::New(r->context->globalAlpha()); } @@ -523,18 +533,30 @@ static v8::Handle ctx2d_globalAlpha(v8::Local, const v8:: static void ctx2d_globalAlpha_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) r->context->setGlobalAlpha(value->NumberValue()); } +// read only property to indicate the validation of the context object +static v8::Handle ctx2d_valid(v8::Local, const v8::AccessorInfo &info) +{ + QV8Context2DResource *r = v8_resource_cast(info.This()); + CHECK_CONTEXT(r) + + + QV8Engine *engine = V8ENGINE_ACCESSOR(); + + return v8::Boolean::New(r->context->valid()); +} + + // string getter/setter default "source-over" static v8::Handle ctx2d_globalCompositeOperation(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -544,8 +566,7 @@ static v8::Handle ctx2d_globalCompositeOperation(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -557,8 +578,8 @@ static void ctx2d_globalCompositeOperation_set(v8::Local, v8::Local< static v8::Handle ctx2d_fillStyle(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -568,8 +589,7 @@ static v8::Handle ctx2d_fillStyle(v8::Local, const v8::Ac static void ctx2d_fillStyle_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -581,8 +601,8 @@ static void ctx2d_fillStyle_set(v8::Local, v8::Local valu static v8::Handle ctx2d_fillColor(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -592,8 +612,7 @@ static v8::Handle ctx2d_fillColor(v8::Local, const v8::Ac static void ctx2d_fillColor_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -604,8 +623,8 @@ static void ctx2d_fillColor_set(v8::Local, v8::Local valu v8::Handle ctx2d_strokeStyle(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -615,8 +634,7 @@ v8::Handle ctx2d_strokeStyle(v8::Local, const v8::Accesso static void ctx2d_strokeStyle_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -628,8 +646,8 @@ static void ctx2d_strokeStyle_set(v8::Local, v8::Local va v8::Handle ctx2d_strokeColor(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -639,8 +657,7 @@ v8::Handle ctx2d_strokeColor(v8::Local, const v8::Accesso static void ctx2d_strokeColor_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -650,8 +667,8 @@ static void ctx2d_strokeColor_set(v8::Local, v8::Local va static v8::Handle ctx2d_createLinearGradient(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE(); @@ -669,8 +686,8 @@ static v8::Handle ctx2d_createLinearGradient(const v8::Arguments &arg static v8::Handle ctx2d_createRadialGradient(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE(); @@ -698,8 +715,8 @@ static v8::Handle ctx2d_createPattern(const v8::Arguments &args) v8::Handle ctx2d_lineCap(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -709,8 +726,7 @@ v8::Handle ctx2d_lineCap(v8::Local, const v8::AccessorInf static void ctx2d_lineCap_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -721,8 +737,8 @@ static void ctx2d_lineCap_set(v8::Local, v8::Local value, v8::Handle ctx2d_lineJoin(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -732,8 +748,7 @@ v8::Handle ctx2d_lineJoin(v8::Local, const v8::AccessorIn static void ctx2d_lineJoin_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -744,8 +759,8 @@ static void ctx2d_lineJoin_set(v8::Local, v8::Local value v8::Handle ctx2d_lineWidth(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + return v8::Number::New(r->context->lineWidth()); } @@ -753,8 +768,7 @@ v8::Handle ctx2d_lineWidth(v8::Local, const v8::AccessorI static void ctx2d_lineWidth_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) r->context->setLineWidth(value->NumberValue()); } @@ -763,8 +777,8 @@ static void ctx2d_lineWidth_set(v8::Local, v8::Local valu v8::Handle ctx2d_miterLimit(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + return v8::Number::New(r->context->miterLimit()); } @@ -772,8 +786,7 @@ v8::Handle ctx2d_miterLimit(v8::Local, const v8::Accessor static void ctx2d_miterLimit_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) r->context->setMiterLimit(value->NumberValue()); } @@ -783,8 +796,8 @@ static void ctx2d_miterLimit_set(v8::Local, v8::Local val v8::Handle ctx2d_shadowBlur(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + return v8::Number::New(r->context->shadowBlur()); } @@ -792,8 +805,7 @@ v8::Handle ctx2d_shadowBlur(v8::Local, const v8::Accessor static void ctx2d_shadowBlur_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) r->context->setShadowBlur(value->NumberValue()); } @@ -801,8 +813,8 @@ static void ctx2d_shadowBlur_set(v8::Local, v8::Local val v8::Handle ctx2d_shadowColor(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -812,8 +824,7 @@ v8::Handle ctx2d_shadowColor(v8::Local, const v8::Accesso static void ctx2d_shadowColor_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) QV8Engine *engine = V8ENGINE_ACCESSOR(); @@ -823,8 +834,8 @@ static void ctx2d_shadowColor_set(v8::Local, v8::Local va v8::Handle ctx2d_shadowOffsetX(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + return v8::Number::New(r->context->shadowOffsetX()); } @@ -832,8 +843,7 @@ v8::Handle ctx2d_shadowOffsetX(v8::Local, const v8::Acces static void ctx2d_shadowOffsetX_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) r->context->setShadowOffsetX(value->NumberValue()); } @@ -841,8 +851,8 @@ static void ctx2d_shadowOffsetX_set(v8::Local, v8::Local v8::Handle ctx2d_shadowOffsetY(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + return v8::Number::New(r->context->shadowOffsetY()); } @@ -850,8 +860,7 @@ v8::Handle ctx2d_shadowOffsetY(v8::Local, const v8::Acces static void ctx2d_shadowOffsetY_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) r->context->setShadowOffsetY(value->NumberValue()); } @@ -860,8 +869,8 @@ static void ctx2d_shadowOffsetY_set(v8::Local, v8::Local static v8::Handle ctx2d_clearRect(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 4) { r->context->clearRect(args[0]->NumberValue(), @@ -876,8 +885,8 @@ static v8::Handle ctx2d_clearRect(const v8::Arguments &args) static v8::Handle ctx2d_fillRect(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 4) { r->context->fillRect(args[0]->NumberValue(), @@ -892,8 +901,8 @@ static v8::Handle ctx2d_fillRect(const v8::Arguments &args) static v8::Handle ctx2d_strokeRect(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 4) { r->context->strokeRect(args[0]->NumberValue(), @@ -909,8 +918,8 @@ static v8::Handle ctx2d_strokeRect(const v8::Arguments &args) static v8::Handle ctx2d_arc(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 6) { r->context->arc(args[0]->NumberValue(), @@ -927,8 +936,8 @@ static v8::Handle ctx2d_arc(const v8::Arguments &args) static v8::Handle ctx2d_arcTo(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 5) { r->context->arcTo(args[0]->NumberValue(), @@ -944,8 +953,8 @@ static v8::Handle ctx2d_arcTo(const v8::Arguments &args) static v8::Handle ctx2d_beginPath(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + r->context->beginPath(); @@ -955,8 +964,8 @@ static v8::Handle ctx2d_beginPath(const v8::Arguments &args) static v8::Handle ctx2d_bezierCurveTo(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 5) { r->context->bezierCurveTo(args[0]->NumberValue(), @@ -973,8 +982,8 @@ static v8::Handle ctx2d_bezierCurveTo(const v8::Arguments &args) static v8::Handle ctx2d_clip(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + r->context->clip(); @@ -984,8 +993,8 @@ static v8::Handle ctx2d_clip(const v8::Arguments &args) static v8::Handle ctx2d_closePath(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + r->context->closePath(); @@ -995,8 +1004,8 @@ static v8::Handle ctx2d_closePath(const v8::Arguments &args) static v8::Handle ctx2d_fill(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + r->context->fill(); @@ -1006,8 +1015,8 @@ static v8::Handle ctx2d_fill(const v8::Arguments &args) static v8::Handle ctx2d_lineTo(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 2) { r->context->lineTo(args[0]->NumberValue(), @@ -1020,8 +1029,8 @@ static v8::Handle ctx2d_lineTo(const v8::Arguments &args) static v8::Handle ctx2d_moveTo(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 2) { r->context->moveTo(args[0]->NumberValue(), @@ -1034,8 +1043,8 @@ static v8::Handle ctx2d_moveTo(const v8::Arguments &args) static v8::Handle ctx2d_quadraticCurveTo(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 4) { r->context->quadraticCurveTo(args[0]->NumberValue(), @@ -1050,8 +1059,8 @@ static v8::Handle ctx2d_quadraticCurveTo(const v8::Arguments &args) static v8::Handle ctx2d_rect(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + if (args.Length() == 4) { r->context->rect(args[0]->NumberValue(), @@ -1066,8 +1075,8 @@ static v8::Handle ctx2d_rect(const v8::Arguments &args) static v8::Handle ctx2d_stroke(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + r->context->stroke(); @@ -1077,8 +1086,8 @@ static v8::Handle ctx2d_stroke(const v8::Arguments &args) static v8::Handle ctx2d_isPointInPath(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + bool pointInPath = false; if (args.Length() == 2) { @@ -1092,8 +1101,8 @@ static v8::Handle ctx2d_isPointInPath(const v8::Arguments &args) static v8::Handle ctx2d_setPathString(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE(); if (args.Length() == 1) { @@ -1102,12 +1111,48 @@ static v8::Handle ctx2d_setPathString(const v8::Arguments &args) return v8::Undefined(); } +static v8::Handle ctx2d_path(v8::Local, const v8::AccessorInfo &info) +{ +// QV8Context2DResource *r = v8_resource_cast(info.This()); +// CHECK_CONTEXT(r) + +// QV8Engine *engine = V8ENGINE(); + + return v8::Undefined(); +} + +static v8::Handle ctx2d_path_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) +{ +// QV8Context2DResource *r = v8_resource_cast(args.This()); +// CHECK_CONTEXT(r) + + +// QV8Engine *engine = V8ENGINE(); +// if (args.Length() == 1) { +// r->context->setPathString(engine->toString(args[0])); +// } + return v8::Undefined(); +} + +static v8::Handle ctx2d_createPath(const v8::Arguments &args) +{ +// QV8Context2DResource *r = v8_resource_cast(args.This()); +// CHECK_CONTEXT(r) + + +// QV8Engine *engine = V8ENGINE(); +// if (args.Length() == 1) { +// r->context->setPathString(engine->toString(args[0])); +// } + return v8::Undefined(); +} + // text v8::Handle ctx2d_font(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + return v8::Undefined(); } @@ -1115,8 +1160,7 @@ v8::Handle ctx2d_font(v8::Local, const v8::AccessorInfo & static void ctx2d_font_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) Q_UNUSED(value); } @@ -1124,8 +1168,8 @@ static void ctx2d_font_set(v8::Local, v8::Local value, co v8::Handle ctx2d_textAlign(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + return v8::Undefined(); } @@ -1133,8 +1177,7 @@ v8::Handle ctx2d_textAlign(v8::Local, const v8::AccessorI static void ctx2d_textAlign_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) Q_UNUSED(value); } @@ -1142,8 +1185,8 @@ static void ctx2d_textAlign_set(v8::Local, v8::Local valu v8::Handle ctx2d_textBaseline(v8::Local, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + return v8::Undefined(); } @@ -1151,8 +1194,7 @@ v8::Handle ctx2d_textBaseline(v8::Local, const v8::Access static void ctx2d_textBaseline_set(v8::Local, v8::Local value, const v8::AccessorInfo &info) { QV8Context2DResource *r = v8_resource_cast(info.This()); - if (!r || !r->context) - V8THROW_ERROR_SETTER("Not a Context2D object"); + CHECK_CONTEXT_SETTER(r) Q_UNUSED(value); } @@ -1160,8 +1202,8 @@ static void ctx2d_textBaseline_set(v8::Local, v8::Local v static v8::Handle ctx2d_fillText(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE(); @@ -1177,8 +1219,8 @@ static v8::Handle ctx2d_fillText(const v8::Arguments &args) static v8::Handle ctx2d_strokeText(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE(); @@ -1195,8 +1237,8 @@ static v8::Handle ctx2d_strokeText(const v8::Arguments &args) static v8::Handle ctx2d_drawImage(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - if (!r || !r->context) - V8THROW_ERROR("Not a Context2D object"); + CHECK_CONTEXT(r) + QV8Engine *engine = V8ENGINE(); @@ -1509,20 +1551,38 @@ void QSGContext2DPrivate::clearRect(qreal x, qreal y, void QSGContext2DPrivate::fillRect(qreal x, qreal y, qreal w, qreal h) { - commands.push_back(QSGContext2D::FillRect); - reals.push_back(x); - reals.push_back(y); - reals.push_back(w); - reals.push_back(h); + QRectF rect; + if (tileRect.isValid()) { + rect = tileRect.intersect(QRect(x, y, w, h)); + } else { + rect = QRectF(x, y, w, h); + } + + if (rect.isValid()) { + commands.push_back(QSGContext2D::FillRect); + reals.push_back(rect.x()); + reals.push_back(rect.y()); + reals.push_back(rect.width()); + reals.push_back(rect.height()); + } } void QSGContext2DPrivate::strokeRect(qreal x, qreal y, qreal w, qreal h) { - QPainterPath path; - path.addRect(x, y, w, h); - commands.push_back(QSGContext2D::Stroke); - pathes.push_back(path); + QPainterPath p; + p.addRect(x, y, w, h); + + if (tileRect.isValid()) { + QPainterPath tr; + tr.addRect(tileRect); + p = p.intersected(tr); + } + + if (!p.isEmpty()) { + commands.push_back(QSGContext2D::Stroke); + pathes.push_back(p); + } } void QSGContext2DPrivate::beginPath() @@ -1633,21 +1693,39 @@ void QSGContext2DPrivate::arc(qreal xc, void QSGContext2DPrivate::fill() { - commands.push_back(QSGContext2D::Fill); - pathes.push_back(path); + QPainterPath tr; + if (tileRect.isValid()) { + tr.addRect(tileRect); + tr = tr.intersected(path); + } else { + tr = path; + } + + if (!tr.isEmpty()) { + commands.push_back(QSGContext2D::Fill); + pathes.push_back(tr); + } } void QSGContext2DPrivate::stroke() { - commands.push_back(QSGContext2D::Stroke); - pathes.push_back(path); -// painter->setMatrix(state.matrix, false); -// QPainterPath tmp = state.matrix.inverted().map(path); //why? -// painter->strokePath(tmp, painter->pen()); + QPainterPath tr; + if (tileRect.isValid()) { + tr.addRect(tileRect); + tr = tr.intersected(path); + } else { + tr = path; + } + + if (!tr.isEmpty()) { + commands.push_back(QSGContext2D::Stroke); + pathes.push_back(tr); + } } void QSGContext2DPrivate::clip() { + //TODO:XXX state.clipPath = path; pathes.push_back(state.clipPath); commands.push_back(QSGContext2D::Clip); @@ -2214,6 +2292,26 @@ void QSGContext2D::setShadowColor(const QString &str) d->setShadowColor(str); } +QSGCanvasPath* QSGContext2D::path() +{ + Q_D(const QSGContext2D); + return new QSGCanvasPath(d->path, this); +} +void QSGContext2D::setPath(QSGCanvasPath* path) +{ + Q_D(QSGContext2D); + d->path = path->m_path; +} + +QSGCanvasPath* QSGContext2D::createPath(const QString& pathString) +{ + QPainterPath path; + if (parsePathDataFast(pathString, path)) { + return new QSGCanvasPath(path, this); + } + return 0; +} + QString QSGContext2D::textBaseline() const { Q_D(const QSGContext2D); @@ -3140,6 +3238,7 @@ QSGContext2DEngineData::QSGContext2DEngineData(QV8Engine *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("valid"), ctx2d_valid, 0, v8::External::Wrap(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)); @@ -3195,8 +3294,17 @@ QSGContext2DEngineData::~QSGContext2DEngineData() V8_DEFINE_EXTENSION(QSGContext2DEngineData, engineData); +QV8Engine* QSGContext2D::v8Engine() const +{ + Q_D(const QSGContext2D); + return d->v8engine; +} + void QSGContext2D::setV8Engine(QV8Engine *engine) { + v8::HandleScope handle_scope; + v8::Context::Scope scope(engine->context()); + Q_D(QSGContext2D); if (d->v8engine != engine) { d->v8engine = engine; @@ -3214,6 +3322,23 @@ void QSGContext2D::setV8Engine(QV8Engine *engine) } } +bool QSGContext2D::valid() const +{ + Q_D(const QSGContext2D); + return d->valid; +} + +void QSGContext2D::setValid(bool valid) +{ + Q_D(QSGContext2D); + d->valid = valid; +} +void QSGContext2D::setTileRect(const QRectF& rect) +{ + Q_D(QSGContext2D); + if (d->tileRect != rect) + d->tileRect = rect; +} void QSGContext2D::addref() { Q_D(QSGContext2D); @@ -3538,7 +3663,7 @@ void QSGContext2D::paint(QPainter* p) { Q_D(QSGContext2D); - QTransform transform = p->worldTransform(); + QMatrix originMatrix = p->matrix(); if (!d->commands.isEmpty()) { int matrix_idx, real_idx, int_idx, variant_idx, string_idx,color_idx,cmd_idx, pen_idx, brush_idx, font_idx, path_idx, image_idx, size_idx; @@ -3551,7 +3676,7 @@ void QSGContext2D::paint(QPainter* p) case UpdateMatrix: { d->state.matrix = d->matrixes[matrix_idx++]; - p->setMatrix(d->state.matrix); + p->setMatrix(d->state.matrix * originMatrix); break; } case ClearRect: diff --git a/src/declarative/items/qsgcontext2d_p.h b/src/declarative/items/qsgcontext2d_p.h index 924c4bf780..335d954fc1 100644 --- a/src/declarative/items/qsgcontext2d_p.h +++ b/src/declarative/items/qsgcontext2d_p.h @@ -86,6 +86,16 @@ public: Q_DECLARE_METATYPE(QSGCanvasGradient*) +class QSGCanvasPath : QObject +{ + Q_OBJECT +public: + QSGCanvasPath(const QPainterPath& path, QObject* parent = 0) : QObject(parent), m_path(path) {} + + QPainterPath m_path; +}; +Q_DECLARE_METATYPE(QSGCanvasPath*) + class QSGContext2DWorkerAgent; class QSGContext2DPrivate; class QSGCanvasItem; @@ -113,6 +123,8 @@ class QSGContext2D : public QObject Q_PROPERTY(QString font READ font WRITE setFont) Q_PROPERTY(QString textBaseline READ textBaseline WRITE setTextBaseline) Q_PROPERTY(QString textAlign READ textAlign WRITE setTextAlign) + + Q_PROPERTY(QSGCanvasPath* path READ path WRITE setPath) Q_ENUMS(PaintCommand) public: enum TextBaseLineType { Alphabetic=0, Top, Middle, Bottom, Hanging}; @@ -245,6 +257,8 @@ public: void setShadowBlur(qreal b); void setShadowColor(const QString &str); + QSGCanvasPath* path(); + void setPath(QSGCanvasPath* path); public slots: void save(); // push state on state stack void restore(); // pop state stack and restore state @@ -295,6 +309,7 @@ public slots: //implement the W3C SVG path spec: //http://www.w3.org/TR/SVG/paths.html void setPathString(const QString& path); + QSGCanvasPath* createPath(const QString& pathString); QSGImage *createImage(const QString &url); @@ -315,8 +330,12 @@ signals: public: bool isDirty() const; v8::Handle v8value() const; + QV8Engine* v8Engine() const; void setV8Engine(QV8Engine *eng); + bool valid() const; + void setValid(bool valid); + void setTileRect(const QRectF& region); void addref(); void release(); diff --git a/src/declarative/items/qsgcontext2d_p_p.h b/src/declarative/items/qsgcontext2d_p_p.h index 4fcf40406e..ed73b2fbd2 100644 --- a/src/declarative/items/qsgcontext2d_p_p.h +++ b/src/declarative/items/qsgcontext2d_p_p.h @@ -82,6 +82,7 @@ public: , cachedImage(1,1, QImage::Format_ARGB32) , canvas(0) , waitingForPainting(false) + , valid(false) { } ~QSGContext2DPrivate() @@ -180,6 +181,7 @@ public: void clearCommands() { + qDebug() << "painting commands:" << commands.size(); commands.remove(0, commands.size()); variants.remove(0, variants.size()); pens.remove(0, pens.size()); @@ -227,6 +229,8 @@ public: QImage cachedImage; QSGCanvasItem* canvas; bool waitingForPainting; + bool valid; + QRectF tileRect; }; QT_END_NAMESPACE -- cgit v1.2.3