Merge branch 'refactor'
authorGunnar Sletta <gunnar.sletta@nokia.com>
Tue, 13 Sep 2011 08:21:53 +0000 (10:21 +0200)
committerGunnar Sletta <gunnar.sletta@nokia.com>
Tue, 13 Sep 2011 08:22:22 +0000 (10:22 +0200)
Conflicts:
src/declarative/items/context2d/qsgcanvasitem.cpp
src/declarative/items/context2d/qsgcontext2d.cpp
src/declarative/items/context2d/qsgcontext2d_p_p.h
src/declarative/particles/qsgcustomparticle.cpp
src/declarative/particles/qsgparticlesystem.cpp

Change-Id: I24e81d3652368c5031305ffa7f969f9f2c249c6c

1  2 
src/declarative/items/context2d/qsgcontext2d.cpp
src/declarative/items/qsgflickable.cpp
src/declarative/items/qsgitemsmodule.cpp
src/declarative/items/qsgspriteengine.cpp
src/declarative/items/qsgspriteimage.cpp
src/declarative/particles/qsgcustomparticle.cpp
src/declarative/particles/qsgimageparticle.cpp
src/declarative/particles/qsgimageparticle_p.h
tests/auto/declarative/qsgtextinput/tst_qsgtextinput.cpp

  ****************************************************************************/
  
  #include "qsgcontext2d_p.h"
 -#include "qsgcontext2d_p_p.h"
 -#include "private/qsgadaptationlayer_p.h"
 +#include "qsgcontext2dcommandbuffer_p.h"
  #include "qsgcanvasitem_p.h"
 +#include "qsgitem_p.h"
 +#include "qsgshadereffectsource_p.h"
+ #include <QtGui/qopenglframebufferobject.h>
 +
  #include <QtCore/qdebug.h>
  #include "private/qsgcontext_p.h"
  #include "private/qdeclarativesvgparser_p.h"
 +#include "private/qdeclarativepath_p.h"
 +
 +#include "private/qsgimage_p_p.h"
  
+ #include <QtGui/qguiapplication.h>
  #include <qdeclarativeinfo.h>
  #include <QtCore/qmath.h>
 -#include "qdeclarativepixmapcache_p.h"
 -
 -#include <private/qv8engine_p.h>
 -#include "qvarlengtharray.h"
 +#include "qv8engine_p.h"
  
 +#include <QtOpenGL/QGLFramebufferObjectFormat>
 +#include <QtOpenGL/QGLFramebufferObject>
 +#include "qdeclarativeengine.h"
  QT_BEGIN_NAMESPACE
 -
 +/*!
 +    \qmlclass Context2D QSGContext2D
 +    \inqmlmodule QtQuick 2
 +    \since QtQuick 2.0
 +    \brief The Context2D element allows you to draw 2d graphic shapes on Canvas item.
 +*/
  static const double Q_PI   = 3.14159265358979323846;   // pi
 -template <class T>
 -void memcpy_vector(QVector<T>* dst, const QVector<T>& src)
 -{
 -    int pos = dst->size();
 -    dst->resize(pos + src.size());
 -    memmove(dst->data() + pos, src.constData(), sizeof(T) * src.size());
 -}
  
 -template <class T>
 -void copy_vector(QVector<T>* dst, const QVector<T>& src)
 -{
 -    int pos = dst->size();
 -    dst->resize(pos + src.size());
 -    for (int i = 0; i < src.size(); i++) {
 -        (*dst)[pos + i] = src[i];
 -    }
 -}
  
+ 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(r)     if (!r || !r->context || !r->context->buffer()) \
 +                                V8THROW_ERROR("Not a Context2D object");
  
 -#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.");
 +#define CHECK_CONTEXT_SETTER(r)     if (!r || !r->context || !r->context->buffer()) \
 +                                       V8THROW_ERROR_SETTER("Not a Context2D object");
  
  static inline int extractInt(const char **name)
  {
@@@ -256,7 -270,7 +260,7 @@@ static bool qt_get_hsl(const QString &s
  }
  
  //### optimize further
 -QColor colorFromString(const QString &name)
 +QColor qt_color_from_string(const QString &name)
  {
      if (name.startsWith(QLatin1String("rgb"))) {
          QRgb rgb;
      return QColor(name);
  }
  
 +QFont qt_font_from_string(const QString& fontString) {
 +    QFont font;
 +     // ### this is simplified and incomplete
 +    // ### TODO:get code from Qt webkit
 +     QStringList tokens = fontString.split(QLatin1String(" "));
 +     foreach (const QString &token, tokens) {
 +         if (token == QLatin1String("italic"))
 +             font.setItalic(true);
 +         else if (token == QLatin1String("bold"))
 +             font.setBold(true);
 +         else if (token.endsWith(QLatin1String("px"))) {
 +             QString number = token;
 +             number.remove(QLatin1String("px"));
 +             //font.setPointSizeF(number.trimmed().toFloat());
 +             font.setPixelSize(number.trimmed().toInt());
 +         } else
 +             font.setFamily(token);
 +     }
 +
 +     return font;
 +}
 +
 +
 +
 +class QSGContext2DEngineData : public QV8Engine::Deletable
 +{
 +public:
 +    QSGContext2DEngineData(QV8Engine *engine);
 +    ~QSGContext2DEngineData();
 +
 +    v8::Persistent<v8::Function> constructorContext;
 +    v8::Persistent<v8::Function> constructorGradient;
 +    v8::Persistent<v8::Function> constructorPattern;
 +    v8::Persistent<v8::Function> constructorPixelArray;
 +    v8::Persistent<v8::Function> constructorImageData;
 +};
 +V8_DEFINE_EXTENSION(QSGContext2DEngineData, engineData);
 +
 +
 +
 +class QV8Context2DResource : public QV8ObjectResource
 +{
 +    V8_RESOURCE_TYPE(Context2DType)
 +public:
 +    QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
 +    QSGContext2D* context;
 +};
 +
 +class QV8Context2DStyleResource : public QV8ObjectResource
 +{
 +    V8_RESOURCE_TYPE(Context2DStyleType)
 +public:
 +    QV8Context2DStyleResource(QV8Engine *e) : QV8ObjectResource(e) {}
 +    QBrush brush;
 +};
 +
 +class QV8Context2DPixelArrayResource : public QV8ObjectResource
 +{
 +    V8_RESOURCE_TYPE(Context2DPixelArrayType)
 +public:
 +    QV8Context2DPixelArrayResource(QV8Engine *e) : QV8ObjectResource(e) {}
 +
 +    QImage image;
 +};
 +
 +static QImage qt_texture_to_image(QSGTexture* texture)
 +{
 +    if (!texture || !texture->textureId())
 +        return QImage();
 +    QGLFramebufferObjectFormat format;
 +    format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
 +    format.setInternalTextureFormat(GL_RGBA);
 +    format.setMipmap(false);
 +    QGLFramebufferObject* fbo = new QGLFramebufferObject(texture->textureSize(), format);
 +    fbo->drawTexture(QPointF(0,0), texture->textureId(), GL_TEXTURE_2D);
 +    return fbo->toImage();
 +}
 +
 +static QSGTexture* qt_item_to_texture(QSGItem* item)
 +{
 +    if (!item)
 +        return 0;
 +    QSGShaderEffectTexture* texture = new QSGShaderEffectTexture(item);
 +    texture->setItem(QSGItemPrivate::get(item)->itemNode());
 +    texture->setLive(true);
 +
 +    QRectF sourceRect = QRectF(0, 0, item->width(), item->height());
 +
 +    texture->setRect(sourceRect);
 +    QSize textureSize = QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height())));
 +    texture->setSize(textureSize);
 +    texture->setRecursive(false);
 +    texture->setFormat(GL_RGBA);
 +    texture->setHasMipmaps(false);
 +    texture->markDirtyTexture();
 +    texture->updateTexture();
 +    return texture;
 +}
 +
 +static QImage qt_item_to_image(QSGItem* item) {
 +    return qt_texture_to_image(qt_item_to_texture(item));
 +}
  
 -static QPainter::CompositionMode compositeOperatorFromString(const QString &compositeOperator)
 +static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
  {
      if (compositeOperator == QLatin1String("source-over")) {
          return QPainter::CompositionMode_SourceOver;
          return QPainter::CompositionMode_DestinationOut;
      } else if (compositeOperator == QLatin1String("destination-over")) {
          return QPainter::CompositionMode_DestinationOver;
 -    } else if (compositeOperator == QLatin1String("darker")) {
 -        return QPainter::CompositionMode_SourceOver;
      } else if (compositeOperator == QLatin1String("lighter")) {
 -        return QPainter::CompositionMode_SourceOver;
 +        return QPainter::CompositionMode_Plus;
      } else if (compositeOperator == QLatin1String("copy")) {
          return QPainter::CompositionMode_Source;
      } else if (compositeOperator == QLatin1String("xor")) {
          return QPainter::CompositionMode_Xor;
 +    } else if (compositeOperator == QLatin1String("qt-clear")) {
 +        return QPainter::CompositionMode_Clear;
 +    } else if (compositeOperator == QLatin1String("qt-destination")) {
 +        return QPainter::CompositionMode_Destination;
 +    } else if (compositeOperator == QLatin1String("qt-multiply")) {
 +        return QPainter::CompositionMode_Multiply;
 +    } else if (compositeOperator == QLatin1String("qt-screen")) {
 +        return QPainter::CompositionMode_Screen;
 +    } else if (compositeOperator == QLatin1String("qt-overlay")) {
 +        return QPainter::CompositionMode_Overlay;
 +    } else if (compositeOperator == QLatin1String("qt-darken")) {
 +        return QPainter::CompositionMode_Darken;
 +    } else if (compositeOperator == QLatin1String("qt-lighten")) {
 +        return QPainter::CompositionMode_Lighten;
 +    } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
 +        return QPainter::CompositionMode_ColorDodge;
 +    } else if (compositeOperator == QLatin1String("qt-color-burn")) {
 +        return QPainter::CompositionMode_ColorBurn;
 +    } else if (compositeOperator == QLatin1String("qt-hard-light")) {
 +        return QPainter::CompositionMode_HardLight;
 +    } else if (compositeOperator == QLatin1String("qt-soft-light")) {
 +        return QPainter::CompositionMode_SoftLight;
 +    } else if (compositeOperator == QLatin1String("qt-difference")) {
 +        return QPainter::CompositionMode_Difference;
 +    } else if (compositeOperator == QLatin1String("qt-exclusion")) {
 +        return QPainter::CompositionMode_Exclusion;
      }
 -
      return QPainter::CompositionMode_SourceOver;
  }
  
 -static QString compositeOperatorToString(QPainter::CompositionMode op)
 +static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
  {
      switch (op) {
      case QPainter::CompositionMode_SourceOver:
      case QPainter::CompositionMode_DestinationOver:
          return QLatin1String("destination-over");
      case QPainter::CompositionMode_Clear:
 -        return QLatin1String("clear");
 +        return QLatin1String("qt-clear");
      case QPainter::CompositionMode_Source:
 -        return QLatin1String("source");
 +        return QLatin1String("copy");
      case QPainter::CompositionMode_Destination:
 -        return QLatin1String("destination");
 +        return QLatin1String("qt-destination");
      case QPainter::CompositionMode_SourceIn:
          return QLatin1String("source-in");
      case QPainter::CompositionMode_DestinationIn:
      case QPainter::CompositionMode_Xor:
          return QLatin1String("xor");
      case QPainter::CompositionMode_Plus:
 -        return QLatin1String("plus");
 +        return QLatin1String("lighter");
      case QPainter::CompositionMode_Multiply:
 -        return QLatin1String("multiply");
 +        return QLatin1String("qt-multiply");
      case QPainter::CompositionMode_Screen:
 -        return QLatin1String("screen");
 +        return QLatin1String("qt-screen");
      case QPainter::CompositionMode_Overlay:
 -        return QLatin1String("overlay");
 +        return QLatin1String("qt-overlay");
      case QPainter::CompositionMode_Darken:
 -        return QLatin1String("darken");
 +        return QLatin1String("qt-darken");
      case QPainter::CompositionMode_Lighten:
 -        return QLatin1String("lighten");
 +        return QLatin1String("qt-lighten");
      case QPainter::CompositionMode_ColorDodge:
 -        return QLatin1String("color-dodge");
 +        return QLatin1String("qt-color-dodge");
      case QPainter::CompositionMode_ColorBurn:
 -        return QLatin1String("color-burn");
 +        return QLatin1String("qt-color-burn");
      case QPainter::CompositionMode_HardLight:
 -        return QLatin1String("hard-light");
 +        return QLatin1String("qt-hard-light");
      case QPainter::CompositionMode_SoftLight:
 -        return QLatin1String("soft-light");
 +        return QLatin1String("qt-soft-light");
      case QPainter::CompositionMode_Difference:
 -        return QLatin1String("difference");
 +        return QLatin1String("qt-difference");
      case QPainter::CompositionMode_Exclusion:
 -        return QLatin1String("exclusion");
 +        return QLatin1String("qt-exclusion");
      default:
          break;
      }
      return QString();
  }
  
 -class QV8Context2DResource : public QV8ObjectResource
 -{
 -    V8_RESOURCE_TYPE(Context2DType)
 -public:
 -    QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
 -    QDeclarativeGuard<QSGContext2D> context;
 -};
  
 -//static script functions
 -static v8::Handle<v8::Value> ctx2d_sync(const v8::Arguments &args)
 +static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
  {
 -    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 -    CHECK_CONTEXT(r)
 -
 -
 -    r->context->sync();
 +    QSGContext2DEngineData *ed = engineData(engine);
 +    v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
 +    QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
 +    if (image.isNull()) {
 +        r->image = QImage(w, h, QImage::Format_ARGB32);
 +        r->image.fill(Qt::transparent);
 +    } else {
 +        Q_ASSERT(image.width() == w && image.height() == h);
 +        r->image = image;
 +    }
 +    v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
 +    pixelData->SetExternalResource(r);
  
 -    return v8::Undefined();
 +    imageData->SetInternalField(0, pixelData);
 +    return imageData;
  }
  
 -// back-reference to the canvas, getter
 +//static script functions
 +
 +/*!
 +    \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
 +     Holds the canvas item that the context paints on.
 +*/
  static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      return engine->newQObject(r->context->canvas());
  }
  
 -// state
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::restore()
 +    Pops the top state on the stack, restoring the context to that state.
 +*/
  static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
 -
 -  r->context->restore();
 -
 -  return v8::Undefined();
 +    r->context->popState();
 +    return args.This();
  }
  
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::reset()
 +    Resets the context state and properties to the default values.
 +*/
  static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
 -
 -  r->context->reset();
 -
 -  return v8::Undefined();
 +    r->context->reset();
 +    return args.This();
  }
  
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::save()
 +    Pushes the current state onto the stack.
 +*/
  static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
 +    r->context->pushState();
  
 -    r->context->save();
 -
 -    return v8::Undefined();
 +    return args.This();
  }
  
  // transformations
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::rotate(real angle)
 +    Changes the transformation matrix to apply a rotation transformation with the given characteristics.
 +    Note: The angle is in radians.
 +*/
  static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
  
 -    if (args.Length() == 1) 
 -        r->context->rotate(args[0]->NumberValue());
 +    if (args.Length() == 1)  {
 +        qreal angle = args[0]->NumberValue();
 +        r->context->state.matrix.rotate(DEGREES(angle));
 +        r->context->buffer()->updateMatrix(r->context->state.matrix);
 +    }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::scale(real x, real y)
 +    Changes the transformation matrix to apply a scaling transformation with the given characteristics.
 +*/
  static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
  
 -    if (args.Length() == 2) 
 -        r->context->scale(args[0]->NumberValue(), args[1]->NumberValue());
 +    if (args.Length() == 2) {
 +        qreal x, y;
 +        x = args[0]->NumberValue();
 +        y = args[1]->NumberValue();
 +        r->context->state.matrix.scale(x, y);
 +        r->context->buffer()->updateMatrix(r->context->state.matrix);
 +    }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
 +    Changes the transformation matrix to the matrix given by the arguments as described below.
 +
 +    \sa QtQuick2::Context2D::transform()
 +*/
  static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
  
  
      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());
 +        r->context->state.matrix = QTransform(args[0]->NumberValue(),
 +                                              args[1]->NumberValue(),
 +                                              args[2]->NumberValue(),
 +                                              args[3]->NumberValue(),
 +                                              args[4]->NumberValue(),
 +                                              args[5]->NumberValue());
 +        r->context->buffer()->updateMatrix(r->context->state.matrix);
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
 +    Changes the transformation matrix to apply the matrix given by the arguments as described below.
 +
 +    \sa QtQuick2::Context2D::setTransform()
 +*/
  static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
  
  
      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());
 +        r->context->state.matrix *= QTransform(args[0]->NumberValue(),
 +                                               args[1]->NumberValue(),
 +                                               args[2]->NumberValue(),
 +                                               args[3]->NumberValue(),
 +                                               args[4]->NumberValue(),
 +                                               args[5]->NumberValue());
 +        r->context->buffer()->updateMatrix(r->context->state.matrix);
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::translate(real x, real y)
 +    Changes the transformation matrix to apply a translation transformation with the given characteristics.
 +*/
  static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
  
  
      if (args.Length() == 2) {
 -        r->context->translate(args[0]->NumberValue(),
 -                              args[1]->NumberValue());
 +        r->context->state.matrix.translate(args[0]->NumberValue(),
 +                                           args[1]->NumberValue());
 +        r->context->buffer()->updateMatrix(r->context->state.matrix);
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 -// compositing
 -// float getter/setter default 1.0
 -static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
 +
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::resetTransform()
 +    Reset the transformation matrix default value.
 +
 +    \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform()
 +*/
 +static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
  {
 -    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
 +    r->context->state.matrix = QTransform();
 +    r->context->buffer()->updateMatrix(r->context->state.matrix);
  
 -    return v8::Number::New(r->context->globalAlpha());
 +    return args.This();
  }
  
 -static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
 +
 +/*!
 +    \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::shear(real sh, real sv )
 +    Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
 +*/
 +static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
  {
 -    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
 -    CHECK_CONTEXT_SETTER(r)
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 +    CHECK_CONTEXT(r)
  
 -    r->context->setGlobalAlpha(value->NumberValue());
 +    r->context->state.matrix.shear(args[0]->NumberValue(),
 +                                   args[1]->NumberValue());
 +    r->context->buffer()->updateMatrix(r->context->state.matrix);
 +
 +    return args.This();
  }
 +// compositing
  
 -// read only property to indicate the validation of the context object
 -static v8::Handle<v8::Value> ctx2d_valid(v8::Local<v8::String>, const v8::AccessorInfo &info)
 +/*!
 +    \qmlproperty real QtQuick2::Context2D::globalAlpha
 +     Holds the the current alpha value applied to rendering operations.
 +     The value must be in the range from 0.0 (fully transparent) to 1.0 (no additional transparency).
 +*/
 +static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
  
  
++<<<<<<< HEAD
 +    return v8::Number::New(r->context->state.globalAlpha);
++=======
+     QV8Engine *engine = V8ENGINE_ACCESSOR();
+     Q_UNUSED(engine)
+     return v8::Boolean::New(r->context->valid());
++>>>>>>> refactor
  }
  
 +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());
 +    CHECK_CONTEXT_SETTER(r)
  
 -// string getter/setter default "source-over"
 +    qreal globalAlpha = value->NumberValue();
 +
 +    if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
 +        r->context->state.globalAlpha = globalAlpha;
 +        r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
 +    }
 +}
 +
 +/*!
 +    \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
 +     Holds the the current the current composition operation, from the list below:
 +     \list
 +     \o source-atop      - A atop B. Display the source image wherever both images are opaque.
 +                           Display the destination image wherever the destination image is opaque but the source image is transparent.
 +                           Display transparency elsewhere.
 +     \o source-in        - A in B. Display the source image wherever both the source image and destination image are opaque.
 +                           Display transparency elsewhere.
 +     \o source-out       - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
 +                           Display transparency elsewhere.
 +     \o source-over      - (default) A over B. Display the source image wherever the source image is opaque.
 +                           Display the destination image elsewhere.
 +     \o destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
 +     \o destination-in   - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
 +     \o destination-out  - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
 +     \o destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
 +     \o lighter          - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
 +     \o copy             - A (B is ignored). Display the source image instead of the destination image.
 +     \o xor              - A xor B. Exclusive OR of the source image and destination image.
 +     \endlist
 +*/
  static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    return engine->toString(r->context->globalCompositeOperation());
 +    return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
  }
  
  static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    r->context->setGlobalCompositeOperation(engine->toString(value));
 +    QPainter::CompositionMode cm = qt_composite_mode_from_string(engine->toString(value));
 +    if (cm != r->context->state.globalCompositeOperation) {
 +        r->context->state.globalCompositeOperation = cm;
 +        r->context->buffer()->setGlobalCompositeOperation(cm);
 +    }
  }
  
  // colors and styles
 -// getter/setter
 +/*!
 +    \qmlproperty variant QtQuick2::Context2D::fillStyle
 +     Holds the current style used for filling shapes.
 +     The style can be either a string containing a CSS color, or a CanvasGradient or CanvasPattern object. Invalid values are ignored.
 +     \sa QtQuick2::Context2D::createLinearGradient
 +     \sa QtQuick2::Context2D::createRadialGradient
 +     \sa QtQuick2::Context2D::createPattern
 +     \sa QtQuick2::Context2D::strokeStyle
 + */
  static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
  
 -
 -    QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    return engine->fromVariant(r->context->fillStyle());
 +    return r->context->m_fillStyle;
  }
  
  static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    r->context->setFillStyle(engine->toVariant(value, -1));
 -}
 -
 -// colors and styles
 -// getter/setter
 -static v8::Handle<v8::Value> ctx2d_fillColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
 +   r->context->m_fillStyle = value;
 +   if (value->IsObject()) {
 +       QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
 +       if (color.isValid()) {
 +           r->context->state.fillStyle = color;
 +           r->context->buffer()->setFillStyle(color);
 +       } else {
 +           QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
 +           if (style && style->brush != r->context->state.fillStyle) {
 +               r->context->state.fillStyle = style->brush;
 +               r->context->buffer()->setFillStyle(style->brush);
 +           }
 +       }
 +   } else if (value->IsString()) {
 +       QColor color = qt_color_from_string(engine->toString(value));
 +       if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
 +            r->context->state.fillStyle = QBrush(color);
 +            r->context->buffer()->setFillStyle(r->context->state.fillStyle);
 +       }
 +   }
 +}
 +
 +static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
 -
 -
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    return engine->fromVariant(r->context->fillColor());
 +    return engine->fromVariant(r->context->state.fillRule);
  }
  
 -static void ctx2d_fillColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
 +static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT_SETTER(r)
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    r->context->setFillColor(engine->toVariant(value, -1).value<QColor>());
 -}
 -
 -//getter/setter
 +    if ((value->IsString() && engine->toString(value) == "WindingFill")
 +      ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
 +        r->context->state.fillRule = Qt::WindingFill;
 +    } else if ((value->IsString() && engine->toString(value) == "OddEvenFill")
 +               ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
 +        r->context->state.fillRule = Qt::OddEvenFill;
 +    } else {
 +        //error
 +    }
 +    r->context->m_path.setFillRule(r->context->state.fillRule);
 +}
 +/*!
 +    \qmlproperty variant QtQuick2::Context2D::strokeStyle
 +     Holds the current color or style to use for the lines around shapes,
 +     The style can be either a string containing a CSS color, or a CanvasGradient or CanvasPattern object. Invalid values are ignored.
 +     \sa QtQuick2::Context2D::createLinearGradient
 +     \sa QtQuick2::Context2D::createRadialGradient
 +     \sa QtQuick2::Context2D::createPattern
 +     \sa QtQuick2::Context2D::fillStyle
 + */
  v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
  
  
 -    QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    return engine->fromVariant(r->context->strokeStyle());
 +    return r->context->m_strokeStyle;
  }
  
  static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    r->context->setStrokeStyle(engine->toVariant(value, -1));
 -}
 -
 -// colors and styles
 -// getter/setter
 -v8::Handle<v8::Value> ctx2d_strokeColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
 -{
 -    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
 -    CHECK_CONTEXT(r)
 -
 -
 -    QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    return engine->fromVariant(r->context->strokeColor());
 +    r->context->m_strokeStyle = value;
 +    if (value->IsObject()) {
 +        QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
 +        if (color.isValid()) {
 +            r->context->state.fillStyle = color;
 +            r->context->buffer()->setStrokeStyle(color);
 +        } else {
 +            QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
 +            if (style && style->brush != r->context->state.strokeStyle) {
 +                r->context->state.strokeStyle = style->brush;
 +                r->context->buffer()->setStrokeStyle(style->brush);
 +            }
 +        }
 +    } else if (value->IsString()) {
 +        QColor color = qt_color_from_string(engine->toString(value));
 +        if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
 +             r->context->state.strokeStyle = QBrush(color);
 +             r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
 +        }
 +    }
  }
  
 -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());
 -    CHECK_CONTEXT_SETTER(r)
 -
 -    QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    r->context->setStrokeColor(engine->toVariant(value, -1).value<QColor>());
 -}
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
 +   Returns a CanvasGradient object that represents a linear gradient that paints along the line given by the coordinates
 +   represented by the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
 +    \sa QtQuick2::Context2D::createRadialGradient
 +    \sa QtQuick2::Context2D::createPattern
 +    \sa QtQuick2::Context2D::fillStyle
 +    \sa QtQuick2::Context2D::strokeStyle
 +  */
  
  static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
  {
      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);
 +        //TODO:infinite or NaN, the method must raise a NOT_SUPPORTED_ERR
 +        QSGContext2DEngineData *ed = engineData(engine);
 +        v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
 +        QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
 +        r->brush = QLinearGradient(args[0]->NumberValue(),
 +                                   args[1]->NumberValue(),
 +                                   args[2]->NumberValue(),
 +                                   args[3]->NumberValue());
 +        gradient->SetExternalResource(r);
 +        return gradient;
      }
  
 -    return v8::Null();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
 +   Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
 +   origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
 +
 +    \sa QtQuick2::Context2D::createLinearGradient
 +    \sa QtQuick2::Context2D::createPattern
 +    \sa QtQuick2::Context2D::fillStyle
 +    \sa QtQuick2::Context2D::strokeStyle
 +  */
 +
  static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      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);
 +        QSGContext2DEngineData *ed = engineData(engine);
 +        v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
 +        QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
 +
 +        qreal x0 = args[0]->NumberValue();
 +        qreal y0 = args[1]->NumberValue();
 +        qreal r0 = args[2]->NumberValue();
 +        qreal x1 = args[3]->NumberValue();
 +        qreal y1 = args[4]->NumberValue();
 +        qreal r1 = args[5]->NumberValue();
 +        //TODO:infinite or NaN, a NOT_SUPPORTED_ERR exception must be raised.
 +        //If either of r0 or r1 are negative, an INDEX_SIZE_ERR exception must be raised.
 +        r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
 +        gradient->SetExternalResource(r);
 +        return gradient;
      }
  
 -    return v8::Null();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod variant createPattern(Image image, string repetition)
 +  Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
 +
 +  The \a image parameter must be a valid Image item, if there is no image data, throws an INVALID_STATE_ERR exception.
 +
 +  The allowed values for \a repetition are:
 +
 +  \list
 +  \o "repeat"    - both directions
 +  \o "repeat-x   - horizontal only
 +  \o "repeat-y"  - vertical only
 +  \o "no-repeat" - neither
 +  \endlist
 +
 +  If the repetition argument is empty or null, the value "repeat" is used.
 +
 +  \sa QtQuick2::Context2D::strokeStyle
 +  \sa QtQuick2::Context2D::fillStyle
 +  */
  static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
  {
 -    //TODO
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 +    CHECK_CONTEXT(r)
 +
 +
 +    QV8Engine *engine = V8ENGINE();
 +
 +    if (args.Length() == 2) {
 +        QSGContext2DEngineData *ed = engineData(engine);
 +        v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
 +        QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
 +
 +        QImage img;
 +
 +        QSGItem* item = qobject_cast<QSGItem*>(engine->toQObject(args[0]));
 +        if (item) {
 +            img = qt_item_to_image(item);
 +//            if (img.isNull()) {
 +//                //exception: INVALID_STATE_ERR
 +//            }
 +        } /*else {
 +            //exception: TYPE_MISMATCH_ERR
 +        }*/
 +
 +        QString repetition = engine->toString(args[1]);
 +
 +//        if (repetition == "repeat" || repetition.isEmpty()) {
 +//            //TODO
 +//        } else if (repetition == "repeat-x") {
 +//            //TODO
 +//        } else if (repetition == "repeat-y") {
 +//            //TODO
 +//        } else if (repetition == "no-repeat") {
 +//            //TODO
 +//        } else {
 +//            //TODO: exception: SYNTAX_ERR
 +//        }
 +        r->brush = img;
 +        pattern->SetExternalResource(r);
 +        return pattern;
 +    }
      return v8::Null();
  }
  
  // line styles
 -// string getter/setter
 +/*!
 +    \qmlproperty string QtQuick2::Context2D::lineCap
 +     Holds the the current line cap style.
 +     The possible line cap styles are:
 +    \list
 +    \o butt - the end of each line has a flat edge perpendicular to the direction of the line, this is the default line cap value.
 +    \o round - a semi-circle with the diameter equal to the width of the line must then be added on to the end of the line.
 +    \o square - a rectangle with the length of the line width and the width of half the line width, placed flat against the edge perpendicular to the direction of the line.
 +    \endlist
 +    Other values are ignored.
 +*/
  v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
  
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    return engine->toString(r->context->lineCap());
 +    switch (r->context->state.lineCap) {
 +    case Qt::RoundCap:
 +        return engine->toString(QLatin1String("round"));
 +    case Qt::FlatCap:
 +        return engine->toString(QLatin1String("butt"));
 +    case Qt::SquareCap:
 +        return engine->toString(QLatin1String("square"));
 +    default:
 +        break;
 +    }
 +    return engine->toString(QLatin1String("butt"));;
  }
  
  static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    r->context->setLineCap(engine->toString(value));
 -}
 -
 -// string getter/setter
 +    QString lineCap = engine->toString(value);
 +    Qt::PenCapStyle cap;
 +    if (lineCap == QLatin1String("round"))
 +        cap = Qt::RoundCap;
 +    else if (lineCap == QLatin1String("butt"))
 +        cap = Qt::FlatCap;
 +    else if (lineCap == QLatin1String("square"))
 +        cap = Qt::SquareCap;
 +
 +    if (cap != r->context->state.lineCap) {
 +        r->context->state.lineCap = cap;
 +        r->context->buffer()->setLineCap(cap);
 +    }
 +}
 +
 +/*!
 +    \qmlproperty string QtQuick2::Context2D::lineJoin
 +     Holds the the current line join style. A join exists at any point in a subpath
 +     shared by two consecutive lines. When a subpath is closed, then a join also exists
 +     at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
 +
 +    The possible line join styles are:
 +    \list
 +    \o bevel - this is all that is rendered at joins.
 +    \o round - a filled arc connecting the two aforementioned corners of the join, abutting (and not overlapping) the aforementioned triangle, with the diameter equal to the line width and the origin at the point of the join, must be rendered at joins.
 +    \o miter - a second filled triangle must (if it can given the miter length) be rendered at the join, this is the default line join style.
 +    \endlist
 +    Other values are ignored.
 +*/
  v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
  
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    return engine->toString(r->context->lineJoin());
 +    switch (r->context->state.lineJoin) {
 +    case Qt::RoundJoin:
 +        return engine->toString(QLatin1String("round"));
 +    case Qt::BevelJoin:
 +        return engine->toString(QLatin1String("bevel"));
 +    case Qt::MiterJoin:
 +        return engine->toString(QLatin1String("miter"));
 +    default:
 +        break;
 +    }
 +    return engine->toString(QLatin1String("miter"));
  }
  
  static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    r->context->setLineJoin(engine->toString(value));
 +    QString lineJoin = engine->toString(value);
 +    Qt::PenJoinStyle join;
 +    if (lineJoin == QLatin1String("round"))
 +        join = Qt::RoundJoin;
 +    else if (lineJoin == QLatin1String("bevel"))
 +        join = Qt::BevelJoin;
 +    else if (lineJoin == QLatin1String("miter"))
 +        join = Qt::MiterJoin;
 +
 +    if (join != r->context->state.lineJoin) {
 +        r->context->state.lineJoin = join;
 +        r->context->buffer()->setLineJoin(join);
 +    }
  }
  
 -// float getter/setter
 +/*!
 +    \qmlproperty real QtQuick2::Context2D::lineWidth
 +     Holds the the current line width. Values that are not finite values greater than zero are ignored.
 + */
  v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
  
  
 -    return v8::Number::New(r->context->lineWidth());
 +    return v8::Number::New(r->context->state.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());
      CHECK_CONTEXT_SETTER(r)
  
 -    r->context->setLineWidth(value->NumberValue());
 +    qreal w = value->NumberValue();
 +
 +    if (w > 0 && w != r->context->state.lineWidth) {
 +        r->context->state.lineWidth = w;
 +        r->context->buffer()->setLineWidth(w);
 +    }
  }
  
 -// float getter/setter
 +/*!
 +    \qmlproperty real QtQuick2::Context2D::miterLimit
 +     Holds the current miter limit ratio.
 +     The default miter limit value is 10.0.
 + */
  v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
  
  
 -    return v8::Number::New(r->context->miterLimit());
 +    return v8::Number::New(r->context->state.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());
      CHECK_CONTEXT_SETTER(r)
  
 -    r->context->setMiterLimit(value->NumberValue());
 +    qreal ml = value->NumberValue();
 +
 +    if (ml > 0 && ml != r->context->state.miterLimit) {
 +        r->context->state.miterLimit = ml;
 +        r->context->buffer()->setMiterLimit(ml);
 +    }
  }
  
  // shadows
 -// float getter/setter
 +/*!
 +    \qmlproperty real QtQuick2::Context2D::shadowBlur
 +     Holds the current level of blur applied to shadows
 + */
  v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
  
  
 -    return v8::Number::New(r->context->shadowBlur());
 +    return v8::Number::New(r->context->state.shadowBlur);
  }
  
  static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT_SETTER(r)
 +    qreal blur = value->NumberValue();
  
 -    r->context->setShadowBlur(value->NumberValue());
 +    if (blur > 0 && blur != r->context->state.shadowBlur) {
 +        r->context->state.shadowBlur = blur;
 +        r->context->buffer()->setShadowBlur(blur);
 +    }
  }
  
 +/*!
 +    \qmlproperty string QtQuick2::Context2D::shadowColor
 +     Holds the current shadow color.
 + */
  v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    return engine->toString(r->context->shadowColor());
 +    return engine->toString(r->context->state.shadowColor.name());
  }
  
  static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    r->context->setShadowColor(engine->toString(value));
 +    QColor color = qt_color_from_string(engine->toString(value));
 +
 +    if (color.isValid() && color != r->context->state.shadowColor) {
 +        r->context->state.shadowColor = color;
 +        r->context->buffer()->setShadowColor(color);
 +    }
  }
  
 +
 +/*!
 +    \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
 +     Holds the current shadow offset in the positive horizontal distance.
 +
 +     \sa QtQuick2::Context2D::shadowOffsetY
 + */
  v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
  
  
 -    return v8::Number::New(r->context->shadowOffsetX());
 +    return v8::Number::New(r->context->state.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());
      CHECK_CONTEXT_SETTER(r)
  
 -    r->context->setShadowOffsetX(value->NumberValue());
 +    //TODO: check value:infinite or NaN
 +    qreal offsetX = value->NumberValue();
 +    if (offsetX != r->context->state.shadowOffsetX) {
 +        r->context->state.shadowOffsetX = offsetX;
 +        r->context->buffer()->setShadowOffsetX(offsetX);
 +    }
  }
 +/*!
 +    \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
 +     Holds the current shadow offset in the positive vertical distance.
  
 +     \sa QtQuick2::Context2D::shadowOffsetX
 + */
  v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
  
  
 -    return v8::Number::New(r->context->shadowOffsetY());
 +    return v8::Number::New(r->context->state.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());
      CHECK_CONTEXT_SETTER(r)
 +    //TODO: check value:infinite or NaN
 +    qreal offsetY = value->NumberValue();
 +    if (offsetY != r->context->state.shadowOffsetY) {
 +        r->context->state.shadowOffsetY = offsetY;
 +        r->context->buffer()->setShadowOffsetY(offsetY);
 +    }
 +}
 +
 +v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
 +{
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
 +    CHECK_CONTEXT(r)
 +    return r->context->m_v8path;
 +}
 +
 +static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
 +{
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
 +    CHECK_CONTEXT_SETTER(r)
 +    QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    r->context->setShadowOffsetY(value->NumberValue());
 +    r->context->beginPath();
 +    if (value->IsObject()) {
 +        QDeclarativePath* path = qobject_cast<QDeclarativePath*>(engine->toQObject(value));
 +        if (path)
 +            r->context->m_path = path->path();
 +    } else {
 +        QString path = engine->toString(value->ToString());
 +        QDeclarativeSvgParser::parsePathDataFast(path, r->context->m_path);
 +    }
 +    r->context->m_v8path = value;
  }
  
  //rects
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
 +  Clears all pixels on the canvas in the given rectangle to transparent black.
 +  */
  static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
  
  
      if (args.Length() == 4) {
 -        r->context->clearRect(args[0]->NumberValue(),
 -                              args[1]->NumberValue(),
 -                              args[2]->NumberValue(),
 -                              args[3]->NumberValue());
 +        r->context->buffer()->clearRect(args[0]->NumberValue(),
 +                                        args[1]->NumberValue(),
 +                                        args[2]->NumberValue(),
 +                                        args[3]->NumberValue());
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
 +   Paint the specified rectangular area using the fillStyle.
  
 +   \sa QtQuick2::Context2D::fillStyle
 +  */
  static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
  
  
      if (args.Length() == 4) {
 -        r->context->fillRect(args[0]->NumberValue(),
 +        r->context->buffer()->fillRect(args[0]->NumberValue(),
                               args[1]->NumberValue(),
                               args[2]->NumberValue(),
                               args[3]->NumberValue());
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
 +   Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
 +   and (if appropriate) miterLimit attributes.
 +
 +   \sa QtQuick2::Context2D::strokeStyle
 +   \sa QtQuick2::Context2D::lineWidth
 +   \sa QtQuick2::Context2D::lineJoin
 +   \sa QtQuick2::Context2D::miterLimit
 +  */
  static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
  
  
      if (args.Length() == 4) {
 -        r->context->strokeRect(args[0]->NumberValue(),
 -                               args[1]->NumberValue(),
 -                               args[2]->NumberValue(),
 -                               args[3]->NumberValue());
 +        r->context->buffer()->strokeRect(args[0]->NumberValue(),
 +                                         args[1]->NumberValue(),
 +                                         args[2]->NumberValue(),
 +                                         args[3]->NumberValue());
      }
      
 -    return v8::Undefined();
 +    return args.This();
  }
  
  // Complex shapes (paths) API
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
 +   Adds points to the subpath such that the arc described by the circumference of
 +   the circle described by the arguments.
 +
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-arc for details.
 +  */
  static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
 +    if (args.Length() >= 5) {
 +        bool antiClockwise = false;
  
 -    if (args.Length() == 6) {
 +        if (args.Length() == 6)
 +            antiClockwise = args[5]->BooleanValue();
 +
 +        qreal radius = args[2]->NumberValue();
 +        //Throws an INDEX_SIZE_ERR exception if the given radius is negative.
          r->context->arc(args[0]->NumberValue(),
                          args[1]->NumberValue(),
 -                        args[2]->NumberValue(),
 +                        radius,
                          args[3]->NumberValue(),
                          args[4]->NumberValue(),
 -                        args[5]->NumberValue());
 +                        antiClockwise);
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
 +
 +   Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto for details.
 +  */
  static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
                            args[4]->NumberValue());
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::beginPath()
 +
 +   Resets the current path.
 +  */
  static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
  
      r->context->beginPath();
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
 +
 +   Adds the given point to the current subpath, connected to the previous one by a cubic Bézier curve with the given control points.
 +
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto for details.
 +  */
  static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
  
 -    if (args.Length() == 5) {
 +    if (args.Length() == 6) {
          r->context->bezierCurveTo(args[0]->NumberValue(),
                                    args[1]->NumberValue(),
                                    args[2]->NumberValue(),
                                    args[5]->NumberValue());
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::clip()
 +
 +   constrains the clipping region to the given path.
 +
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-clip for details.
 +  */
  static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
 -
 -    r->context->clip();
 +    r->context->state.clipPath = r->context->m_path;
 +    r->context->buffer()->clip(r->context->state.clipPath);
      
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::closePath()
 +
 +   Marks the current subpath as closed, and starts a new subpath with a point the same as the start and end of the newly closed subpath.
 +
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath for details.
 +  */
  static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
  
      r->context->closePath();
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fill()
 +
 +   Fills the subpaths with the current fill style.
 +
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-fill for details.
 +
 +   \sa QtQuick2::Context2D::fillStyle
 +  */
  static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
 +    r->context->buffer()->fill(r->context->m_path);
  
 -    r->context->fill();
 -
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::lineTo(real x, real y)
 +
 +   Adds the given point to the current subpath, connected to the previous one by a straight line.
 + */
  static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
                             args[1]->NumberValue());
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::moveTo(real x, real y)
 +
 +   Creates a new subpath with the given point.
 + */
  static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
                             args[1]->NumberValue());
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
 +
 +   Adds the given point to the current subpath, connected to the previous one by a quadratic Bézier curve with the given control point.
 +
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto for details.
 + */
  static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
                                       args[3]->NumberValue());
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::rect(real x, real y, real w, real h)
 +
 +   Adds a new closed subpath to the path, representing the given rectangle.
 +
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-rect for details.
 + */
  static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
                           args[3]->NumberValue());
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 -static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::roundedRect(real x, real y, real w, real h,  real xRadius, real yRadius)
 +
 +   Adds the given rectangle rect with rounded corners to the path. The xRadius and yRadius arguments specify the radii of the
 +   ellipses defining the corners of the rounded rectangle.
 + */
 +static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
  
 -    r->context->stroke();
 +    if (args.Length() == 6) {
 +        r->context->roundedRect(args[0]->NumberValue(),
 +                                args[1]->NumberValue(),
 +                                args[2]->NumberValue(),
 +                                args[3]->NumberValue(),
 +                                args[4]->NumberValue(),
 +                                args[5]->NumberValue());
 +    }
  
 -    return v8::Undefined();
 +    return args.This();
  }
  
 -static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
 +
 +  Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
 +  and adds it to the path as a closed subpath.
 +
 +  The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
 + */
 +static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
  
 -    bool pointInPath = false;
 -    if (args.Length() == 2) {
 -        pointInPath = r->context->isPointInPath(args[0]->NumberValue(),
 -                                                args[1]->NumberValue());
 +    if (args.Length() == 6) {
 +        r->context->ellipse(args[0]->NumberValue(),
 +                            args[1]->NumberValue(),
 +                            args[2]->NumberValue(),
 +                            args[3]->NumberValue());
      }
  
 -    return v8::Boolean::New(pointInPath);
 +    return args.This();
  }
  
 -static v8::Handle<v8::Value> ctx2d_setPathString(const v8::Arguments &args)
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::text(string text, real x, real y)
 +
 +  Adds the given \a text to the path as a set of closed subpaths created from the current context font supplied.
 +  The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (x, y).
 + */
 +static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      CHECK_CONTEXT(r)
  
 -
      QV8Engine *engine = V8ENGINE();
 -    if (args.Length() == 1) {
 -        r->context->setPathString(engine->toString(args[0]));
 +    if (args.Length() == 3) {
 +        r->context->text(engine->toString(args[0]),
 +                         args[1]->NumberValue(),
 +                         args[2]->NumberValue());
      }
 -    return v8::Undefined();
 +
 +    return args.This();
  }
  
 -static v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::stroke()
 +
 +   Strokes the subpaths with the current stroke style.
 +
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke for details.
 +
 +   \sa QtQuick2::Context2D::strokeStyle
 +  */
 +static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
  {
 -//    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
 -//    CHECK_CONTEXT(r)
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 +    CHECK_CONTEXT(r)
  
 -//    QV8Engine *engine = V8ENGINE();
  
 -    return v8::Undefined();
 +    r->context->buffer()->stroke(r->context->m_path);
 +
 +    return args.This();
  }
  
 -static v8::Handle<v8::Value> ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::isPointInPath(real x, real y)
 +
 +   Returns true if the given point is in the current path.
 +
 +   See http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath for details.
 +  */
 +static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
  {
 -//    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 -//    CHECK_CONTEXT(r)
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 +    CHECK_CONTEXT(r)
  
  
 -//    QV8Engine *engine = V8ENGINE();
 -//    if (args.Length() == 1) {
 -//        r->context->setPathString(engine->toString(args[0]));
 -//    }
 -    return v8::Undefined();
 +    bool pointInPath = false;
 +    if (args.Length() == 2) {
 +        pointInPath = r->context->isPointInPath(args[0]->NumberValue(),
 +                                                args[1]->NumberValue());
 +    }
 +
 +    return v8::Boolean::New(pointInPath);
  }
  
 -static v8::Handle<v8::Value> ctx2d_createPath(const v8::Arguments &args)
 +static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
  {
 -//    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 -//    CHECK_CONTEXT(r)
 -
 +    V8THROW_ERROR("Context2D::drawFocusRing is not supported")
 +    return args.This();
 +}
  
 -//    QV8Engine *engine = V8ENGINE();
 -//    if (args.Length() == 1) {
 -//        r->context->setPathString(engine->toString(args[0]));
 -//    }
 -    return v8::Undefined();
 +static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
 +{
 +    V8THROW_ERROR("Context2D::setCaretSelectionRect is not supported")
 +    return args.This();
  }
  
 +static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
 +{
 +    V8THROW_ERROR("Context2D::caretBlinkRate is not supported")
 +
 +    return args.This();
 +}
  // text
 +/*!
 +  \qmlproperty string QtQuick2::Context2D::font
 +  Holds the current font settings, default value is "10px sans-serif".
 +
 +  See http://www.w3.org/TR/2dcontext/#dom-context-2d-font for details.
 +  */
  v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    return engine->toString(r->context->font());
 +    return engine->toString(r->context->m_fontString);
  }
  
  static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
      CHECK_CONTEXT_SETTER(r)
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    r->context->setFont(engine->toString(value));
 -}
 -
 +    QString fs = engine->toString(value);
 +    if (fs != r->context->m_fontString) {
 +        r->context->m_fontString = fs;
 +        QFont font = qt_font_from_string(fs);
 +        r->context->state.font = font;
 +    }
 +}
 +
 +/*!
 +  \qmlproperty string QtQuick2::Context2D::textAlign
 +
 +  Holds the current text alignment settings.
 +  The possible values are:
 +  \list
 +    \o start
 +    \o end
 +    \o left
 +    \o right
 +    \o center
 +  \endlist
 +  Other values are ignored. The default is start.
 +  */
  v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
      QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    return engine->toString(r->context->textAlign());
 +    switch (r->context->state.textAlign) {
 +    case QSGContext2D::Start:
 +        return engine->toString(QLatin1String("start"));
 +   case QSGContext2D::End:
 +        return engine->toString(QLatin1String("end"));
 +   case QSGContext2D::Left:
 +        return engine->toString(QLatin1String("left"));
 +   case QSGContext2D::Right:
 +        return engine->toString(QLatin1String("right"));
 +   case QSGContext2D::Center:
 +        return engine->toString(QLatin1String("center"));
 +    default:
 +        break;
 +    }
 +    return engine->toString(QLatin1String("start"));
  }
  
  static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
      CHECK_CONTEXT_SETTER(r)
      QV8Engine *engine = V8ENGINE_ACCESSOR();
  
 -    r->context->setTextAlign(engine->toString(value));
 +    QString textAlign = engine->toString(value);
 +
 +    QSGContext2D::TextAlignType ta;
 +    if (textAlign == QLatin1String("start"))
 +        ta = QSGContext2D::Start;
 +    else if (textAlign == QLatin1String("end"))
 +        ta = QSGContext2D::End;
 +    else if (textAlign == QLatin1String("left"))
 +        ta = QSGContext2D::Left;
 +    else if (textAlign == QLatin1String("right"))
 +        ta = QSGContext2D::Right;
 +    else if (textAlign == QLatin1String("center"))
 +        ta = QSGContext2D::Center;
 +
 +    if (ta != r->context->state.textAlign) {
 +        r->context->state.textAlign = ta;
 +    }
  }
  
 +/*!
 +  \qmlproperty string QtQuick2::Context2D::textBaseline
 +
 +  Holds the current baseline alignment settings.
 +  The possible values are:
 +  \list
 +    \o top
 +    \o hanging
 +    \o middle
 +    \o alphabetic
 +    \o ideographic
 +    \o bottom
 +  \endlist
 +  Other values are ignored. The default value is "alphabetic".
 +  See http://www.w3.org/TR/2dcontext/#dom-context-2d-textbaseline for details.
 +  */
  v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT(r)
  
      QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    return engine->toString(r->context->textBaseline());
 +    switch (r->context->state.textBaseline) {
 +    case QSGContext2D::Alphabetic:
 +        return engine->toString(QLatin1String("alphabetic"));
 +    case QSGContext2D::Hanging:
 +        return engine->toString(QLatin1String("hanging"));
 +    case QSGContext2D::Top:
 +        return engine->toString(QLatin1String("top"));
 +    case QSGContext2D::Bottom:
 +        return engine->toString(QLatin1String("bottom"));
 +    case QSGContext2D::Middle:
 +        return engine->toString(QLatin1String("middle"));
 +    default:
 +        break;
 +    }
 +    return engine->toString(QLatin1String("alphabetic"));
  }
  
  static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
      CHECK_CONTEXT_SETTER(r)
      QV8Engine *engine = V8ENGINE_ACCESSOR();
 -
 -    r->context->setTextBaseline(engine->toString(value));
 -}
 -
 +    QString textBaseline = engine->toString(value);
 +
 +    QSGContext2D::TextBaseLineType tb;
 +    if (textBaseline == QLatin1String("alphabetic"))
 +        tb = QSGContext2D::Alphabetic;
 +    else if (textBaseline == QLatin1String("hanging"))
 +        tb = QSGContext2D::Hanging;
 +    else if (textBaseline == QLatin1String("top"))
 +        tb = QSGContext2D::Top;
 +    else if (textBaseline == QLatin1String("bottom"))
 +        tb = QSGContext2D::Bottom;
 +    else if (textBaseline == QLatin1String("middle"))
 +        tb = QSGContext2D::Middle;
 +
 +    if (tb != r->context->state.textBaseline) {
 +        r->context->state.textBaseline = tb;
 +    }
 +}
 +
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillText(text, x, y)
 +  Fills the given text at the given position.
 +  See http://www.w3.org/TR/2dcontext/#dom-context-2d-filltext for details.
 +  */
  static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      QV8Engine *engine = V8ENGINE();
  
      if (args.Length() == 3) {
 -        r->context->fillText(engine->toString(args[0]),
 -                             args[1]->NumberValue(),
 -                             args[2]->NumberValue());
 +        QPainterPath textPath = r->context->createTextGlyphs(args[1]->NumberValue(),
 +                                                             args[2]->NumberValue(),
 +                                                             engine->toString(args[0]));
 +        r->context->buffer()->fill(textPath);
      }
  
 -    return v8::Undefined();
 +    return args.This();
  }
 -
 +/*!
 +  \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::strokeText(text, x, y)
 +  Strokes the given text at the given position.
 +  See http://www.w3.org/TR/2dcontext/#dom-context-2d-stroketext for details.
 +  */
  static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
      QV8Engine *engine = V8ENGINE();
  
      if (args.Length() == 3) {
 -        r->context->strokeText(engine->toString(args[0]),
 -                               args[1]->NumberValue(),
 -                               args[2]->NumberValue());
 +        QPainterPath textPath = r->context->createTextGlyphs(args[1]->NumberValue(),
 +                                                             args[2]->NumberValue(),
 +                                                             engine->toString(args[0]));
 +        r->context->buffer()->stroke(textPath);
 +    }
 +
 +    return args.This();
 +}
 +/*!
 +  \qmlclass QtQuick2::TextMetrics
 +    \inqmlmodule QtQuick 2
 +    \since QtQuick 2.0
 +    \brief The Context2D TextMetrics interface.
 +    The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
 +    See http://www.w3.org/TR/2dcontext/#textmetrics for more details.
 +
 +    \sa QtQuick2::Context2D::measureText
 +    \sa QtQuick2::TextMetrics::width
 +  */
 +
 +/*!
 +  \qmlproperty int QtQuick2::TextMetrics::width
 +  Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
 +  This property is read only.
 +  See http://www.w3.org/TR/2dcontext/#dom-textmetrics-width for more details.
 +  */
 +
 +/*!
 +  \qmlmethod variant QtQuick2::Context2D::measureText(text)
 +  Returns a TextMetrics object with the metrics of the given text in the current font.
 +  See http://www.w3.org/TR/2dcontext/#dom-context-2d-measuretext for details.
 +  */
 +static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
 +{
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 +    CHECK_CONTEXT(r)
 +
 +
 +    QV8Engine *engine = V8ENGINE();
 +
 +    if (args.Length() == 1) {
 +        QFontMetrics fm(r->context->state.font);
 +        uint width = fm.width(engine->toString(args[0]));
 +        v8::Local<v8::Object> tm = v8::Object::New();
 +        tm->Set(v8::String::New("width"), v8::Number::New(width));
 +        return tm;
      }
  
      return v8::Undefined();
  }
  
  // drawing images
 +/*!
 +  \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
 +  Draws the given \a image on the canvas at position (\a dx, \a dy).
 +  Note:
 +     The \a image type can be an Image item or a image url. When given as Image
 +  type, if the image isn't fully loaded, will draw nothing. When given as url string,
 +  the context loads the image asynchorously and redraw the canvas when the image is loaded.
 +
 +  See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
 +  */
 +/*!
 +  \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
 +  Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
 +  height \a dh.
 +  See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
 +  */
 +/*!
 +  \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
 +  Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
 +  onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
 +  See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
 +  */
  static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
  {
      QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
  
      QV8Engine *engine = V8ENGINE();
  
 +    //TODO: handle exceptions
 +
 +    qreal sx, sy, sw, sh, dx, dy, dw, dh;
 +
 +    if (args.Length() != 3 && args.Length() != 5 && args.Length() != 9) {
 +        //parameter error
 +        return args.This();
 +    }
 +
 +
 +    QImage image;
 +    if (args[0]->IsString()) {
 +        image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
 +    } /*else if (args[0]->IsObject()) {
 +        QSGImage* imageItem = qobject_cast<QSGImage*>(engine->toQObject(args[0]->ToObject()));
 +        if (imageItem) {
 +            image = imageItem->pixmap().toImage();
 +        } else {
 +            //wrong image type
 +            return args.This();
 +        }
 +    }*/
      if (args.Length() == 3) {
 -        r->context->drawImage(engine->toString(args[0]),
 -                              args[1]->NumberValue(),
 -                              args[2]->NumberValue());
 +        dx = args[1]->NumberValue();
 +        dy = args[2]->NumberValue();
 +        sx = 0;
 +        sy = 0;
 +        sw = image.isNull()? -1 : image.width();
 +        sh = image.isNull()? -1 : image.height();
 +        dw = sw;
 +        dh = sh;
      } else if (args.Length() == 5) {
 -        r->context->drawImage(engine->toString(args[0]),
 -                              args[1]->NumberValue(),
 -                              args[2]->NumberValue(),
 -                              args[3]->NumberValue(),
 -                              args[4]->NumberValue());
 +        sx = 0;
 +        sy = 0;
 +        sw = image.isNull()? -1 : image.width();
 +        sh = image.isNull()? -1 : image.height();
 +        dx = args[1]->NumberValue();
 +        dy = args[2]->NumberValue();
 +        dw = args[3]->NumberValue();
 +        dh = 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());
 +        sx = args[1]->NumberValue();
 +        sy = args[2]->NumberValue();
 +        sw = args[3]->NumberValue();
 +        sh = args[4]->NumberValue();
 +        dx = args[5]->NumberValue();
 +        dy = args[6]->NumberValue();
 +        dw = args[7]->NumberValue();
 +        dh = args[8]->NumberValue();
 +    } else {
 +        //error
 +        return args.This();
      }
  
 -    return v8::Undefined();
 +    r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
 +
 +    return args.This();
  }
  
  // pixel manipulation
 -static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
 -{
 -    //#TODO
 -    return v8::Undefined();
 -}
 +/*!
 +  \qmlclass QtQuick2::CanvasImageData
  
 -static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
 +  */
 +/*!
 +  \qmlproperty QtQuick2::CanvasImageData::width
 +  Holds the actual width dimension of the data in the ImageData object, in device pixels.
 + */
 +v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
  {
 -    //#TODO
 -    return v8::Undefined();
 +    QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
 +    if (!r)
 +        return v8::Integer::New(0);
 +    return v8::Integer::New(r->image.width());
  }
  
 -static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
 +/*!
 +  \qmlproperty QtQuick2::CanvasImageData::height
 +  Holds the actual height dimension of the data in the ImageData object, in device pixels.
 +  */
 +v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
  {
 -    //#TODO
 -    return v8::Undefined();
 -}
 +    QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
 +    if (!r)
 +        return v8::Integer::New(0);
  
 -bool QSGContext2DPrivate::hasShadow() const
 -{
 -    return state.shadowColor.isValid()
 -        && state.shadowColor.alpha()
 -        && (state.shadowBlur || state.shadowOffsetX || state.shadowOffsetY);
 +    return v8::Integer::New(r->image.height());
  }
  
 -void QSGContext2DPrivate::clearShadow()
 +/*!
 +  \qmlproperty QtQuick2::CanvasImageData::data
 +  Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
 + */
 +v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
  {
 -    state.shadowOffsetX = 0;
 -    state.shadowOffsetY = 0;
 -    state.shadowBlur = 0;
 -    state.shadowColor = QColor();
 +    return args.This()->GetInternalField(0);
  }
  
 -QImage QSGContext2DPrivate::makeShadowImage(const QPixmap& pix)
 +static v8::Handle<v8::Value> ctx2d_imageData_mirror(const v8::Arguments &args)
  {
 -    QImage shadowImg(pix.width() + state.shadowBlur * 2 + qAbs(state.shadowOffsetX),
 -                     pix.height() + state.shadowBlur *2 + qAbs(state.shadowOffsetY),
 -                     QImage::Format_ARGB32);
 -    shadowImg.fill(0);
 -    QPainter tmpPainter(&shadowImg);
 -    tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
 -    qreal shadowX = state.shadowOffsetX > 0? state.shadowOffsetX : 0;
 -    qreal shadowY = state.shadowOffsetY > 0? state.shadowOffsetY : 0;
 +    bool horizontal = false, vertical = true;
 +    QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
 +
 +    if (!r) {
 +        //error
 +        return v8::Undefined();
 +    }
  
 -    tmpPainter.drawPixmap(shadowX, shadowY, pix);
 -    tmpPainter.end();
 +    if (args.Length() > 2) {
 +      //error
 +      return v8::Undefined();
 +    }
  
++<<<<<<< HEAD
 +    if (args.Length() == 1) {
 +        horizontal = args[0]->BooleanValue();
 +    } else if (args.Length() == 2) {
 +        horizontal = args[0]->BooleanValue();
 +        vertical = args[1]->BooleanValue();
++=======
+ #if 0
+     // ### refactor
+     // blur the alpha channel
+     if (state.shadowBlur > 0) {
+         QImage blurred(shadowImg.size(), QImage::Format_ARGB32);
+         blurred.fill(0);
+         QPainter blurPainter(&blurred);
+         qt_blurImage(&blurPainter, shadowImg, state.shadowBlur, false, true);
+         blurPainter.end();
+         shadowImg = blurred;
++>>>>>>> refactor
      }
+ #endif
  
 -    // blacken the image with shadow color...
 -    tmpPainter.begin(&shadowImg);
 -    tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
 -    tmpPainter.fillRect(shadowImg.rect(), state.shadowColor);
 -    tmpPainter.end();
 -    return shadowImg;
 +    r->image = r->image.mirrored(horizontal, vertical);
 +    return args.This();
  }
  
 -void QSGContext2DPrivate::fillRectShadow(QPainter* p, QRectF shadowRect)
 +
 +static v8::Handle<v8::Value> ctx2d_imageData_filter(const v8::Arguments &args)
  {
 -    QRectF r = shadowRect;
 -    r.moveTo(0, 0);
 +    QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
  
 -    QImage shadowImage(r.size().width() + 1, r.size().height() + 1, QImage::Format_ARGB32);
 -    QPainter tp;
 -    tp.begin(&shadowImage);
 -    tp.fillRect(r, p->brush());
 -    tp.end();
 -    shadowImage = makeShadowImage(QPixmap::fromImage(shadowImage));
 +    if (!r) {
 +        //error
 +        return v8::Undefined();
 +    }
  
 -    qreal dx = shadowRect.left() + (state.shadowOffsetX < 0? state.shadowOffsetX:0);
 -    qreal dy = shadowRect.top() + (state.shadowOffsetY < 0? state.shadowOffsetY:0);
 +    if (args.Length() >= 1) {
 +        int filterFlag = args[0]->IntegerValue();
 +        switch(filterFlag) {
 +        case QSGCanvasItem::GrayScale :
 +        {
 +            for (int y = 0; y < r->image.height(); ++y) {
 +              QRgb *row = (QRgb*)r->image.scanLine(y);
 +              for (int x = 0; x < r->image.width(); ++x) {
 +                  unsigned char* rgb = ((unsigned char*)&row[x]);
 +                  rgb[0] = rgb[1] = rgb[2] = qGray(rgb[0], rgb[1], rgb[2]);
 +              }
 +            }
 +        }
 +            break;
 +        case QSGCanvasItem::Threshold :
 +        {
 +            int threshold = 127;
 +            if (args.Length() > 1)
 +                threshold = args[1]->IntegerValue();
 +
 +            for (int y = 0; y < r->image.height(); ++y) {
 +              QRgb *row = (QRgb*)r->image.scanLine(y);
 +              for (int x = 0; x < r->image.width(); ++x) {
 +                  unsigned char* rgb = ((unsigned char*)&row[x]);
 +                  unsigned char v = qGray(rgb[0], rgb[1], rgb[2]) >= threshold ? 255 : 0;
 +                  rgb[0] = rgb[1] = rgb[2] = v;
 +              }
 +            }
 +        }
 +            break;
 +        case QSGCanvasItem::Brightness :
 +        {
 +            int adjustment = 1;
 +            if (args.Length() > 1)
 +                adjustment = args[1]->IntegerValue();
 +
 +            for (int y = 0; y < r->image.height(); ++y) {
 +              QRgb *row = (QRgb*)r->image.scanLine(y);
 +              for (int x = 0; x < r->image.width(); ++x) {
 +                ((unsigned char*)&row[x])[0] += adjustment;
 +                ((unsigned char*)&row[x])[1] += adjustment;
 +                ((unsigned char*)&row[x])[2] += adjustment;
 +              }
 +            }
 +        }
 +            break;
 +        case QSGCanvasItem::Invert :
 +        {
 +            r->image.invertPixels();
 +        }
 +            break;
 +        case QSGCanvasItem::Blur :
 +        {
 +            QImage blurred(r->image.size(), QImage::Format_ARGB32);
 +            qreal blur = 10;
 +            if (args.Length() > 1)
 +                blur = args[1]->NumberValue();
 +
 +            blurred.fill(Qt::transparent);
 +            QPainter blurPainter(&blurred);
 +            qt_blurImage(&blurPainter, r->image, blur, true, false);
 +            blurPainter.end();
 +            r->image = blurred;
 +        }
 +            break;
 +        case QSGCanvasItem::Opaque :
 +        {
 +            for (int y = 0; y < r->image.height(); ++y) {
 +              QRgb *row = (QRgb*)r->image.scanLine(y);
 +              for (int x = 0; x < r->image.width(); ++x) {
 +                ((unsigned char*)&row[x])[3] = 255;
 +              }
 +            }
 +        }
 +            break;
 +        case QSGCanvasItem::Convolute :
 +        {
 +            if (args.Length() > 1 && args[1]->IsArray()) {
 +                v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(args[1]);
 +                QVector<int> weights;
 +                for (uint32_t i = 0; i < array->Length(); ++i)
 +                    weights.append(array->Get(i)->NumberValue());
 +                int sides = qRound(qSqrt(weights.size()));
 +                int half = qFloor(sides/2);
 +
 +                QImage image = QImage(r->image.size(), QImage::Format_ARGB32);
 +                int w = r->image.width();
 +                int h = r->image.height();
 +                for (int y = 0; y < image.height(); ++y) {
 +                  QRgb *dRow = (QRgb*)image.scanLine(y);
 +                  for (int x = 0; x < image.width(); ++x) {
 +                      unsigned char* dRgb = ((unsigned char*)&dRow[x]);
 +                      unsigned char red=0, green=0, blue=0, alpha=0;
 +                      int sy = y;
 +                      int sx = x;
 +
 +                      for (int cy=0; cy<sides; cy++) {
 +                         for (int cx=0; cx<sides; cx++) {
 +                           int scy = sy + cy - half;
 +                           int scx = sx + cx - half;
 +                           if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
 +                              QRgb *sRow = (QRgb*)(r->image.scanLine(scy));
 +                              unsigned char* sRgb = ((unsigned char*)&sRow[scx]);
 +                              int wt = weights[cy*sides+cx];
 +                              red += sRgb[0] * wt;
 +                              green += sRgb[1] * wt;
 +                              blue += sRgb[2] * wt;
 +                              alpha += sRgb[3] * wt;
 +                           }
 +                         }
 +                      }
 +                      dRgb[0] = red;
 +                      dRgb[1] = green;
 +                      dRgb[2] = blue;
 +                      dRgb[3] = alpha;
 +                  }
 +                }
 +                r->image = image;
 +            } else {
 +                //error
 +            }
 +        }
 +            break;
 +        default:
 +            break;
 +        }
 +    }
  
 -    p->drawImage(dx, dy, shadowImage);
 -    p->fillRect(shadowRect, p->brush());
 +    return args.This();
  }
 +/*!
 +  \qmlclass QtQuick2::CanvasPixelArray
 +  The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
 +  See http://www.w3.org/TR/2dcontext/#canvaspixelarray for more details.
 +  */
  
 -void QSGContext2DPrivate::fillShadowPath(QPainter* p, const QPainterPath& path)
 +/*!
 +  \qmlproperty QtQuick2::CanvasPixelArray::length
 +  The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
 +  The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
 + */
 +v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
  {
 -    QRectF r = path.boundingRect();
 -    QImage img(r.size().width() + r.left() + 1,
 -               r.size().height() + r.top() + 1,
 -               QImage::Format_ARGB32);
 -    img.fill(0);
 -    QPainter tp(&img);
 -    tp.fillPath(path.translated(0, 0), p->brush());
 -    tp.end();
 +    QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
 +    if (!r || r->image.isNull()) return v8::Undefined();
  
 -    QImage shadowImage = makeShadowImage(QPixmap::fromImage(img));
 -    qreal dx = r.left() + (state.shadowOffsetX < 0? state.shadowOffsetX:0);
 -    qreal dy = r.top() + (state.shadowOffsetY < 0? state.shadowOffsetY:0);
 -
 -    p->drawImage(dx, dy, shadowImage);
 -    p->fillPath(path, p->brush());
 +    return v8::Integer::New(r->image.width() * r->image.height() * 4);
  }
  
 -void QSGContext2DPrivate::strokeShadowPath(QPainter* p, const QPainterPath& path)
 +v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
  {
 -    QRectF r = path.boundingRect();
 -    QImage img(r.size().width() + r.left() + 1,
 -               r.size().height() + r.top() + 1,
 -               QImage::Format_ARGB32);
 -    img.fill(0);
 -    QPainter tp(&img);
 -    tp.strokePath(path, p->pen());
 -    tp.end();
 -
 -    QImage shadowImage = makeShadowImage(QPixmap::fromImage(img));
 -    qreal dx = r.left() + (state.shadowOffsetX < 0? state.shadowOffsetX:0);
 -    qreal dy = r.top() + (state.shadowOffsetY < 0? state.shadowOffsetY:0);
 -    p->drawImage(dx, dy, shadowImage);
 -    p->strokePath(path, p->pen());
 -}
 +    QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
  
 -void QSGContext2DPrivate::clear()
 -{
 -    clearRect(0, 0, size.width(), size.height());
 +    if (r && index && index < r->image.width() * r->image.height() * 4) {
 +        const int w = r->image.width();
 +        const int h = r->image.height();
 +        const int row = (index / 4) / w;
 +        const int col = (index / 4) % w;
 +        const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
 +        pixel += col;
 +        switch (index % 4) {
 +        case 0:
 +            return v8::Integer::New(qRed(*pixel));
 +        case 1:
 +            return v8::Integer::New(qGreen(*pixel));
 +        case 2:
 +            return v8::Integer::New(qBlue(*pixel));
 +        case 3:
 +            return v8::Integer::New(qAlpha(*pixel));
 +        }
 +    }
 +    return v8::Undefined();
  }
  
 -void QSGContext2DPrivate::reset()
 +v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
  {
 -    stateStack.clear();
 -    state.matrix = QMatrix();
 -    state.clipPath = QPainterPath();
 -    state.strokeStyle = Qt::black;
 -    state.fillStyle = Qt::black;
 -    state.globalAlpha = 1.0;
 -    state.lineWidth = 1;
 -    state.lineCap = Qt::FlatCap;
 -    state.lineJoin = Qt::MiterJoin;
 -    state.miterLimit = 10;
 -    state.shadowOffsetX = 0;
 -    state.shadowOffsetY = 0;
 -    state.shadowBlur = 0;
 -    state.shadowColor = qRgba(0, 0, 0, 0);
 -    state.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
 -    state.font = QFont();
 -    state.textAlign = QSGContext2D::Start;
 -    state.textBaseline = QSGContext2D::Alphabetic;
 -    clear();
 -}
 +    QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
  
 +    const int v = value->Uint32Value();
 +    if (r && index > 0 && index < r->image.width() * r->image.height() * 4 && v > 0 && v <= 255) {
 +        const int w = r->image.width();
 +        const int h = r->image.height();
 +        const int row = (index / 4) / w;
 +        const int col = (index / 4) % w;
  
 -void QSGContext2DPrivate::updateMatrix(const QMatrix& m)
 -{
 -    commands.push_back(QSGContext2D::UpdateMatrix);
 -    matrixes.push_back(m);
 +        QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
 +        pixel += col;
 +        switch (index % 4) {
 +        case 0:
 +            *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
 +            break;
 +        case 1:
 +            *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
 +            break;
 +        case 2:
 +            *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
 +            break;
 +        case 3:
 +            *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
 +            break;
 +        }
 +    }
 +    return v8::Undefined();
  }
 +/*!
 +  \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
 +   Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
 +  */
 +/*!
 +  \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
 +   Creates a CanvasImageData object with the same dimensions as the argument.
 +  */
 +/*!
 +  \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
 +   Creates a CanvasImageData object with the given image loaded from \a imageUrl.
 +   Note:The \a imageUrl must be already loaded before this function call, if not, an empty
 +   CanvasImageData obect will be returned.
 +
 +   \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
 +  */
 +static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
 +{
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 +    CHECK_CONTEXT(r)
  
  
 +    QV8Engine *engine = V8ENGINE();
  
 +    if (args.Length() == 1) {
 +        if (args[0]->IsObject()) {
 +            v8::Local<v8::Object> imgData = args[0]->ToObject();
 +            QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
 +            if (pa) {
 +                qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
 +                qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
 +                return qt_create_image_data(w, h, engine, QImage());
 +            }
 +        } else if (args[0]->IsString()) {
 +            QImage image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
 +            return qt_create_image_data(image.width(), image.height(), engine, image);
 +        }
 +    } else if (args.Length() == 2) {
 +        qreal w = args[0]->NumberValue();
 +        qreal h = args[1]->NumberValue();
 +        if (w > 0 && h > 0)
 +            return qt_create_image_data(w, h, engine, QImage());
 +    }
 +    return v8::Undefined();
 +}
  
 -void QSGContext2DPrivate::save()
 +/*!
 +  \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
 +  Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
 +  */
 +static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
  {
 -    stateStack.push(state);
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 +    CHECK_CONTEXT(r)
 +
 +    QV8Engine *engine = V8ENGINE();
 +    if (args.Length() == 4) {
 +        qreal x = args[0]->NumberValue();
 +        qreal y = args[1]->NumberValue();
 +        qreal w = args[2]->NumberValue();
 +        qreal h = args[3]->NumberValue();
 +        QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
 +        if (image.format() != QImage::Format_ARGB32)
 +            image = image.convertToFormat(QImage::Format_ARGB32);
 +        v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
 +
 +        return imageData;
 +    }
 +    return v8::Null();
  }
  
 -void QSGContext2DPrivate::restore()
 +/*!
 +  \qmlmethod QtQuick2::Context2D putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
 +  Paints the data from the given ImageData object onto the canvas. If a dirty rectangle (\a dirtyX, \a dirtyY, \a dirtyWidth, \a dirtyHeight) is provided, only the pixels from that rectangle are painted.
 +  */
 +static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
  {
 -    if (!stateStack.isEmpty()) {
 -        bool update = false;
 -        QSGContext2D::State s = stateStack.pop();
 -        if (state.matrix != s.matrix) {
 -            updateMatrix(s.matrix);
 -            update = true;
 -        }
 +    QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
 +    CHECK_CONTEXT(r)
 +    if (args.Length() != 3 && args.Length() != 7)
 +        return v8::Undefined();
 +
 +    if (args[0]->IsNull() || !args[0]->IsObject()) {
 +        V8THROW_ERROR("Context2D::putImageData, the image data type mismatch");
 +    }
 +    qreal dx = args[1]->NumberValue();
 +    qreal dy = args[2]->NumberValue();
 +    qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
 +
 +    v8::Local<v8::Object> imageData = args[0]->ToObject();
 +    QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
 +    if (pixelArray) {
 +        w = imageData->Get(v8::String::New("width"))->NumberValue();
 +        h = imageData->Get(v8::String::New("height"))->NumberValue();
 +
 +        if (args.Length() == 7) {
 +            dirtyX = args[3]->NumberValue();
 +            dirtyY = args[4]->NumberValue();
 +            dirtyWidth = args[5]->NumberValue();
 +            dirtyHeight = args[6]->NumberValue();
 +            if (dirtyWidth < 0) {
 +                dirtyX = dirtyX+dirtyWidth;
 +                dirtyWidth = -dirtyWidth;
 +            }
  
 -        if (s.pen != state.pen) {
 -            commands.push_back(QSGContext2D::UpdatePen);
 -            pens.push_back(s.pen);
 -            update = true;
 -        }
 +            if (dirtyHeight < 0) {
 +                dirtyY = dirtyY+dirtyHeight;
 +                dirtyHeight = -dirtyHeight;
 +            }
  
 -        if (s.globalAlpha != state.globalAlpha) {
 -            commands.push_back(QSGContext2D::GlobalAlpha);
 -            reals.push_back(s.globalAlpha);
 -            update = true;
 -        }
 +            if (dirtyX < 0) {
 +                dirtyWidth = dirtyWidth+dirtyX;
 +                dirtyX = 0;
 +            }
  
 -        if (s.globalCompositeOperation != state.globalCompositeOperation) {
 -            commands.push_back(QSGContext2D::GlobalCompositeOperation);
 -            ints.push_back(s.globalCompositeOperation);
 -            update = true;
 -        }
 +            if (dirtyY < 0) {
 +                dirtyHeight = dirtyHeight+dirtyY;
 +                dirtyY = 0;
 +            }
  
 -        if (s.font != state.font) {
 -            commands.push_back(QSGContext2D::Font);
 -            fonts.push_back(s.font);
 -            update = true;
 -        }
 +            if (dirtyX+dirtyWidth > w) {
 +                dirtyWidth = w - dirtyX;
 +            }
  
 -        if (s.fillStyle != state.fillStyle) {
 -            commands.push_back(QSGContext2D::FillStyle);
 -            brushes.push_back(s.fillStyle);
 -            update = true;
 -        }
 +            if (dirtyY+dirtyHeight > h) {
 +                dirtyHeight = h - dirtyY;
 +            }
  
 -        if (s.clipPath != state.clipPath) {
 -            //commands.push_back(QSGContext2D::ClipPath);
 -            update = true;
 +            if (dirtyWidth <=0 || dirtyHeight <= 0)
 +                return args.This();
 +        } else {
 +            dirtyX = 0;
 +            dirtyY = 0;
 +            dirtyWidth = w;
 +            dirtyHeight = h;
          }
  
 -        if (s.textAlign != state.textAlign) {
 -            commands.push_back(QSGContext2D::TextAlign);
 -            update = true;
 -        }
 +        QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
 +        r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
 +    }
 +    return args.This();
 +}
  
 -        if (s.textBaseline != state.textBaseline) {
 -            commands.push_back(QSGContext2D::TextBaseline);
 -            update = true;
 -        }
 +/*!
 +  \qmlclass QtQuick2::CanvasGradient
 +    \inqmlmodule QtQuick 2
 +    \since QtQuick 2.0
 +    \brief The Context2D opaque CanvasGradient interface.
 +  */
  
 -        if (s.shadowBlur != state.shadowBlur
 -         || s.shadowColor != state.shadowColor
 -         || s.shadowOffsetX != state.shadowOffsetX
 -         || s.shadowOffsetY != state.shadowOffsetY) {
 -            update = true;
 +/*!
 +  \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
 +  Adds a color stop with the given color to the gradient at the given offset.
 +  0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
 +  */
 +static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
 +{
 +    QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
 +    if (!style)
 +        V8THROW_ERROR("Not a CanvasGradient object");
 +
 +    QV8Engine *engine = V8ENGINE();
 +
 +    if (args.Length() == 2) {
 +
 +        if (!style->brush.gradient())
 +            V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
 +        QGradient gradient = *(style->brush.gradient());
 +        qreal pos = args[0]->NumberValue();
 +        QColor color = qt_color_from_string(engine->toString(args[1]));
 +        if (pos < 0.0 || pos > 1.0) {
 +            //Throws an INDEX_SIZE_ERR exception
 +            V8THROW_ERROR("CanvasGradient: parameter offset out of range");
          }
  
 -        if (update)
 -            state = s;
 +        if (color.isValid()) {
 +            gradient.setColorAt(pos, color);
 +        } else {
 +            //Throws a SYNTAX_ERR exception
 +            V8THROW_ERROR("CanvasGradient: parameter color is not a valid color string");
 +        }
 +        style->brush = gradient;
      }
 +
 +    return args.This();
  }
  
 -void QSGContext2DPrivate::scale(qreal x, qreal y)
 +
 +void QSGContext2D::beginPath()
  {
 -    state.matrix.scale(x, y);
 -    updateMatrix(state.matrix);
 +    m_path = QPainterPath();
 +    m_path.setFillRule(state.fillRule);
  }
  
 -void QSGContext2DPrivate::rotate(qreal angle)
 +void QSGContext2D::closePath()
  {
 -    state.matrix.rotate(DEGREES(angle));
 -    updateMatrix(state.matrix);
 -}
 +    if (m_path.isEmpty())
 +        return;
  
 +    QRectF boundRect = m_path.boundingRect();
 +    if (boundRect.width() || boundRect.height())
 +        m_path.closeSubpath();
 +}
  
 -void QSGContext2DPrivate::translate(qreal x, qreal y)
 +void QSGContext2D::moveTo( qreal x, qreal y)
  {
 -    state.matrix.translate(x, y);
 -    updateMatrix(state.matrix);
 +    m_path.moveTo(state.matrix.map(QPointF(x, y)));
  }
  
 -void QSGContext2DPrivate::transform(
 -                                    qreal m11, qreal m12,
 -                                    qreal m21, qreal m22,
 -                                    qreal dx, qreal dy)
 +void QSGContext2D::lineTo( qreal x, qreal y)
  {
 -    QMatrix matrix(m11, m12, m21, m22, dx, dy);
 -    state.matrix *= matrix;
 -    updateMatrix(state.matrix);
 +    m_path.lineTo(state.matrix.map(QPointF(x, y)));
  }
  
 -void QSGContext2DPrivate::setTransform(
 -                                       qreal m11, qreal m12,
 -                                       qreal m21, qreal m22,
 -                                       qreal dx, qreal dy)
 +void QSGContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
 +                                           qreal x, qreal y)
  {
 -   QMatrix matrix(m11, m12, m21, m22, dx, dy);
 -   state.matrix = matrix;
 -   updateMatrix(state.matrix);
 +    m_path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
 +                      state.matrix.map(QPointF(x, y)));
  }
  
 -void QSGContext2DPrivate::clearRect(qreal x, qreal y,
 -                                    qreal w, qreal h)
 +void QSGContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
 +                                        qreal cp2x, qreal cp2y,
 +                                        qreal x, qreal y)
  {
 -    commands.push_back(QSGContext2D::ClearRect);
 -    reals.push_back(x);
 -    reals.push_back(y);
 -    reals.push_back(w);
 -    reals.push_back(h);
 +    m_path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
 +                       state.matrix.map(QPointF(cp2x, cp2y)),
 +                       state.matrix.map(QPointF(x, y)));
  }
  
 -void QSGContext2DPrivate::fillRect(qreal x, qreal y,
 -                                   qreal w, qreal h)
 +void QSGContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
  {
 -    QRectF rect;
 -    if (tileRect.isValid()) {
 -        rect = tileRect.intersect(QRect(x, y, w, h));
 -    } else {
 -        rect = QRectF(x, y, w, h);
 -    }
 +    QPointF p0(m_path.currentPosition());
  
 -    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());
 -    }
 -}
 +    QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
 +    QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
 +    float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
 +    float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
  
 -void QSGContext2DPrivate::strokeRect(qreal x, qreal y,
 -                                     qreal w, qreal h)
 -{
 -    QPainterPath p;
 -    p.addRect(x, y, w, h);
 +    double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
  
 -    if (tileRect.isValid()) {
 -        QPainterPath tr;
 -        tr.addRect(tileRect);
 -        p = p.intersected(tr);
 +    // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
 +    // We could have used areCollinear() here, but since we're reusing
 +    // the variables computed above later on we keep this logic.
 +    if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
 +        m_path.lineTo(p1);
 +        return;
      }
  
 -    if (!p.isEmpty()) {
 -        commands.push_back(QSGContext2D::Stroke);
 -        pathes.push_back(p);
 -    }
 -}
 +    float tangent = radius / tan(acos(cos_phi) / 2);
 +    float factor_p1p0 = tangent / p1p0_length;
 +    QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
  
 -void QSGContext2DPrivate::beginPath()
 -{
 -    path = QPainterPath();
 -}
 +    QPointF orth_p1p0(p1p0.y(), -p1p0.x());
 +    float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
 +    float factor_ra = radius / orth_p1p0_length;
  
 -void QSGContext2DPrivate::closePath()
 -{
 -    path.closeSubpath();
 -}
 +    // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
 +    double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
 +    if (cos_alpha < 0.f)
 +        orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
  
 -void QSGContext2DPrivate::moveTo( qreal x, qreal y)
 -{
 -    path.moveTo(state.matrix.map(QPointF(x, y)));
 +    QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
 +
 +    // calculate angles for addArc
 +    orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
 +    float sa = acos(orth_p1p0.x() / orth_p1p0_length);
 +    if (orth_p1p0.y() < 0.f)
 +        sa = 2 * Q_PI - sa;
 +
 +    // anticlockwise logic
 +    bool anticlockwise = false;
 +
 +    float factor_p1p2 = tangent / p1p2_length;
 +    QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
 +    QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
 +    float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
 +    float ea = acos(orth_p1p2.x() / orth_p1p2_length);
 +    if (orth_p1p2.y() < 0)
 +        ea = 2 * Q_PI - ea;
 +    if ((sa > ea) && ((sa - ea) < Q_PI))
 +        anticlockwise = true;
 +    if ((sa < ea) && ((ea - sa) > Q_PI))
 +        anticlockwise = true;
 +
 +    arc(p.x(), p.y(), radius, sa, ea, anticlockwise, false);
  }
  
 -void QSGContext2DPrivate::lineTo( qreal x, qreal y)
 +void QSGContext2D::arcTo(qreal x1, qreal y1,
 +                                qreal x2, qreal y2,
 +                                qreal radius)
  {
 -    path.lineTo(state.matrix.map(QPointF(x, y)));
 +    QPointF st  = state.matrix.map(QPointF(x1, y1));
 +    QPointF end = state.matrix.map(QPointF(x2, y2));
 +
 +    if (!m_path.elementCount()) {
 +        m_path.moveTo(st);
 +    } else if (st == m_path.currentPosition() || st == end || !radius) {
 +        m_path.lineTo(st);
 +    } else {
 +        addArcTo(st, end, radius);
 +    }
  }
  
 -void QSGContext2DPrivate::quadraticCurveTo(qreal cpx, qreal cpy,
 -                                           qreal x, qreal y)
 +void QSGContext2D::rect(qreal x, qreal y,
 +                               qreal w, qreal h)
  {
 -    path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
 -                      state.matrix.map(QPointF(x, y)));
 +    m_path.addPolygon(state.matrix.map(QRectF(x, y, w, h)));
  }
  
 -void QSGContext2DPrivate::bezierCurveTo(qreal cp1x, qreal cp1y,
 -                                        qreal cp2x, qreal cp2y,
 -                                        qreal x, qreal y)
 +void QSGContext2D::roundedRect(qreal x, qreal y,
 +                               qreal w, qreal h,
 +                               qreal xr, qreal yr)
  {
 -    path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
 -                       state.matrix.map(QPointF(cp2x, cp2y)),
 -                       state.matrix.map(QPointF(x, y)));
 +    QPainterPath path;
 +    path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
 +    m_path.addPath(state.matrix.map(path));
  }
  
 -void QSGContext2DPrivate::arcTo(qreal x1, qreal y1,
 -                                qreal x2, qreal y2,
 -                                qreal radius)
 +void QSGContext2D::ellipse(qreal x, qreal y,
 +                           qreal w, qreal h)
  {
 -    QPointF st  = state.matrix.map(QPoint(x1, y1));
 -    QPointF end = state.matrix.map(QPoint(x2, y2));
 -
 -    path.arcTo(st.x(), st.y(),
 -                     end.x()-st.x(), end.y()-st.y(),
 -                     radius, 90);
 +    QPainterPath path;
 +    path.addEllipse(x, y, w, h);
 +    m_path.addPath(state.matrix.map(path));
  }
  
 -void QSGContext2DPrivate::rect(qreal x, qreal y,
 -                               qreal w, qreal h)
 +void QSGContext2D::text(const QString& str, qreal x, qreal y)
  {
      QPainterPath path;
 -    path.addRect(QRectF(x, y, w, h));
 -    path.addPath(state.matrix.map(path));
 +    path.addText(x, y, state.font, str);
 +    m_path.addPath(state.matrix.map(path));
  }
  
 -void QSGContext2DPrivate::arc(qreal xc,
 -                              qreal yc,
 -                              qreal radius,
 -                              qreal sar,
 -                              qreal ear,
 -                              bool antiClockWise)
 +void QSGContext2D::arc(qreal xc,
 +                       qreal yc,
 +                       qreal radius,
 +                       qreal sar,
 +                       qreal ear,
 +                       bool antiClockWise,
 +                       bool transform)
  {
 -    QPainterPath p;
  
 +    if (transform) {
 +        QPointF point = state.matrix.map(QPointF(xc, yc));
 +        xc = point.x();
 +        yc = point.y();
 +    }
      //### HACK
  
      // In Qt we don't switch the coordinate system for degrees
      double ys     = yc - radius;
      double width  = radius*2;
      double height = radius*2;
 -
 -    if (!antiClockWise && (ea < sa)) {
 -        span += 360;
 -    } else if (antiClockWise && (sa < ea)) {
 -        span -= 360;
 +    if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
 +        // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
 +        // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
 +        // circumference of this circle.
 +        span = 360;
 +    else {
 +        if (!antiClockWise && (ea < sa)) {
 +            span += 360;
 +        } else if (antiClockWise && (sa < ea)) {
 +            span -= 360;
 +        }
 +        //### this is also due to switched coordinate system
 +        // we would end up with a 0 span instead of 360
 +        if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
 +              qFuzzyCompare(qAbs(span), 360))) {
 +            span   += ea - sa;
 +        }
 +        if (!m_path.elementCount())
 +            m_path.moveTo(xs, ys);
      }
  
 -    //### this is also due to switched coordinate system
 -    // we would end up with a 0 span instead of 360
 -    if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
 -          qFuzzyCompare(qAbs(span), 360))) {
 -        span   += ea - sa;
 +
 +    if (transform) {
 +        QPointF currentPos = m_path.currentPosition();
 +        QPointF startPos = QPointF(xc + radius  * qCos(sar),
 +                                   yc - radius  * qSin(sar));
 +        if (currentPos != startPos)
 +            m_path.lineTo(startPos);
      }
  
 -    p.moveTo(QPointF(xc + radius  * qCos(sar),
 -                        yc - radius  * qSin(sar)));
 +    m_path.arcTo(xs, ys, width, height, sa, span);
 +}
  
 -    p.arcTo(xs, ys, width, height, sa, span);
 -
 -    path.addPath(state.matrix.map(p));
 -}
 -
 -void QSGContext2DPrivate::fill()
 -{
 -    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()
 -{
 -    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);
 -}
 -
 -void QSGContext2DPrivate::setGlobalAlpha( qreal alpha)
 -{
 -    state.globalAlpha = alpha;
 -    commands.push_back(QSGContext2D::GlobalAlpha);
 -    reals.push_back(state.globalAlpha);
 -}
 -
 -void QSGContext2DPrivate::setGlobalCompositeOperation( const QString &op)
 -{
 -    state.globalCompositeOperation = compositeOperatorFromString(op);
 -    commands.push_back(QSGContext2D::GlobalCompositeOperation);
 -    ints.push_back(state.globalCompositeOperation);
 -}
 -
 -void QSGContext2DPrivate::setStrokeStyle( const QVariant &style)
 -{
 -    QSGCanvasGradient *gradient= qobject_cast<QSGCanvasGradient*>(style.value<QObject*>());
 -    QBrush b;
 -    if (gradient) {
 -        b = gradient->value();
 -    } else {
 -        b =  colorFromString(style.toString());
 -    }
 -
 -    if (state.strokeStyle != b) {
 -        state.strokeStyle = b;
 -        state.pen.setBrush(state.strokeStyle);
 -        commands.push_back(QSGContext2D::UpdatePen);
 -        pens.push_back(state.pen);
 -    }
 -}
 -void QSGContext2DPrivate::setStrokeColor(const QColor& color)
 -{
 -    if (state.strokeStyle != color) {
 -        state.strokeStyle = color;
 -        commands.push_back(QSGContext2D::UpdatePen);
 -        QPen pen;
 -        pen.setBrush(state.strokeStyle);
 -        pens.push_back(pen);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setFillColor(const QColor& color)
 -{
 -    if (state.fillStyle != color) {
 -        state.fillStyle = color;
 -        commands.push_back(QSGContext2D::UpdateBrush);
 -        brushes.push_back(state.fillStyle);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setFillStyle( const QVariant &style)
 -{
 -    QSGCanvasGradient *gradient= qobject_cast<QSGCanvasGradient*>(style.value<QObject*>());
 -    QBrush b;
 -    if (gradient) {
 -        b = gradient->value();
 -    } else {
 -        b =  colorFromString(style.toString());
 -    }
 -
 -    if (state.fillStyle != b) {
 -        state.fillStyle = b;
 -        commands.push_back(QSGContext2D::UpdateBrush);
 -        brushes.push_back(b);
 -    }
 -}
 -
 -
 -void QSGContext2DPrivate::setLineWidth( qreal w)
 -{
 -    if (state.lineWidth != w) {
 -        state.pen.setWidthF(w);
 -        state.lineWidth = w;
 -        commands.push_back(QSGContext2D::UpdatePen);
 -        pens.push_back(state.pen);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setLineCap( const QString& cap)
 -{
 -    Qt::PenCapStyle style;
 -    if (cap == QLatin1String("round"))
 -        style = Qt::RoundCap;
 -    else if (cap == QLatin1String("square"))
 -        style = Qt::SquareCap;
 -    else //if (capString == "butt")
 -        style = Qt::FlatCap;
 -
 -
 -    if (state.lineCap != style) {
 -        state.pen.setCapStyle(style);
 -        state.lineCap = style;
 -        commands.push_back(QSGContext2D::UpdatePen);
 -        pens.push_back(state.pen);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setLineJoin( const QString& join)
 -{
 -    Qt::PenJoinStyle style;
 -    if (join == QLatin1String("round"))
 -        style = Qt::RoundJoin;
 -    else if (join == QLatin1String("bevel"))
 -        style = Qt::BevelJoin;
 -    else //if (joinString == "miter")
 -        style = Qt::MiterJoin;
 -    if (state.lineJoin != style) {
 -        state.lineJoin = style;
 -        state.pen.setJoinStyle(style);
 -        commands.push_back(QSGContext2D::UpdatePen);
 -        pens.push_back(state.pen);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setMiterLimit( qreal limit)
 -{
 -    if (state.miterLimit != limit) {
 -        state.pen.setMiterLimit(limit);
 -        state.miterLimit = limit;
 -        commands.push_back(QSGContext2D::UpdatePen);
 -        pens.push_back(state.pen);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setShadowOffsetX( qreal x)
 -{
 -    if (state.shadowOffsetX != x) {
 -        state.shadowOffsetX = x;
 -        commands.push_back(QSGContext2D::ShadowOffsetX);
 -        reals.push_back(x);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setShadowOffsetY( qreal y)
 -{
 -    if (state.shadowOffsetY != y) {
 -        state.shadowOffsetY = y;
 -        commands.push_back(QSGContext2D::ShadowOffsetY);
 -        reals.push_back(y);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setShadowBlur( qreal b)
 -{
 -    if (state.shadowBlur != b) {
 -        state.shadowBlur = b;
 -        commands.push_back(QSGContext2D::ShadowBlur);
 -        reals.push_back(b);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setShadowColor( const QString&  color)
 -{
 -    QColor c = colorFromString(color);
 -    if (state.shadowColor != c) {
 -        state.shadowColor = c;
 -        commands.push_back(QSGContext2D::ShadowColor);
 -        colors.push_back(c);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setFont( const QString&  fontString)
 -{
 -   QFont font;
 -    // ### this is simplified and incomplete
 -   // ### TODO:get code from Qt webkit
 -    QStringList tokens = fontString.split(QLatin1String(" "));
 -    foreach (const QString &token, tokens) {
 -        if (token == QLatin1String("italic"))
 -            font.setItalic(true);
 -        else if (token == QLatin1String("bold"))
 -            font.setBold(true);
 -        else if (token.endsWith(QLatin1String("px"))) {
 -            QString number = token;
 -            number.remove(QLatin1String("px"));
 -            font.setPointSizeF(number.trimmed().toFloat());
 -        } else
 -            font.setFamily(token);
 -    }
 -
 -    if (state.font != font) {
 -        state.font = font;
 -        commands.push_back(QSGContext2D::Font);
 -        fonts.push_back(font);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setTextBaseline( const QString&  baseline)
 -{
 -    QSGContext2D::TextBaseLineType tbl;
 -     if (baseline==QLatin1String("alphabetic"))
 -        tbl = QSGContext2D::Alphabetic;
 -    else if (baseline == QLatin1String("hanging"))
 -        tbl = QSGContext2D::Hanging;
 -    else if (baseline == QLatin1String("top"))
 -        tbl = QSGContext2D::Top;
 -    else if (baseline == QLatin1String("bottom"))
 -        tbl = QSGContext2D::Bottom;
 -    else if (baseline == QLatin1String("middle"))
 -        tbl = QSGContext2D::Middle;
 -    else {
 -        tbl = QSGContext2D::Alphabetic;
 -        Q_Q(QSGContext2D);
 -        qmlInfo(q) << "QSGContext2D: invalid baseline:" << baseline;
 -    }
 -    if (state.textBaseline != tbl) {
 -        state.textBaseline = tbl;
 -        commands.push_back(QSGContext2D::TextBaseline);
 -        ints.push_back(tbl);
 -    }
 -}
 -
 -void QSGContext2DPrivate::setTextAlign(const QString&  align)
 -{
 -    QSGContext2D::TextAlignType ta;
 -     if (align==QLatin1String("start"))
 -        ta = QSGContext2D::Start;
 -    else if (align == QLatin1String("end"))
 -        ta = QSGContext2D::End;
 -    else if (align == QLatin1String("left"))
 -        ta = QSGContext2D::Left;
 -    else if (align == QLatin1String("right"))
 -        ta = QSGContext2D::Right;
 -    else if (align == QLatin1String("center"))
 -        ta = QSGContext2D::Center;
 -    else {
 -        ta = QSGContext2D::Start;
 -        Q_Q(QSGContext2D);
 -        qmlInfo(q)  << "QSGContext2D: invalid text align:" << align;
 -    }
 -     if (state.textAlign != ta) {
 -         state.textAlign = ta;
 -         commands.push_back(QSGContext2D::TextAlign);
 -         ints.push_back(ta);
 -     }
 -}
 -
 -void QSGContext2DPrivate::fillText(const QString&  text, qreal x, qreal y)
 -{
 -    commands.push_back(QSGContext2D::FillText);
 -    strings.push_back(text);
 -    reals.push_back(x);
 -    reals.push_back(y);
 -    ints.push_back(state.textAlign);
 -    ints.push_back(state.textBaseline);
 -}
 -
 -
 -void QSGContext2DPrivate::strokeText( const QString&  text, qreal x, qreal y)
 -{
 -    commands.push_back(QSGContext2D::StrokeText);
 -    strings.push_back(text);
 -    reals.push_back(x);
 -    reals.push_back(y);
 -    ints.push_back(state.textAlign);
 -    ints.push_back(state.textBaseline);
 -}
 -
 -void QSGContext2DPrivate::drawImage(const QString& url, qreal dx, qreal dy)
 -{
 -    commands.push_back(QSGContext2D::DrawImage1);
 -    strings.push_back(url);
 -    reals.push_back(dx);
 -    reals.push_back(dy);
 -}
 -
 -void QSGContext2DPrivate::drawImage(const QString& url, qreal dx, qreal dy, qreal dw, qreal dh)
 -{
 -    commands.push_back(QSGContext2D::DrawImage2);
 -    strings.push_back(url);
 -    reals.push_back(dx);
 -    reals.push_back(dy);
 -    reals.push_back(dw);
 -    reals.push_back(dh);
 -}
 -
 -void QSGContext2DPrivate::drawImage(const QString& url, qreal sx, qreal sy, qreal sw, qreal sh, qreal dx, qreal dy, qreal dw, qreal dh)
 -{
 -    commands.push_back(QSGContext2D::DrawImage3);
 -    strings.push_back(url);
 -    reals.push_back(sx);
 -    reals.push_back(sy);
 -    reals.push_back(sw);
 -    reals.push_back(sh);
 -    reals.push_back(dx);
 -    reals.push_back(dy);
 -    reals.push_back(dw);
 -    reals.push_back(dh);
 -}
 -
 -QList<int> QSGContext2DPrivate::getImageData(qreal sx, qreal sy, qreal sw, qreal sh)
 -{
 -    Q_Q(QSGContext2D);
 -    waitingForPainting = true;
 -    commands.push_back(QSGContext2D::GetImageData);
 -    reals.push_back(sx);
 -    reals.push_back(sy);
 -    reals.push_back(sw);
 -    reals.push_back(sh);
 -    q->sync();
 -   return imageData;
 -}
 -
 -void QSGContext2DPrivate::putImageData(const QVariantList& imageData, qreal dx, qreal dy, qreal w, qreal h)
 -{
 -    QImage image = cachedImage.copy(dx, dy, w, h);
 -    uchar* data = image.bits();
 -    int i = 0;
 -    while(i< imageData.size() && i < image.byteCount()) {
 -        //the stored order in QImage:BGRA
 -        //the stored order in Canvas:RGBA
 -        *(data+i)   = imageData[i+2].toInt();//B
 -        *(data+i+1) = imageData[i+1].toInt();//G
 -        *(data+i+2) = imageData[i].toInt();//R
 -        *(data+i+3) = imageData[i+3].toInt();//A
 -        i+=4;
 -    }
 -    commands.push_back(QSGContext2D::PutImageData);
 -    images.push_back(image);
 -    reals.push_back(dx);
 -    reals.push_back(dy);
 -}
 -
 -void QSGContext2D::save()
 -{
 -    Q_D(QSGContext2D);
 -    d->save();
 -}
 -
 -
 -void QSGContext2D::restore()
 -{
 -    Q_D(QSGContext2D);
 -    d->restore();
 -}
 -
 -
 -void QSGContext2D::scale(qreal x, qreal y)
 -{
 -    Q_D(QSGContext2D);
 -    d->scale(x, y);
 -}
 -
 -
 -void QSGContext2D::rotate(qreal angle)
 -{
 -    Q_D(QSGContext2D);
 -    d->rotate(angle);
 -}
 -
 -
 -void QSGContext2D::translate(qreal x, qreal y)
 -{
 -    Q_D(QSGContext2D);
 -    d->translate(x, y);
 -}
 -
 -void QSGContext2D::transform(qreal m11, qreal m12, qreal m21, qreal m22,
 -                          qreal dx, qreal dy)
 -{
 -    Q_D(QSGContext2D);
 -    d->transform(m11, m12, m21, m22, dx, dy);
 -}
 -
 -
 -void QSGContext2D::setTransform(qreal m11, qreal m12, qreal m21, qreal m22,
 -                             qreal dx, qreal dy)
 -{
 -    Q_D(QSGContext2D);
 -    d->setTransform(m11, m12, m21, m22, dx, dy);
 -}
 -
 -QString QSGContext2D::globalCompositeOperation() const
 -{
 -    Q_D(const QSGContext2D);
 -    return compositeOperatorToString(d->state.globalCompositeOperation);
 -}
 -
 -void QSGContext2D::setGlobalCompositeOperation(const QString &op)
 -{
 -    Q_D(QSGContext2D);
 -    d->setGlobalCompositeOperation(op);
 -}
 -
 -QVariant QSGContext2D::strokeStyle() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.strokeStyle;
 -}
 -
 -void QSGContext2D::setStrokeStyle(const QVariant &style)
 -{
 -    Q_D(QSGContext2D);
 -    d->setStrokeStyle(style);
 -}
 -
 -QVariant QSGContext2D::fillStyle() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.fillStyle;
 -}
 -
 -QColor QSGContext2D::strokeColor() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.strokeStyle.color();
 -}
 -
 -QColor QSGContext2D::fillColor() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.fillStyle.color();
 -}
 -
 -void QSGContext2D::setFillStyle(const QVariant &style)
 -{
 -    Q_D(QSGContext2D);
 -    d->setFillStyle(style);
 -}
 -void QSGContext2D::setStrokeColor(const QColor& color)
 -{
 -    Q_D(QSGContext2D);
 -    d->setStrokeColor(color);
 -}
 -
 -void QSGContext2D::setFillColor(const QColor& color)
 -{
 -    Q_D(QSGContext2D);
 -    d->setFillColor(color);
 -}
 -
 -qreal QSGContext2D::globalAlpha() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.globalAlpha;
 -}
 -
 -void QSGContext2D::setGlobalAlpha(qreal alpha)
 -{
 -    Q_D(QSGContext2D);
 -    d->setGlobalAlpha(alpha);
 -}
 -
 -QSGImage *QSGContext2D::createImage(const QString &url)
 -{
 -    Q_D(QSGContext2D);
 -//### cache image
 -    QSGImage* img = new QSGImage(d->canvas);
 -    img->setSource(QUrl(url));
 -    return img;
 -}
 -
 -QSGCanvasGradient *QSGContext2D::createLinearGradient(qreal x0, qreal y0,
 -                                                qreal x1, qreal y1)
 -{
 -    QLinearGradient g(x0, y0, x1, y1);
 -    return new QSGCanvasGradient(g);
 -}
 -
 -
 -QSGCanvasGradient *QSGContext2D::createRadialGradient(qreal x0, qreal y0,
 -                                                qreal r0, qreal x1,
 -                                                qreal y1, qreal r1)
 -{
 -    QRadialGradient g(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
 -    return new QSGCanvasGradient(g);
 -}
 -
 -qreal QSGContext2D::lineWidth() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.lineWidth;
 -}
 -
 -void QSGContext2D::setLineWidth(qreal w)
 -{
 -    Q_D(QSGContext2D);
 -    d->setLineWidth(w);
 -}
 -
 -QString QSGContext2D::lineCap() const
 -{
 -    Q_D(const QSGContext2D);
 -    switch(d->state.lineCap) {
 -    case Qt::RoundCap:
 -        return QLatin1String("round");
 -    case Qt::FlatCap:
 -        return QLatin1String("butt");
 -    case Qt::SquareCap:
 -        return QLatin1String("square");
 -    default:
 -        break;
 -    }
 -    return QLatin1String("");
 -}
 -
 -void QSGContext2D::setLineCap(const QString &capString)
 -{
 -    Q_D(QSGContext2D);
 -    d->setLineCap(capString);
 -}
 -
 -QString QSGContext2D::lineJoin() const
 -{
 -    Q_D(const QSGContext2D);
 -    switch (d->state.lineJoin) {
 -    case Qt::RoundJoin:
 -        return QLatin1String("round");
 -    case Qt::BevelJoin:
 -        return QLatin1String("bevel");
 -    case Qt::MiterJoin:
 -        return QLatin1String("miter");
 -    default:
 -        break;
 -    }
 -    return QLatin1String("");
 -}
 -
 -void QSGContext2D::setLineJoin(const QString &joinString)
 -{
 -    Q_D(QSGContext2D);
 -    d->setLineJoin(joinString);
 -}
 -
 -qreal QSGContext2D::miterLimit() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.miterLimit;
 -}
 -
 -void QSGContext2D::setMiterLimit(qreal m)
 -{
 -    Q_D(QSGContext2D);
 -    d->setMiterLimit(m);
 -}
 -
 -void QSGContext2D::setShadowOffsetX(qreal x)
 -{
 -    Q_D(QSGContext2D);
 -    d->setShadowOffsetX(x);
 -}
 -
 -void QSGContext2D::setShadowOffsetY(qreal y)
 -{
 -    Q_D(QSGContext2D);
 -    d->setShadowOffsetY(y);
 -}
 -
 -void QSGContext2D::setShadowBlur(qreal b)
 -{
 -    Q_D(QSGContext2D);
 -    d->setShadowBlur(b);
 -}
 -
 -void QSGContext2D::setShadowColor(const QString &str)
 -{
 -    Q_D(QSGContext2D);
 -    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 (QDeclarativeSvgParser::parsePathDataFast(pathString, path)) {
 -        return new QSGCanvasPath(path, this);
 -    }
 -    return 0;
 -}
 -
 -QString QSGContext2D::textBaseline() const
 -{
 -    Q_D(const QSGContext2D);
 -    switch(d->state.textBaseline) {
 -    case QSGContext2D::Alphabetic:
 -        return QLatin1String("alphabetic");
 -    case QSGContext2D::Hanging:
 -        return QLatin1String("hanging");
 -    case QSGContext2D::Top:
 -        return QLatin1String("top");
 -    case QSGContext2D::Bottom:
 -        return QLatin1String("bottom");
 -    case QSGContext2D::Middle:
 -        return QLatin1String("middle");
 -    default:
 -        break;
 -    }
 -    return QLatin1String("alphabetic");
 -}
 -
 -void QSGContext2D::setTextBaseline(const QString &baseline)
 -{
 -    Q_D(QSGContext2D);
 -    d->setTextBaseline(baseline);
 -}
 -
 -QString QSGContext2D::textAlign() const
 -{
 -    Q_D(const QSGContext2D);
 -    switch(d->state.textAlign) {
 -    case QSGContext2D::Start:
 -        return QLatin1String("start");
 -   case QSGContext2D::End:
 -        return QLatin1String("end");
 -   case QSGContext2D::Left:
 -        return QLatin1String("left");
 -   case QSGContext2D::Right:
 -        return QLatin1String("right");
 -   case QSGContext2D::Center:
 -        return QLatin1String("center");
 -    default:
 -        break;
 -    }
 -    return QLatin1String("start");
 -}
 -
 -void QSGContext2D::setTextAlign(const QString &align)
 -{
 -    Q_D(QSGContext2D);
 -    d->setTextAlign(align);
 -
 -    d->commands.push_back(QSGContext2D::TextAlign);
 -    d->ints.push_back(d->state.textAlign);
 -}
 -
 -void QSGContext2D::setFont(const QString &fontString)
 -{
 -    Q_D(QSGContext2D);
 -    d->setFont(fontString);
 -}
 -
 -QString QSGContext2D::font() const
 -{
 -    //### TODO
 -    Q_D(const QSGContext2D);
 -    return d->state.font.toString();
 -}
 -
 -qreal QSGContext2D::shadowOffsetX() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.shadowOffsetX;
 -}
 -
 -qreal QSGContext2D::shadowOffsetY() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.shadowOffsetY;
 -}
 -
 -
 -qreal QSGContext2D::shadowBlur() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.shadowBlur;
 -}
 -
 -
 -QString QSGContext2D::shadowColor() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.shadowColor.name();
 -}
 -
 -
 -void QSGContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
 -{
 -    Q_D(QSGContext2D);
 -    d->clearRect(x, y, w, h);
 -}
 -
 -void QSGContext2D::fillRect(qreal x, qreal y, qreal w, qreal h)
 -{
 -    Q_D(QSGContext2D);
 -    d->fillRect(x, y, w, h);
 -}
 -
 -int QSGContext2DPrivate::baseLineOffset(QSGContext2D::TextBaseLineType value, const QFontMetrics &metrics)
 +int baseLineOffset(QSGContext2D::TextBaseLineType value, const QFontMetrics &metrics)
  {
      int offset = 0;
      switch (value) {
 -    case QSGContext2D::Top:
 +    case QSGContext2D::QSGContext2D::Top:
          break;
 -    case QSGContext2D::Alphabetic:
 -    case QSGContext2D::Middle:
 -    case QSGContext2D::Hanging:
 +    case QSGContext2D::QSGContext2D::Alphabetic:
 +    case QSGContext2D::QSGContext2D::Middle:
 +    case QSGContext2D::QSGContext2D::Hanging:
          offset = metrics.ascent();
          break;
 -    case QSGContext2D::Bottom:
 +    case QSGContext2D::QSGContext2D::Bottom:
          offset = metrics.height();
         break;
      }
      return offset;
  }
  
 -int QSGContext2DPrivate::textAlignOffset(QSGContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
 +static int textAlignOffset(QSGContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
  {
      int offset = 0;
      if (value == QSGContext2D::Start)
 -        value = qApp->layoutDirection() == Qt::LeftToRight ? QSGContext2D::Left : QSGContext2D::Right;
 +        value = QApplication::layoutDirection() == Qt::LeftToRight ? QSGContext2D::Left : QSGContext2D::Right;
      else if (value == QSGContext2D::End)
 -        value = qApp->layoutDirection() == Qt::LeftToRight ? QSGContext2D::Right: QSGContext2D::Left;
 +        value = QApplication::layoutDirection() == Qt::LeftToRight ? QSGContext2D::Right: QSGContext2D::Left;
      switch (value) {
 -    case QSGContext2D::Center:
 +    case QSGContext2D::QSGContext2D::Center:
          offset = metrics.width(text)/2;
          break;
 -    case QSGContext2D::Right:
 +    case QSGContext2D::QSGContext2D::Right:
          offset = metrics.width(text);
 -    case QSGContext2D::Left:
 +    case QSGContext2D::QSGContext2D::Left:
      default:
          break;
      }
      return offset;
  }
  
 -void QSGContext2D::fillText(const QString &text, qreal x, qreal y)
 -{
 -    Q_D(QSGContext2D);
 -    d->fillText(text, x, y);
 -}
 -
 -void QSGContext2D::strokeText(const QString &text, qreal x, qreal y)
 -{
 -    Q_D(QSGContext2D);
 -    d->strokeText(text, x, y);
 -}
 -
 -void QSGContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
 -{
 -    Q_D(QSGContext2D);
 -    d->strokeRect(x, y, w, h);
 -}
 -
 -void QSGContext2D::beginPath()
 -{
 -    Q_D(QSGContext2D);
 -    d->beginPath();
 -}
 -
 -
 -void QSGContext2D::closePath()
 -{
 -    Q_D(QSGContext2D);
 -    d->closePath();
 -}
 -
 -
 -void QSGContext2D::moveTo(qreal x, qreal y)
 -{
 -    Q_D(QSGContext2D);
 -    d->moveTo(x, y);
 -}
 -
 -
 -void QSGContext2D::lineTo(qreal x, qreal y)
 -{
 -    Q_D(QSGContext2D);
 -    d->lineTo(x, y);
 -}
 -
 -
 -void QSGContext2D::quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y)
 -{
 -    Q_D(QSGContext2D);
 -    d->quadraticCurveTo(cpx, cpy, x, y);
 -}
 -
 -
 -void QSGContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
 -                              qreal cp2x, qreal cp2y, qreal x, qreal y)
 -{
 -    Q_D(QSGContext2D);
 -    d->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
 -}
 -
 -
 -void QSGContext2D::arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius)
 -{
 -    Q_D(QSGContext2D);
 -    d->arcTo(x1, y1, x2, y2, radius);
 -}
 -
 -
 -void QSGContext2D::rect(qreal x, qreal y, qreal w, qreal h)
 -{
 -    Q_D(QSGContext2D);
 -    d->rect(x, y, w, h);
 -}
 -
 -void QSGContext2D::arc(qreal xc, qreal yc, qreal radius,
 -                    qreal sar, qreal ear,
 -                    bool anticlockwise)
 -{
 -    Q_D(QSGContext2D);
 -    d->arc(xc, yc, radius, sar, ear, anticlockwise);
 -}
 -
  
 -void QSGContext2D::fill()
 +QImage QSGContext2D::createImage(const QUrl& url)
  {
 -    Q_D(QSGContext2D);
 -    d->fill();
 +    return m_canvas->loadedImage(url);
  }
  
 -
 -void QSGContext2D::stroke()
 +QPainterPath QSGContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
  {
 -    Q_D(QSGContext2D);
 -    d->stroke();
 -}
 +    const QFontMetrics metrics(state.font);
 +    int yoffset = baseLineOffset(static_cast<QSGContext2D::TextBaseLineType>(state.textBaseline), metrics);
 +    int xoffset = textAlignOffset(static_cast<QSGContext2D::TextAlignType>(state.textAlign), metrics, text);
  
 +    QPainterPath textPath;
  
 -void QSGContext2D::clip()
 -{
 -    Q_D(QSGContext2D);
 -    d->clip();
 +    textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
 +    textPath = state.matrix.map(textPath);
 +    return textPath;
  }
  
  
  bool QSGContext2D::isPointInPath(qreal x, qreal y) const
  {
 -    Q_D(const QSGContext2D);
 -    return d->path.contains(QPointF(x, y));
 +    return m_path.contains(QPointF(x, y));
  }
  
 -void QSGContext2D::setPathString(const QString& path)
 +QSGContext2D::QSGContext2D(QSGCanvasItem* item)
 +    : m_canvas(item)
 +    , m_buffer(new QSGContext2DCommandBuffer)
 +    , m_v8engine(0)
  {
 -    Q_D(QSGContext2D);
 -    d->path = QPainterPath();
 -    QDeclarativeSvgParser::parsePathDataFast(path, d->path);
 +    reset();
  }
  
 -QList<int> QSGContext2D::getImageData(qreal sx, qreal sy, qreal sw, qreal sh)
 -{
 -    Q_D(QSGContext2D);
 -    return d->getImageData(sx, sy, sw, sh);
 -}
 -
 -void QSGContext2D::putImageData(const QVariant& imageData, qreal x, qreal y, qreal w, qreal h)
 -{
 -    Q_D(QSGContext2D);
 -    return d->putImageData(imageData.toList(), x, y, w, h);
 -}
 -
 -QSGContext2D::QSGContext2D(QObject *parent)
 -    : QObject(*(new QSGContext2DPrivate()), parent)
 -{
 -    Q_D(QSGContext2D);
 -    d->canvas = qobject_cast<QSGCanvasItem*>(parent);
 -}
 -
 -QSGContext2D::QSGContext2D(QSGContext2D *orig, QSGContext2DWorkerAgent* agentData)
 -    : QObject(*(new QSGContext2DPrivate()), 0)
 -{
 -    Q_D(QSGContext2D);
 -    d->agent = 0;
 -    d->agentData = agentData;
 -    if (d->agentData) {
 -        d->agentData->orig = orig;
 -    }
 -    d->canvas = qobject_cast<QSGCanvasItem*>(orig);
 -}
 -
 -QSGCanvasItem*  QSGContext2D::canvas() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->canvas;
 -}
  QSGContext2D::~QSGContext2D()
  {
 -    Q_D(QSGContext2D);
 -    if (d->agent) {
 -        d->agentData->syncDone.wakeAll();
 -        d->agent->release();
 -    }
 -}
 -
 -bool QSGContext2D::isDirty() const
 -{
 -    Q_D(const QSGContext2D);
 -    return !d->commands.isEmpty();
  }
  
  v8::Handle<v8::Object> QSGContext2D::v8value() const
  {
 -    Q_D(const QSGContext2D);
 -    return d->v8value;
 +    return m_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::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("resetTransform"), V8FUNCTION(ctx2d_resetTransform, 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->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, 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("fillRule"), ctx2d_fillRule, ctx2d_fillRule_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("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->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_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("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("roundedRect "), V8FUNCTION(ctx2d_roundedRect, engine));
 +    ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
 +    ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, 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->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
 +    ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
 +    ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, 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("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);
 -
 -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;
 +    constructorContext = qPersistentNew(ft->GetFunction());
  
 -        qPersistentDispose(d->v8value);
 +    v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
 +    ftGradient->InstanceTemplate()->SetHasExternalResource(true);
 +    ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
 +    constructorGradient = qPersistentNew(ftGradient->GetFunction());
  
 -        if (d->v8engine == 0)
 -            return;
 +    v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
 +    ftPattern->InstanceTemplate()->SetHasExternalResource(true);
 +    constructorPattern = qPersistentNew(ftPattern->GetFunction());
  
 -        QSGContext2DEngineData *ed = engineData(engine);
 -        d->v8value = qPersistentNew(ed->constructor->NewInstance());
 -        QV8Context2DResource *r = new QV8Context2DResource(engine);
 -        r->context = this;
 -        d->v8value->SetExternalResource(r);
 -    }
 -}
 +    v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
 +    ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
 +    ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
 +    ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
 +    constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
  
 -bool QSGContext2D::valid() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->valid;
 +    v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
 +    ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
 +    ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
 +    ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
 +    ftImageData->PrototypeTemplate()->Set(v8::String::New("mirror"), V8FUNCTION(ctx2d_imageData_mirror, engine));
 +    ftImageData->PrototypeTemplate()->Set(v8::String::New("filter"), V8FUNCTION(ctx2d_imageData_filter, engine));
 +    ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
 +    constructorImageData = qPersistentNew(ftImageData->GetFunction());
  }
  
 -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()
 +QSGContext2DEngineData::~QSGContext2DEngineData()
  {
 -    Q_D(QSGContext2D);
 -    Q_ASSERT(d->agentData);
 -    d->agentData->ref.ref();
 +    qPersistentDispose(constructorContext);
 +    qPersistentDispose(constructorGradient);
 +    qPersistentDispose(constructorPattern);
 +    qPersistentDispose(constructorImageData);
 +    qPersistentDispose(constructorPixelArray);
  }
  
 -void QSGContext2D::release()
 +void QSGContext2D::popState()
  {
 -    Q_D(QSGContext2D);
 -    Q_ASSERT(d->agentData);
 -    if (!d->agentData->ref.deref()) {
 -        deleteLater();
 -    }
 -}
 +    if (m_stateStack.isEmpty())
 +        return;
  
 -void QSGContext2D::processCommands(const QJSValue& commands)
 -{
 -#ifdef QSGCANVASITEM_DEBUG
 -    QElapsedTimer t;
 -    t.start();
 -#endif
 -    int ii = 0;
 -    if (commands.isArray()) {
 -        QJSValue cmd = commands.property(ii);
 -        while(cmd.isValid()) {
 -            processCommand(cmd);
 -            ii++;
 -            cmd = commands.property(ii);
 -        }
 -    }
 +    QSGContext2D::State newState = m_stateStack.pop();
  
 -#ifdef QSGCANVASITEM_DEBUG
 -    qDebug() << "processed" << ii << "commands in " << t.nsecsElapsed() << "nsecs";
 -#endif
 -    sync();
 -}
 +    if (state.matrix != newState.matrix)
 +        buffer()->updateMatrix(newState.matrix);
  
 -void QSGContext2D::sync()
 -{
 -    Q_D(QSGContext2D);
 +    if (newState.globalAlpha != state.globalAlpha)
 +        buffer()->setGlobalAlpha(newState.globalAlpha);
  
 -#ifdef QSGCANVASITEM_DEBUG
 -    QElapsedTimer t;
 -    t.start();
 -#endif
 -    if (d->agentData) {
 -        if (d->agentData->ref == 1) return;
 +    if (newState.globalCompositeOperation != state.globalCompositeOperation)
 +        buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
  
 -        Sync *s = new Sync;
 -        s->data = d->agentData;
 +    if (newState.fillStyle != state.fillStyle)
 +        buffer()->setFillStyle(newState.fillStyle);
  
 -        d->agentData->mutex.lock();
 -        QCoreApplication::postEvent(this, s);
 -        d->agentData->syncDone.wait(&d->agentData->mutex);
 -        d->agentData->mutex.unlock();
 -    } else {
 -        //qmlInfo(this) << "Context2D sync() can only be called from a WorkerScript;";
 -        emit changed();
 -    }
 +    if (newState.strokeStyle != state.strokeStyle)
 +        buffer()->setStrokeStyle(newState.strokeStyle);
  
 -#ifdef QSGCANVASITEM_DEBUG
 -    qDebug() << "syncing time:" << t.nsecsElapsed();
 -#endif
 -}
 +    if (newState.lineWidth != state.lineWidth)
 +        buffer()->setLineWidth(newState.lineWidth);
  
 +    if (newState.lineCap != state.lineCap)
 +        buffer()->setLineCap(newState.lineCap);
  
 -bool QSGContext2D::event(QEvent *e)
 -{
 -    Q_D(QSGContext2D);
 -    if (e->type() == QEvent::User && d->agentData) {
 -        QMutexLocker locker(&d->agentData->mutex);
 -        Sync *s = static_cast<Sync *>(e);
 -
 -        QSGContext2DPrivate* origin_d = static_cast<QSGContext2DPrivate*>(s->data->orig->d_func());
 -
 -        //quick copy
 -        memcpy_vector<PaintCommand>(&origin_d->commands, d->commands);
 -        memcpy_vector<int>(&origin_d->ints, d->ints);
 -        memcpy_vector<qreal>(&origin_d->reals, d->reals);
 -        memcpy_vector<QColor>(&origin_d->colors, d->colors);
 -        memcpy_vector<QMatrix>(&origin_d->matrixes, d->matrixes);
 -        memcpy_vector<QSize>(&origin_d->sizes, d->sizes);
 -
 -        //slow copy
 -        copy_vector<QString>(&origin_d->strings, d->strings);
 -        copy_vector<QVariant>(&origin_d->variants, d->variants);
 -        copy_vector<QPen>(&origin_d->pens, d->pens);
 -        copy_vector<QBrush>(&origin_d->brushes, d->brushes);
 -        copy_vector<QPainterPath>(&origin_d->pathes, d->pathes);
 -        copy_vector<QFont>(&origin_d->fonts, d->fonts);
 -        copy_vector<QImage>(&origin_d->images, d->images);
 -        origin_d->state = d->state;
 -        d->clearCommands();
 -
 -        if (d->waitingForPainting) {
 -            d->imageData.clear();
 -            origin_d->imageData.clear();
 -            emit s->data->orig->changed();
 -            while(origin_d->imageData.isEmpty()) {
 -                QCoreApplication::processEvents();
 -            }
 -            d->imageData = origin_d->imageData;
 -            d->waitingForPainting = false;
 -            qDebug() << "imageData size:" << d->imageData.size();
 -        } else {
 -            emit s->data->orig->changed();
 -        }
 +    if (newState.lineJoin != state.lineJoin)
 +        buffer()->setLineJoin(newState.lineJoin);
  
 -        d->agentData->syncDone.wakeAll();
 -        return true;
 -    }
 -    return QObject::event(e);
 -}
 +    if (newState.miterLimit != state.miterLimit)
 +        buffer()->setMiterLimit(newState.miterLimit);
  
 -void QSGContext2D::processCommand(const QJSValue& cmd)
 -{
 -    int action = cmd.property(0).toInt32();
 -    switch (action) {
 -    case QSGContext2D::Save:
 -        save();
 -        break;
 -    case QSGContext2D::Restore:
 -        restore();
 -        break;
 -    case QSGContext2D::Scale:
 -        scale(cmd.property(1).toNumber(), cmd.property(2).toNumber());
 -        break;
 -    case QSGContext2D::Rotate:
 -        rotate(cmd.property(1).toNumber());
 -        break;
 -    case QSGContext2D::Translate:
 -        translate(cmd.property(1).toNumber(), cmd.property(2).toNumber());
 -        break;
 -    case QSGContext2D::Transform:
 -        transform(cmd.property(1).toNumber(),
 -                  cmd.property(2).toNumber(),
 -                  cmd.property(3).toNumber(),
 -                  cmd.property(4).toNumber(),
 -                  cmd.property(5).toNumber(),
 -                  cmd.property(6).toNumber());
 -        break;
 -    case QSGContext2D::SetTransform:
 -        setTransform(cmd.property(1).toNumber(),
 -                  cmd.property(2).toNumber(),
 -                  cmd.property(3).toNumber(),
 -                  cmd.property(4).toNumber(),
 -                  cmd.property(5).toNumber(),
 -                  cmd.property(6).toNumber());
 -        break;
 -    case QSGContext2D::ClearRect:
 -        clearRect(cmd.property(1).toNumber(),
 -                  cmd.property(2).toNumber(),
 -                  cmd.property(3).toNumber(),
 -                  cmd.property(4).toNumber());
 -        break;
 -    case QSGContext2D::FillRect:
 -        fillRect(cmd.property(1).toNumber(),
 -                 cmd.property(2).toNumber(),
 -                 cmd.property(3).toNumber(),
 -                 cmd.property(4).toNumber());
 -        break;
 -    case QSGContext2D::StrokeRect:
 -        strokeRect(cmd.property(1).toNumber(),
 -                   cmd.property(2).toNumber(),
 -                   cmd.property(3).toNumber(),
 -                   cmd.property(4).toNumber());
 -        break;
 -    case QSGContext2D::BeginPath:
 -        beginPath();
 -        break;
 -    case QSGContext2D::ClosePath:
 -        closePath();
 -        break;
 -    case QSGContext2D::MoveTo:
 -        moveTo(cmd.property(1).toNumber(),
 -               cmd.property(2).toNumber());
 -        break;
 -    case QSGContext2D::LineTo:
 -        lineTo(cmd.property(1).toNumber(),
 -               cmd.property(2).toNumber());
 -        break;
 -    case QSGContext2D::QuadraticCurveTo:
 -        quadraticCurveTo(cmd.property(1).toNumber(),
 -                         cmd.property(2).toNumber(),
 -                         cmd.property(3).toNumber(),
 -                         cmd.property(4).toNumber());
 -        break;
 -    case QSGContext2D::BezierCurveTo:
 -        bezierCurveTo(cmd.property(1).toNumber(),
 -                      cmd.property(2).toNumber(),
 -                      cmd.property(3).toNumber(),
 -                      cmd.property(4).toNumber(),
 -                      cmd.property(5).toNumber(),
 -                      cmd.property(6).toNumber());
 -        break;
 -    case QSGContext2D::ArcTo:
 -        arcTo(cmd.property(1).toNumber(),
 -              cmd.property(2).toNumber(),
 -              cmd.property(3).toNumber(),
 -              cmd.property(4).toNumber(),
 -              cmd.property(5).toNumber());
 -        break;
 -    case QSGContext2D::Rect:
 -        rect(cmd.property(1).toNumber(),
 -             cmd.property(2).toNumber(),
 -             cmd.property(3).toNumber(),
 -             cmd.property(4).toNumber());
 -        break;
 -    case QSGContext2D::Arc:
 -        arc(cmd.property(1).toNumber(),
 -            cmd.property(2).toNumber(),
 -            cmd.property(3).toNumber(),
 -            cmd.property(4).toNumber(),
 -            cmd.property(5).toNumber(),
 -            cmd.property(6).toBool());
 -        break;
 -    case QSGContext2D::Fill:
 -        fill();
 -        break;
 -    case QSGContext2D::Stroke:
 -        stroke();
 -        break;
 -    case QSGContext2D::Clip:
 -        clip();
 -        break;
 -    case QSGContext2D::GlobalAlpha:
 -        setGlobalAlpha(cmd.property(1).toNumber());
 -        break;
 -    case QSGContext2D::GlobalCompositeOperation:
 -        setGlobalCompositeOperation(cmd.property(1).toString());
 -        break;
 -    case QSGContext2D::StrokeStyle:
 -        setStrokeStyle(cmd.property(1).toVariant());
 -        break;
 -    case QSGContext2D::FillStyle:
 -        setFillStyle(cmd.property(1).toVariant());
 -        break;
 -    case QSGContext2D::FillColor:
 -        setFillColor(cmd.property(1).toVariant().value<QColor>());
 -        break;
 -    case QSGContext2D::StrokeColor:
 -        setStrokeColor(cmd.property(1).toVariant().value<QColor>());
 -        break;
 -    case QSGContext2D::LineWidth:
 -        setLineWidth(cmd.property(1).toNumber());
 -        break;
 -    case QSGContext2D::LineCap:
 -        setLineCap(cmd.property(1).toString());
 -        break;
 -    case QSGContext2D::LineJoin:
 -        setLineJoin(cmd.property(1).toString());
 -        break;
 -    case QSGContext2D::MiterLimit:
 -        setMiterLimit(cmd.property(1).toNumber());
 -        break;
 -    case QSGContext2D::ShadowOffsetX:
 -        setShadowOffsetX(cmd.property(1).toNumber());
 -        break;
 -    case QSGContext2D::ShadowOffsetY:
 -        setShadowOffsetY(cmd.property(1).toNumber());
 -        break;
 -    case QSGContext2D::ShadowBlur:
 -        setShadowBlur(cmd.property(1).toNumber());
 -        break;
 -    case QSGContext2D::ShadowColor:
 -        setShadowColor(cmd.property(1).toString());
 -        break;
 -    case QSGContext2D::Font:
 -        setFont(cmd.property(1).toString());
 -        break;
 -    case QSGContext2D::TextBaseline:
 -        setTextBaseline(cmd.property(1).toString());
 -        break;
 -    case QSGContext2D::TextAlign:
 -        setTextAlign(cmd.property(1).toString());
 -        break;
 -    case QSGContext2D::FillText:
 -        fillText(cmd.property(1).toString(), cmd.property(2).toNumber(), cmd.property(3).toNumber());
 -        break;
 -    case QSGContext2D::StrokeText:
 -        strokeText(cmd.property(1).toString(), cmd.property(2).toNumber(), cmd.property(3).toNumber());
 -        break;
 -    case QSGContext2D::DrawImage1:
 -    {
 -        drawImage(cmd.property(1).toString(),
 -                  cmd.property(2).toNumber(),
 -                  cmd.property(3).toNumber());
 -        break;
 -    }
 -    case QSGContext2D::DrawImage2:
 -        drawImage(cmd.property(1).toString(),
 -                  cmd.property(2).toNumber(),
 -                  cmd.property(3).toNumber(),
 -                  cmd.property(4).toNumber(),
 -                  cmd.property(5).toNumber());
 -        break;
 -    case QSGContext2D::DrawImage3:
 -            drawImage(cmd.property(1).toString(),
 -                      cmd.property(2).toNumber(),
 -                      cmd.property(3).toNumber(),
 -                      cmd.property(4).toNumber(),
 -                      cmd.property(5).toNumber(),
 -                      cmd.property(6).toNumber(),
 -                      cmd.property(7).toNumber(),
 -                      cmd.property(8).toNumber(),
 -                      cmd.property(9).toNumber());
 -            break;
 -    case QSGContext2D::PutImageData:
 -            putImageData(cmd.property(1).toVariant(),
 -                         cmd.property(2).toNumber(),
 -                         cmd.property(3).toNumber(),
 -                         cmd.property(4).toNumber(),
 -                         cmd.property(5).toNumber());
 -            break;
 -    default:
 -        break;
 -    }
 -}
 +    if (newState.clipPath != state.clipPath)
 +        buffer()->clip(newState.clipPath);
  
 -void QSGContext2D::paint(QPainter* p)
 -{
 -    Q_D(QSGContext2D);
 +    if (newState.shadowBlur != state.shadowBlur)
 +        buffer()->setShadowBlur(newState.shadowBlur);
  
 -    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;
 +    if (newState.shadowColor != state.shadowColor)
 +        buffer()->setShadowColor(newState.shadowColor);
  
 -        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 = 0;
 +    if (newState.shadowOffsetX != state.shadowOffsetX)
 +        buffer()->setShadowOffsetX(newState.shadowOffsetX);
  
 -        foreach(PaintCommand cmd, d->commands) {
 -            switch (cmd) {
 -            case UpdateMatrix:
 -            {
 -                d->state.matrix = d->matrixes[matrix_idx++];
 -                p->setMatrix(d->state.matrix * originMatrix);
 -                break;
 -            }
 -            case ClearRect:
 -            {
 -                qreal x = d->reals[real_idx++];
 -                qreal y = d->reals[real_idx++];
 -                qreal w = d->reals[real_idx++];
 -                qreal h = d->reals[real_idx++];
 -                p->eraseRect(QRectF(x, y, w, h));
 -                break;
 -            }
 -            case FillRect:
 -            {
 -                qreal x = d->reals[real_idx++];
 -                qreal y = d->reals[real_idx++];
 -                qreal w = d->reals[real_idx++];
 -                qreal h = d->reals[real_idx++];
 -                if (d->hasShadow())
 -                    d->fillRectShadow(p, QRectF(x, y, w, h));
 -                else
 -                    p->fillRect(QRectF(x, y, w, h), p->brush());
 -                break;
 -            }
 -            case ShadowColor:
 -            {
 -                QColor c = d->colors[color_idx++];
 -                d->state.shadowColor = c;
 -                break;
 -            }
 -            case ShadowBlur:
 -            {
 -                qreal blur = d->reals[real_idx++];
 -                d->state.shadowBlur = blur;
 -                break;
 -            }
 -            case ShadowOffsetX:
 -            {
 -                qreal x = d->reals[real_idx++];
 -                d->state.shadowOffsetX = x;
 -                break;
 -            }
 -            case ShadowOffsetY:
 -            {
 -                qreal y = d->reals[real_idx++];
 -                d->state.shadowOffsetY = y;
 -                break;
 -            }
 -            case Fill:
 -            {
 -                QPainterPath path = d->pathes[path_idx++];
 -                //qDebug() << "fill path:" << path.elementCount();
 -                if (d->hasShadow())
 -                    d->fillShadowPath(p,path);
 -                else
 -                    p->fillPath(path, p->brush());
 -                break;
 -            }
 -            case Stroke:
 -            {
 -                //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
 -                    p->strokePath(path, p->pen());
 -                break;
 -            }
 -            case Clip:
 -            {
 -                QPainterPath clipPath = d->pathes[path_idx++];
 -                p->setClipPath(clipPath);
 -                p->setClipping(true);
 -                break;
 -            }
 -            case UpdateBrush:
 -            {
 -                p->setBrush(d->brushes[brush_idx++]);
 -                break;
 -            }
 -            case UpdatePen:
 -            {
 -                p->setPen(d->pens[pen_idx++]);
 -                break;
 -            }
 -            case GlobalAlpha:
 -            {
 -                p->setOpacity(d->reals[real_idx++]);
 -                break;
 -            }
 -            case GlobalCompositeOperation:
 -            {
 -                p->setCompositionMode(static_cast<QPainter::CompositionMode>(d->ints[int_idx++]));
 -                break;
 -            }
 -            case Font:
 -            {
 -                p->setFont(d->fonts[font_idx++]);
 -                break;
 -            }
 -            case StrokeText:
 -            {
 -                QString text = d->strings[string_idx++];
 -                qreal x = d->reals[real_idx++];
 -                qreal y = d->reals[real_idx++];
 -                int align = d->ints[int_idx++];
 -                int baseline = d->ints[int_idx++];
 -
 -                QPen oldPen = p->pen();
 -                p->setPen(QPen(p->brush(),0));
 -                //p->setMatrix(state.matrix, false); // always set?
 -
 -                QPainterPath textPath;
 -                QFont oldFont = p->font();
 -                QFont font = p->font();
 -                font.setStyleStrategy(QFont::ForceOutline);
 -                p->setFont(font);
 -                const QFontMetrics &metrics = p->fontMetrics();
 -                int yoffset = d->baseLineOffset(static_cast<QSGContext2D::TextBaseLineType>(baseline), metrics);
 -                int xoffset = d->textAlignOffset(static_cast<QSGContext2D::TextAlignType>(align), metrics, text);
 -                textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), font, text);
 -                if (d->hasShadow())
 -                    d->strokeShadowPath(p,textPath);
 -
 -                p->strokePath(textPath, QPen(p->brush(), p->pen().widthF()));
 -
 -                //reset old font
 -                p->setFont(oldFont);
 -                p->setPen(oldPen);
 -                break;
 -            }
 -            case FillText:
 -            {
 -                QString text = d->strings[string_idx++];
 -                qreal x = d->reals[real_idx++];
 -                qreal y = d->reals[real_idx++];
 -                int align = d->ints[int_idx++];
 -                int baseline = d->ints[int_idx++];
 -
 -                QFont oldFont = p->font();
 -                QPen oldPen = p->pen();
 -                p->setPen(QPen(p->brush(), p->pen().widthF()));
 -                //p->setMatrix(state.matrix, false);
 -                //QFont font = p->font();
 -                QFont font = d->state.font;
 -                font.setBold(true);
 -
 -                p->setFont(font);
 -                int yoffset = d->baseLineOffset(static_cast<QSGContext2D::TextBaseLineType>(baseline), p->fontMetrics());
 -                int xoffset = d->textAlignOffset(static_cast<QSGContext2D::TextAlignType>(align), p->fontMetrics(), text);
 -                QTextOption opt; // Adjust baseLine etc
 -                if (d->hasShadow()) {
 -                    const QFontMetrics &metrics = p->fontMetrics();
 -                    QPainterPath textPath;
 -                    textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), font, text);
 -                    d->fillShadowPath(p,textPath);
 -                }
 -                //p->drawText(QRectF(x - xoffset, y - yoffset, QWIDGETSIZE_MAX, p->fontMetrics().height()), text, opt);
 -                p->setFont(oldFont);
 -                p->setPen(oldPen);
 -                break;
 -            }
 -            case DrawImage1:
 -            {
 -                QUrl url(d->strings[string_idx++]);
 -                qreal x = d->reals[real_idx++];
 -                qreal y = d->reals[real_idx++];
 -                QDeclarativePixmap px(qmlEngine(d->canvas), url);
 -                qDebug() << "draw image:" << url << px.pixmap().size();
 -                if (px.isReady()) {
 -                    QPixmap pixmap = px.pixmap();
 -                    if (d->hasShadow()) {
 -                        QImage shadow = d->makeShadowImage(pixmap);
 -                        qreal dx = x + (d->state.shadowOffsetX < 0? d->state.shadowOffsetX:0);
 -                        qreal dy = y + (d->state.shadowOffsetY < 0? d->state.shadowOffsetY:0);
 -                        p->drawImage(QPointF(dx, dy), shadow);
 -                    }
 -                    p->drawPixmap(QPointF(x, y), pixmap);
 -                }
 -                break;
 -            }
 -            case DrawImage2:
 -            {
 -                qreal dx = d->reals[real_idx++];
 -                qreal dy = d->reals[real_idx++];
 -                qreal dw = d->reals[real_idx++];
 -                qreal dh = d->reals[real_idx++];
 -                QUrl url(d->strings[string_idx++]);
 -                QDeclarativePixmap px(qmlEngine(d->canvas), url);
 -                if (px.isReady()) {
 -                    QPixmap pixmap = px.pixmap().scaled(dw, dh);
 -                    if (d->hasShadow()) {
 -                        QImage shadow = d->makeShadowImage(pixmap);
 -                        qreal shadow_dx = dx + (d->state.shadowOffsetX < 0? d->state.shadowOffsetX:0);
 -                        qreal shadow_dy = dy + (d->state.shadowOffsetY < 0? d->state.shadowOffsetY:0);
 -                        p->drawImage(QPointF(shadow_dx, shadow_dy), shadow);
 -                    }
 -                    p->drawPixmap(QPointF(dx, dy), pixmap);
 -                }
 -                break;
 -            }
 -            case DrawImage3:
 -            {
 -                qreal sx = d->reals[real_idx++];
 -                qreal sy = d->reals[real_idx++];
 -                qreal sw = d->reals[real_idx++];
 -                qreal sh = d->reals[real_idx++];
 -                qreal dx = d->reals[real_idx++];
 -                qreal dy = d->reals[real_idx++];
 -                qreal dw = d->reals[real_idx++];
 -                qreal dh = d->reals[real_idx++];
 -                QUrl url(d->strings[string_idx++]);
 -                QDeclarativePixmap px(qmlEngine(d->canvas), url);
 -                if (px.isReady()) {
 -                    QPixmap pixmap = px.pixmap().copy(sx, sy, sw, sh).scaled(dw, dh);
 -                    if (d->hasShadow()) {
 -                        QImage shadow = d->makeShadowImage(pixmap);
 -                        qreal shadow_dx = dx + (d->state.shadowOffsetX < 0? d->state.shadowOffsetX:0);
 -                        qreal shadow_dy = dy + (d->state.shadowOffsetY < 0? d->state.shadowOffsetY:0);
 -                        p->drawImage(QPointF(shadow_dx, shadow_dy), shadow);
 -                    }
 -                    p->drawPixmap(QPointF(dx, dy), pixmap);
 -                }
 -                break;
 -            }
 -            case GetImageData:
 -            {
 -                qreal sx = d->reals[real_idx++];
 -                qreal sy = d->reals[real_idx++];
 -                qreal sw = d->reals[real_idx++];
 -                qreal sh = d->reals[real_idx++];
 -                QImage img = toImage().copy(sx, sy, sw, sh);
 -                const uchar* data = img.constBits();
 -                int i = 0;
 -
 -                while(i< img.byteCount()) {
 -                    //the stored order in QImage:BGRA
 -                    d->imageData << *(data+i+2);//R
 -                    d->imageData << *(data+i+1);//G
 -                    d->imageData << *(data+i);//B
 -                    d->imageData << *(data+i+3);//A
 -                    i+=4;
 -                }
 -                break;
 -            }
 -            case PutImageData:
 -            {
 -                QImage image = d->images[image_idx++];
 -                qreal x = d->reals[real_idx++];
 -                qreal y = d->reals[real_idx++];
 -                p->drawImage(QPointF(x, y), image);
 -                break;
 -            }
 -            default:
 -                break;
 -            }
 -        }
 -        d->clearCommands();
 -    }
 -}
 +    if (newState.shadowOffsetY != state.shadowOffsetY)
 +        buffer()->setShadowOffsetY(newState.shadowOffsetY);
  
 -QPaintDevice* QSGContext2D::paintDevice()
 -{
 -    Q_D(QSGContext2D);
 -    return &d->cachedImage;
 -}
 -const QImage& QSGContext2D::toImage() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->cachedImage;
 -}
 -bool QSGContext2D::requireCachedImage() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->waitingForPainting;
 -}
 -void QSGContext2D::setCachedImage(const QImage& image)
 -{
 -    Q_D(QSGContext2D);
 -#ifndef QSGCANVASITEM_PAINTING_ON_IMAGE
 -    if (d->waitingForPainting) {
 -        d->cachedImage = image;
 -        d->waitingForPainting = false;
 -    }
 -#endif
 +    state = newState;
  }
 -
 -void QSGContext2D::clear()
 +void QSGContext2D::pushState()
  {
 -    Q_D(QSGContext2D);
 -    d->clear();
 +    m_stateStack.push(state);
  }
  
  void QSGContext2D::reset()
  {
 -    Q_D(QSGContext2D);
 -    d->reset();
 -}
 -
 -void QSGContext2D::drawImage(const QString& imgUrl, qreal dx, qreal dy)
 -{
 -    Q_D(QSGContext2D);
 -    if (!imgUrl.isEmpty())
 -        d->drawImage(imgUrl, dx, dy);
 -}
 -
 -void QSGContext2D::drawImage(const QString& imgUrl, qreal sx, qreal sy, qreal sw, qreal sh, qreal dx, qreal dy, qreal dw, qreal dh)
 -{
 -    Q_D(QSGContext2D);
 -    if (!imgUrl.isEmpty())
 -        d->drawImage(imgUrl, sx, sy, sw, sh, dx, dy, dw, dh);
 -}
 -
 -void QSGContext2D::drawImage(const QString& imgUrl, qreal dx, qreal dy,
 -                             qreal dw, qreal dh)
 -{
 -    Q_D(QSGContext2D);
 -    if (!imgUrl.isEmpty())
 -        d->drawImage(imgUrl, dx, dy, dw, dh);
 +    QSGContext2D::State newState;
 +    newState.matrix = QTransform();
 +
 +    QPainterPath defaultClipPath;
 +    defaultClipPath.addRect(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
 +    newState.clipPath = defaultClipPath;
 +    newState.clipPath.setFillRule(Qt::WindingFill);
 +
 +    newState.strokeStyle = Qt::black;
 +    newState.fillStyle = Qt::black;
 +    newState.fillRule = Qt::WindingFill;
 +    newState.globalAlpha = 1.0;
 +    newState.lineWidth = 1;
 +    newState.lineCap = Qt::FlatCap;
 +    newState.lineJoin = Qt::MiterJoin;
 +    newState.miterLimit = 10;
 +    newState.shadowOffsetX = 0;
 +    newState.shadowOffsetY = 0;
 +    newState.shadowBlur = 0;
 +    newState.shadowColor = qRgba(0, 0, 0, 0);
 +    newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
 +    newState.font = QFont(QLatin1String("sans-serif"), 10);
 +    newState.textAlign = QSGContext2D::Start;
 +    newState.textBaseline = QSGContext2D::Alphabetic;
 +
 +    m_fontString = "";
 +    m_stateStack.clear();
 +    m_stateStack.push(newState);
 +    popState();
  }
  
 -void QSGContext2D::setSize(int width, int height)
 +void QSGContext2D::setV8Engine(QV8Engine *engine)
  {
 -    QSize size(width, height);
 -    setSize(size);
 -}
 +    v8::HandleScope handle_scope;
 +    v8::Context::Scope scope(engine->context());
  
 -void QSGContext2D::setSize(const QSize &size)
 -{
 -    Q_D(QSGContext2D);
 +    if (m_v8engine != engine) {
 +        m_v8engine = engine;
  
 -    if (d->size == size)
 -        return;
 -    d->setSize(size);
 -    emit changed();
 -}
 +        qPersistentDispose(m_v8value);
  
 -QSize QSGContext2D::size() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->size;
 -}
 +        if (m_v8engine == 0)
 +            return;
  
 -QMatrix QSGContext2D::worldMatrix() const
 -{
 -    Q_D(const QSGContext2D);
 -    return d->state.matrix;
 +        QSGContext2DEngineData *ed = engineData(engine);
 +        m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
 +        QV8Context2DResource *r = new QV8Context2DResource(engine);
 +        r->context = this;
 +        m_v8value->SetExternalResource(r);
 +    }
  }
  
  QT_END_NAMESPACE
@@@ -45,8 -45,9 +45,9 @@@
  #include "qsgcanvas_p.h"
  
  #include <QtDeclarative/qdeclarativeinfo.h>
- #include <QtGui/qgraphicssceneevent.h>
- #include <QtGui/qapplication.h>
+ #include <QtGui/qevent.h>
+ #include <QtGui/qguiapplication.h>
+ #include <QtGui/qstylehints.h>
  #include "qplatformdefs.h"
  
  QT_BEGIN_NAMESPACE
@@@ -235,8 -236,8 +236,8 @@@ void QSGFlickablePrivate::AxisData::add
  
  void QSGFlickablePrivate::AxisData::updateVelocity()
  {
 +    velocity = 0;
      if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) {
 -        velocity = 0;
          int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES;
          for (int i = 0; i < count; ++i) {
              qreal v = velocityBuffer.at(i);
@@@ -793,7 -794,7 +794,7 @@@ void QSGFlickable::setPixelAligned(boo
      }
  }
  
- void QSGFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
+ void QSGFlickablePrivate::handleMousePressEvent(QMouseEvent *event)
  {
      Q_Q(QSGFlickable);
      if (interactive && timeline.isActive()
      fixupMode = Normal;
      lastPos = QPoint();
      QSGItemPrivate::start(lastPosTime);
-     pressPos = event->pos();
+     pressPos = event->localPos();
      hData.pressPos = hData.move.value();
      vData.pressPos = vData.move.value();
      flickingHorizontally = false;
      QSGItemPrivate::start(velocityTime);
  }
  
- void QSGFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
+ void QSGFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
  {
      Q_Q(QSGFlickable);
      if (!interactive || !lastPosTime.isValid())
      bool stealX = stealMouse;
  
      if (q->yflick()) {
-         int dy = int(event->pos().y() - pressPos.y());
-         if (qAbs(dy) > QApplication::startDragDistance() || QSGItemPrivate::elapsed(pressTime) > 200) {
+         int dy = int(event->localPos().y() - pressPos.y());
+         if (qAbs(dy) > qApp->styleHints()->startDragDistance() || QSGItemPrivate::elapsed(pressTime) > 200) {
              if (!vMoved)
                  vData.dragStartOffset = dy;
              qreal newY = dy + vData.pressPos - vData.dragStartOffset;
                  vData.move.setValue(qRound(newY));
                  vMoved = true;
              }
-             if (qAbs(dy) > QApplication::startDragDistance())
+             if (qAbs(dy) > qApp->styleHints()->startDragDistance())
                  stealY = true;
          }
      }
  
      if (q->xflick()) {
-         int dx = int(event->pos().x() - pressPos.x());
-         if (qAbs(dx) > QApplication::startDragDistance() || QSGItemPrivate::elapsed(pressTime) > 200) {
+         int dx = int(event->localPos().x() - pressPos.x());
+         if (qAbs(dx) > qApp->styleHints()->startDragDistance() || QSGItemPrivate::elapsed(pressTime) > 200) {
              if (!hMoved)
                  hData.dragStartOffset = dx;
              qreal newX = dx + hData.pressPos - hData.dragStartOffset;
                  hMoved = true;
              }
  
-             if (qAbs(dx) > QApplication::startDragDistance())
+             if (qAbs(dx) > qApp->styleHints()->startDragDistance())
                  stealX = true;
          }
      }
          if (elapsed <= 0)
              return;
          QSGItemPrivate::restart(lastPosTime);
-         qreal dy = event->pos().y()-lastPos.y();
+         qreal dy = event->localPos().y()-lastPos.y();
          if (q->yflick() && !rejectY)
              vData.addVelocitySample(dy/elapsed, maxVelocity);
-         qreal dx = event->pos().x()-lastPos.x();
+         qreal dx = event->localPos().x()-lastPos.x();
          if (q->xflick() && !rejectX)
              hData.addVelocitySample(dx/elapsed, maxVelocity);
      }
  
-     lastPos = event->pos();
+     lastPos = event->localPos();
  }
  
- void QSGFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+ void QSGFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
  {
      Q_Q(QSGFlickable);
      stealMouse = false;
      qreal velocity = vData.velocity;
      if (vData.atBeginning || vData.atEnd)
          velocity /= 2;
-     if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold)
+     if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->localPos().y() - pressPos.y()) > FlickThreshold)
          flickY(velocity);
      else
          fixupY();
      velocity = hData.velocity;
      if (hData.atBeginning || hData.atEnd)
          velocity /= 2;
-     if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold)
+     if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->localPos().x() - pressPos.x()) > FlickThreshold)
          flickX(velocity);
      else
          fixupX();
          q->movementEnding();
  }
  
- void QSGFlickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
+ void QSGFlickable::mousePressEvent(QMouseEvent *event)
  {
      Q_D(QSGFlickable);
      if (d->interactive) {
      }
  }
  
- void QSGFlickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+ void QSGFlickable::mouseMoveEvent(QMouseEvent *event)
  {
      Q_D(QSGFlickable);
      if (d->interactive) {
      }
  }
  
- void QSGFlickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+ void QSGFlickable::mouseReleaseEvent(QMouseEvent *event)
  {
      Q_D(QSGFlickable);
      if (d->interactive) {
@@@ -1074,7 -1075,7 +1075,7 @@@ bool QSGFlickablePrivate::isOutermostPr
      return true;
  }
  
- void QSGFlickablePrivate::captureDelayedPress(QGraphicsSceneMouseEvent *event)
+ void QSGFlickablePrivate::captureDelayedPress(QMouseEvent *event)
  {
      Q_Q(QSGFlickable);
      if (!q->canvas() || pressDelay <= 0)
      if (!isOutermostPressDelay())
          return;
      delayedPressTarget = q->canvas()->mouseGrabberItem();
-     delayedPressEvent = new QGraphicsSceneMouseEvent(event->type());
+     delayedPressEvent = new QMouseEvent(*event);
      delayedPressEvent->setAccepted(false);
-     for (int i = 0x1; i <= 0x10; i <<= 1) {
-         if (event->buttons() & i) {
-             Qt::MouseButton button = Qt::MouseButton(i);
-             delayedPressEvent->setButtonDownPos(button, event->buttonDownPos(button));
-             delayedPressEvent->setButtonDownScenePos(button, event->buttonDownScenePos(button));
-             delayedPressEvent->setButtonDownScreenPos(button, event->buttonDownScreenPos(button));
-         }
-     }
-     delayedPressEvent->setButtons(event->buttons());
-     delayedPressEvent->setButton(event->button());
-     delayedPressEvent->setPos(event->pos());
-     delayedPressEvent->setScenePos(event->scenePos());
-     delayedPressEvent->setScreenPos(event->screenPos());
-     delayedPressEvent->setLastPos(event->lastPos());
-     delayedPressEvent->setLastScenePos(event->lastScenePos());
-     delayedPressEvent->setLastScreenPos(event->lastScreenPos());
-     delayedPressEvent->setModifiers(event->modifiers());
      delayedPressTimer.start(pressDelay, q);
  }
  
@@@ -1518,34 -1502,26 +1502,26 @@@ void QSGFlickable::mouseUngrabEvent(
      }
  }
  
- bool QSGFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+ bool QSGFlickable::sendMouseEvent(QMouseEvent *event)
  {
      Q_D(QSGFlickable);
-     QGraphicsSceneMouseEvent mouseEvent(event->type());
      QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
  
      QSGCanvas *c = canvas();
      QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
      bool disabledItem = grabber && !grabber->isEnabled();
      bool stealThisEvent = d->stealMouse;
-     if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
+     if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
+         QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
+                                event->button(), event->buttons(), event->modifiers());
          mouseEvent.setAccepted(false);
-         for (int i = 0x1; i <= 0x10; i <<= 1) {
-             if (event->buttons() & i) {
-                 Qt::MouseButton button = Qt::MouseButton(i);
-                 mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
-             }
-         }
-         mouseEvent.setScenePos(event->scenePos());
-         mouseEvent.setLastScenePos(event->lastScenePos());
-         mouseEvent.setPos(mapFromScene(event->scenePos()));
-         mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
  
          switch(mouseEvent.type()) {
-         case QEvent::GraphicsSceneMouseMove:
+         case QEvent::MouseMove:
              d->handleMouseMoveEvent(&mouseEvent);
              break;
-         case QEvent::GraphicsSceneMousePress:
+         case QEvent::MouseButtonPress:
              if (d->pressed) // we are already pressed - this is a delayed replay
                  return false;
  
              d->captureDelayedPress(event);
              stealThisEvent = d->stealMouse;   // Update stealThisEvent in case changed by function call above
              break;
-         case QEvent::GraphicsSceneMouseRelease:
+         case QEvent::MouseButtonRelease:
              if (d->delayedPressEvent) {
                  // We replay the mouse press but the grabber we had might not be interessted by the event (e.g. overlay)
                  // so we reset the grabber
          d->lastPosTime.invalidate();
          returnToBounds();
      }
-     if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+     if (event->type() == QEvent::MouseButtonRelease) {
          d->lastPosTime.invalidate();
          d->clearDelayedPress();
          d->stealMouse = false;
@@@ -1601,10 -1577,10 +1577,10 @@@ bool QSGFlickable::childMouseEventFilte
      if (!isVisible() || !d->interactive || !isEnabled())
          return QSGItem::childMouseEventFilter(i, e);
      switch (e->type()) {
-     case QEvent::GraphicsSceneMousePress:
-     case QEvent::GraphicsSceneMouseMove:
-     case QEvent::GraphicsSceneMouseRelease:
-         return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+     case QEvent::MouseButtonPress:
+     case QEvent::MouseMove:
+     case QEvent::MouseButtonRelease:
+         return sendMouseEvent(static_cast<QMouseEvent *>(e));
      default:
          break;
      }
@@@ -130,7 -130,8 +130,8 @@@ static void qt_sgitems_defineModule(con
      qmlRegisterType<QDeclarativePathArc>("QtQuick",2,0,"PathArc");
      qmlRegisterType<QDeclarativePathSvg>("QtQuick",2,0,"PathSvg");
      qmlRegisterType<QSGPathView>(uri,major,minor,"PathView");
-     qmlRegisterUncreatableType<QSGBasePositioner>(uri,major,minor,"Positioner","Positioner is an abstract type that is only available as an attached property.");
+     qmlRegisterUncreatableType<QSGBasePositioner>(uri,major,minor,"Positioner",
+                                                   QStringLiteral("Positioner is an abstract type that is only available as an attached property."));
  #ifndef QT_NO_VALIDATOR
      qmlRegisterType<QIntValidator>(uri,major,minor,"IntValidator");
      qmlRegisterType<QDoubleValidator>(uri,major,minor,"DoubleValidator");
      qmlRegisterType<QValidator>();
  #endif
      qmlRegisterType<QSGVisualModel>();
- #ifndef QT_NO_ACTION
-     qmlRegisterType<QAction>();
- #endif
      qmlRegisterType<QSGPen>();
      qmlRegisterType<QSGFlickableVisibleArea>();
      qRegisterMetaType<QSGAnchorLine>("QSGAnchorLine");
      qmlRegisterUncreatableType<QSGPaintedItem>("QtQuick", 2, 0, "PaintedItem", QSGPaintedItem::tr("Cannot create instance of abstract class PaintedItem"));
  
      qmlRegisterType<QSGCanvasItem>("QtQuick", 2, 0, "Canvas");
 -    qmlRegisterType<QSGContext2D>();
 -    qmlRegisterType<QSGCanvasGradient>();
  
      qmlRegisterType<QSGSprite>("QtQuick", 2, 0, "Sprite");
      qmlRegisterType<QSGSpriteImage>("QtQuick", 2, 0, "SpriteImage");
@@@ -44,7 -44,7 +44,7 @@@
  #include <QDebug>
  #include <QPainter>
  #include <QSet>
- #include <QtOpenGL>
+ #include <QtGui>
  
  QT_BEGIN_NAMESPACE
  
@@@ -53,7 -53,7 +53,7 @@@
     Also solve the state data initialization/transfer issue so as to not need to make friends
  */
  
 -QSGSpriteEngine::QSGSpriteEngine(QObject *parent) :
 +QSGStochasticEngine::QSGStochasticEngine(QObject *parent) :
      QObject(parent), m_timeOffset(0)
  {
      //Default size 1
@@@ -61,7 -61,7 +61,7 @@@
      m_advanceTime.start();
  }
  
 -QSGSpriteEngine::QSGSpriteEngine(QList<QSGSprite*> states, QObject *parent) :
 +QSGStochasticEngine::QSGStochasticEngine(QList<QSGStochasticState*> states, QObject *parent) :
      QObject(parent), m_states(states), m_timeOffset(0)
  {
      //Default size 1
      m_advanceTime.start();
  }
  
 +QSGStochasticEngine::~QSGStochasticEngine()
 +{
 +}
 +
 +QSGSpriteEngine::QSGSpriteEngine(QObject *parent)
 +    : QSGStochasticEngine(parent)
 +{
 +}
 +
 +QSGSpriteEngine::QSGSpriteEngine(QList<QSGSprite*> sprites, QObject *parent)
 +    : QSGStochasticEngine(parent)
 +{
 +    foreach (QSGSprite* sprite, sprites)
 +        m_states << (QSGStochasticState*)sprite;
 +}
 +
  QSGSpriteEngine::~QSGSpriteEngine()
  {
  }
  
 +
  int QSGSpriteEngine::maxFrames()
  {
      return m_maxFrames;
@@@ -104,46 -87,46 +104,46 @@@ TODO: Above idea needs to have the vary
  */
  int QSGSpriteEngine::spriteState(int sprite)
  {
 -    int state = m_sprites[sprite];
 -    if (!m_states[state]->m_generatedCount)
 +    int state = m_things[sprite];
 +    if (!m_sprites[state]->m_generatedCount)
          return state;
 -    int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow;
 +    int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
      int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
      return state + extra;
  }
  
  int QSGSpriteEngine::spriteStart(int sprite)
  {
 -    int state = m_sprites[sprite];
 -    if (!m_states[state]->m_generatedCount)
 +    int state = m_things[sprite];
 +    if (!m_sprites[state]->m_generatedCount)
          return m_startTimes[sprite];
 -    int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow;
 +    int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
      int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
      return state + extra*rowDuration;
  }
  
  int QSGSpriteEngine::spriteFrames(int sprite)
  {
 -    int state = m_sprites[sprite];
 -    if (!m_states[state]->m_generatedCount)
 -        return m_states[state]->frames();
 -    int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow;
 +    int state = m_things[sprite];
 +    if (!m_sprites[state]->m_generatedCount)
 +        return m_sprites[state]->frames();
 +    int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
      int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
 -    if (extra == m_states[state]->m_generatedCount - 1)//last state
 -        return m_states[state]->frames() % m_states[state]->m_framesPerRow;
 +    if (extra == m_sprites[state]->m_generatedCount - 1)//last state
 +        return m_sprites[state]->frames() % m_sprites[state]->m_framesPerRow;
      else
 -        return m_states[state]->m_framesPerRow;
 +        return m_sprites[state]->m_framesPerRow;
  }
  
  int QSGSpriteEngine::spriteDuration(int sprite)
  {
 -    int state = m_sprites[sprite];
 -    if (!m_states[state]->m_generatedCount)
 +    int state = m_things[sprite];
 +    if (!m_sprites[state]->m_generatedCount)
          return m_duration[sprite];
 -    int rowDuration = m_duration[sprite] * m_states[state]->m_framesPerRow;
 +    int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
      int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
 -    if (extra == m_states[state]->m_generatedCount - 1)//last state
 -        return (m_duration[sprite] * m_states[state]->frames()) % rowDuration;
 +    if (extra == m_sprites[state]->m_generatedCount - 1)//last state
 +        return (m_duration[sprite] * m_sprites[state]->frames()) % rowDuration;
      else
          return rowDuration;
  }
@@@ -153,21 -136,21 +153,21 @@@ int QSGSpriteEngine::spriteCount()//TOD
      return m_imageStateCount;
  }
  
 -void QSGSpriteEngine::setGoal(int state, int sprite, bool jump)
 +void QSGStochasticEngine::setGoal(int state, int sprite, bool jump)
  {
 -    if (sprite >= m_sprites.count() || state >= m_states.count())
 +    if (sprite >= m_things.count() || state >= m_states.count())
          return;
      if (!jump){
          m_goals[sprite] = state;
          return;
      }
  
 -    if (m_sprites[sprite] == state)
 +    if (m_things[sprite] == state)
          return;//Already there
 -    m_sprites[sprite] = state;
 +    m_things[sprite] = state;
      m_duration[sprite] = m_states[state]->variedDuration();
      m_goals[sprite] = -1;
 -    restartSprite(sprite);
 +    restart(sprite);
      emit stateChanged(sprite);
      emit m_states[state]->entered();
      return;
@@@ -182,15 -165,8 +182,15 @@@ QImage QSGSpriteEngine::assembledImage(
  
      int maxSize;
      glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
 +    foreach (QSGStochasticState* s, m_states){
 +        QSGSprite* sprite = qobject_cast<QSGSprite*>(s);
 +        if (sprite)
 +            m_sprites << sprite;
 +        else
 +            qDebug() << "Error: Non-sprite in QSGSpriteEngine";
 +    }
  
 -    foreach (QSGSprite* state, m_states){
 +    foreach (QSGSprite* state, m_sprites){
          if (state->frames() > m_maxFrames)
              m_maxFrames = state->frames();
  
      image.fill(0);
      QPainter p(&image);
      int y = 0;
 -    foreach (QSGSprite* state, m_states){
 +    foreach (QSGSprite* state, m_sprites){
          QImage img(state->source().toLocalFile());
          if (img.height() == frameHeight && img.width() <  maxSize){//Simple case
              p.drawImage(0,y,img);
      return image;
  }
  
 -void QSGSpriteEngine::setCount(int c)
 +void QSGStochasticEngine::setCount(int c)
  {
 -    m_sprites.resize(c);
 +    m_things.resize(c);
      m_goals.resize(c);
      m_duration.resize(c);
      m_startTimes.resize(c);
  }
  
 -void QSGSpriteEngine::startSprite(int index, int state)
 +void QSGStochasticEngine::start(int index, int state)
  {
 -    if (index >= m_sprites.count())
 +    if (index >= m_things.count())
          return;
 -    m_sprites[index] = state;
 +    m_things[index] = state;
      m_duration[index] = m_states[state]->variedDuration();
      m_goals[index] = -1;
 -    restartSprite(index);
 +    restart(index);
  }
  
 -void QSGSpriteEngine::stopSprite(int index)
 +void QSGStochasticEngine::stop(int index)
  {
 -    if (index >= m_sprites.count())
 +    if (index >= m_things.count())
          return;
      //Will never change until start is called again with a new state - this is not a 'pause'
      for (int i=0; i<m_stateUpdates.count(); i++)
          m_stateUpdates[i].second.removeAll(index);
  }
  
 -void QSGSpriteEngine::restartSprite(int index)
 +void QSGStochasticEngine::restart(int index)
  {
      m_startTimes[index] = m_timeOffset + m_advanceTime.elapsed();
 -    int time = m_duration[index] * m_states[m_sprites[index]]->frames() + m_startTimes[index];
 +    int time = m_duration[index] * m_states[m_things[index]]->frames() + m_startTimes[index];
      for (int i=0; i<m_stateUpdates.count(); i++)
          m_stateUpdates[i].second.removeAll(index);
      addToUpdateList(time, index);
  }
  
 -uint QSGSpriteEngine::updateSprites(uint time)//### would returning a list of changed idxs be faster than signals?
 +uint QSGStochasticEngine::updateSprites(uint time)//### would returning a list of changed idxs be faster than signals?
  {
      //Sprite State Update;
      QSet<int> changedIndexes;
      while (!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){
          foreach (int idx, m_stateUpdates.first().second){
 -            if (idx >= m_sprites.count())
 +            if (idx >= m_things.count())
                  continue;//TODO: Proper fix(because this does happen and I'm just ignoring it)
 -            int stateIdx = m_sprites[idx];
 +            int stateIdx = m_things[idx];
              int nextIdx = -1;
              int goalPath = goalSeek(stateIdx, idx);
              if (goalPath == -1){//Random
              if (nextIdx == -1)//No to states means stay here
                  nextIdx = stateIdx;
  
 -            m_sprites[idx] = nextIdx;
 +            m_things[idx] = nextIdx;
              m_duration[idx] = m_states[nextIdx]->variedDuration();
              m_startTimes[idx] = time;
              if (nextIdx != stateIdx){
      return m_stateUpdates.first().first;
  }
  
 -int QSGSpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist)
 +int QSGStochasticEngine::goalSeek(int curIdx, int spriteIdx, int dist)
  {
      QString goalName;
      if (m_goals[spriteIdx] != -1)
              return curIdx;
      if (dist < 0)
          dist = m_states.count();
 -    QSGSprite* curState = m_states[curIdx];
 +    QSGStochasticState* curState = m_states[curIdx];
      for (QVariantMap::const_iterator iter = curState->m_to.constBegin();
          iter!=curState->m_to.constEnd(); iter++){
          if (iter.key() == goalName)
      return -1;
  }
  
 -void QSGSpriteEngine::addToUpdateList(uint t, int idx)
 +void QSGStochasticEngine::addToUpdateList(uint t, int idx)
  {
      for (int i=0; i<m_stateUpdates.count(); i++){
          if (m_stateUpdates[i].first==t){
@@@ -225,8 -225,8 +225,8 @@@ void QSGSpriteImage::createEngine(
  }
  
  static QSGGeometry::Attribute SpriteImage_Attributes[] = {
-     { 0, 2, GL_FLOAT },            // tex
-     { 1, 4, GL_FLOAT }             // animData
+     QSGGeometry::Attribute::create(0, 2, GL_FLOAT),         // tex
+     QSGGeometry::Attribute::create(1, 4, GL_FLOAT)          // animData
  };
  
  static QSGGeometry::AttributeSet SpriteImage_AttributeSet =
@@@ -263,7 -263,7 +263,7 @@@ QSGGeometryNode* QSGSpriteImage::buildN
      g->setDrawingMode(GL_TRIANGLES);
  
      SpriteVertices *p = (SpriteVertices *) g->vertexData();
 -    m_spriteEngine->startSprite(0);
 +    m_spriteEngine->start(0);
      p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = 0;
      p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = 0;
      p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->spriteFrames();
@@@ -83,11 -83,11 +83,11 @@@ static const char qt_particles_default_
          "}";
  
  static QSGGeometry::Attribute PlainParticle_Attributes[] = {
-     { 0, 2, GL_FLOAT },             // Position
-     { 1, 2, GL_FLOAT },             // TexCoord
-     { 2, 4, GL_FLOAT },             // Data
-     { 3, 4, GL_FLOAT },             // Vectors
-     { 4, 1, GL_FLOAT }              // r
+     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),       // Position
+     QSGGeometry::Attribute::create(1, 2, GL_FLOAT),             // TexCoord
+     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Data
+     QSGGeometry::Attribute::create(3, 4, GL_FLOAT),             // Vectors
+     QSGGeometry::Attribute::create(4, 1, GL_FLOAT)              // r
  };
  
  static QSGGeometry::AttributeSet PlainParticle_AttributeSet =
@@@ -132,11 -132,20 +132,20 @@@ QSGCustomParticle::QSGCustomParticle(QS
      : QSGParticlePainter(parent)
      , m_pleaseReset(true)
      , m_dirtyData(true)
+     , m_material(0)
      , m_rootNode(0)
  {
      setFlag(QSGItem::ItemHasContents);
  }
  
+ class QSGShaderEffectMaterialObject : public QObject, public QSGShaderEffectMaterial { };
+ QSGCustomParticle::~QSGCustomParticle()
+ {
+     if (m_material)
+         m_material->deleteLater();
+ }
  void QSGCustomParticle::componentComplete()
  {
      reset();
@@@ -269,13 -278,12 +278,12 @@@ void QSGCustomParticle::setSource(cons
      }
  
      QObject *obj = qVariantValue<QObject *>(var);
-     QSGTextureProvider *int3rface = QSGTextureProvider::from(obj);
-     if (!int3rface) {
-         qWarning("Could not assign property '%s', did not implement QSGTextureProvider.", source.name.constData());
-     }
      source.item = qobject_cast<QSGItem *>(obj);
+     if (!source.item || !source.item->isTextureProvider()) {
+         qWarning("ShaderEffect: source uniform [%s] is not assigned a valid texture provider: %s [%s]",
+                  source.name.constData(), qPrintable(obj->objectName()), obj->metaObject()->className());
+         return;
+     }
  
      // TODO: Copy better solution in QSGShaderEffect when they find it.
      // 'source.item' needs a canvas to get a scenegraph node.
@@@ -406,7 -414,6 +414,7 @@@ void QSGCustomParticle::lookThroughShad
  
  QSGNode *QSGCustomParticle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
  {
 +    Q_UNUSED(oldNode);
      if (m_pleaseReset){
  
          //delete m_material;//Shader effect item doesn't regen material?
@@@ -463,9 -470,15 +471,20 @@@ QSGShaderEffectNode* QSGCustomParticle:
          s.fragmentCode = qt_particles_default_fragment_code;
      if (s.vertexCode.isEmpty())
          s.vertexCode = qt_particles_default_vertex_code;
+     if (!m_material) {
+         m_material = new QSGShaderEffectMaterialObject;
+     }
      s.vertexCode = qt_particles_template_vertex_code + s.vertexCode;
++<<<<<<< HEAD
 +    m_material.setProgramSource(s);
 +    foreach (const QString &str, m_groups){
++=======
+     m_material->setProgramSource(s);
+     foreach (const QString &str, m_particles){
++>>>>>>> refactor
          int gIdx = m_system->m_groupIds[str];
          int count = m_system->m_groupData[gIdx]->size();
          //Create Particle Geometry
          QSGShaderEffectNode* node = new QSGShaderEffectNode();
  
          node->setGeometry(g);
-         node->setMaterial(&m_material);
+         node->setMaterial(m_material);
          node->markDirty(QSGNode::DirtyMaterial);
  
          m_nodes.insert(gIdx, node);
@@@ -525,29 -538,29 +544,29 @@@ void QSGCustomParticle::buildData(
          return;
      const QByteArray timestampName("qt_Timestamp");
      QVector<QPair<QByteArray, QVariant> > values;
-     QVector<QPair<QByteArray, QPointer<QSGItem> > > textures;
-     const QVector<QPair<QByteArray, QPointer<QSGItem> > > &oldTextures = m_material.textureProviders();
+     QVector<QPair<QByteArray, QSGTextureProvider *> > textures;
+     const QVector<QPair<QByteArray, QSGTextureProvider *> > &oldTextures = m_material->textureProviders();
      for (int i = 0; i < oldTextures.size(); ++i) {
-         QSGTextureProvider *oldSource = QSGTextureProvider::from(oldTextures.at(i).second);
-         if (oldSource && oldSource->textureChangedSignal())
+         QSGTextureProvider *t = oldTextures.at(i).second;
+         if (t)
              foreach (QSGShaderEffectNode* node, m_nodes)
-                 disconnect(oldTextures.at(i).second, oldSource->textureChangedSignal(), node, SLOT(markDirtyTexture()));
+                 disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
      }
      for (int i = 0; i < m_sources.size(); ++i) {
          const SourceData &source = m_sources.at(i);
-         textures.append(qMakePair(source.name, source.item));
-         QSGTextureProvider *t = QSGTextureProvider::from(source.item);
-         if (t && t->textureChangedSignal())
+         QSGTextureProvider *t = source.item->textureProvider();
+         textures.append(qMakePair(source.name, t));
+         if (t)
              foreach (QSGShaderEffectNode* node, m_nodes)
-                 connect(source.item, t->textureChangedSignal(), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+                 connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
      }
      for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin();
           it != m_source.uniformNames.end(); ++it) {
          values.append(qMakePair(*it, property(*it)));
      }
      values.append(qMakePair(timestampName, QVariant(m_lastTime)));
-     m_material.setUniforms(values);
-     m_material.setTextureProviders(textures);
+     m_material->setUniforms(values);
+     m_material->setTextureProviders(textures);
      m_dirtyData = false;
      foreach (QSGShaderEffectNode* node, m_nodes)
          node->markDirty(QSGNode::DirtyMaterial);
@@@ -49,7 -49,7 +49,7 @@@
  #include "qsgparticleemitter_p.h"
  #include "qsgsprite_p.h"
  #include "qsgspriteengine_p.h"
- #include <QGLFunctions>
+ #include <QOpenGLFunctions>
  #include <qsgengine.h>
  
  QT_BEGIN_NAMESPACE
@@@ -65,7 -65,7 +65,7 @@@ DEFINE_BOOL_CONFIG_OPTION(qmlParticlesD
  //TODO: Make it larger on desktop? Requires fixing up shader code with the same define
  #define UNIFORM_ARRAY_SIZE 64
  
- const float CONV = 0.017453292519943295;
+ const qreal CONV = 0.017453292519943295;
  class ImageMaterialData
  {
      public:
@@@ -98,13 -98,13 +98,13 @@@ class TabledMaterial : public QSGSimple
  public:
      TabledMaterial()
      {
-         QFile vf(":defaultshaders/imagevertex.shader");
+         QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
          vf.open(QFile::ReadOnly);
          m_vertex_code = QByteArray(SHADER_DEFINES)
              + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
              + vf.readAll();
  
-         QFile ff(":defaultshaders/imagefragment.shader");
+         QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
          ff.open(QFile::ReadOnly);
          m_fragment_code = QByteArray(SHADER_DEFINES)
              + QByteArray("#define TABLE\n#define DEFORM\n#define COLOR\n")
          program()->bind();
          program()->setUniformValue("texture", 0);
          program()->setUniformValue("colortable", 1);
-         glFuncs = QGLContext::currentContext()->functions();
+         glFuncs = QOpenGLContext::currentContext()->functions();
          m_timestamp_id = program()->uniformLocation("timestamp");
          m_entry_id = program()->uniformLocation("entry");
          m_sizetable_id = program()->uniformLocation("sizetable");
      int m_opacitytable_id;
      QByteArray m_vertex_code;
      QByteArray m_fragment_code;
-     QGLFunctions* glFuncs;
+     QOpenGLFunctions* glFuncs;
  };
  
  class DeformableMaterialData : public ImageMaterialData {};
@@@ -166,13 -166,13 +166,13 @@@ class DeformableMaterial : public QSGSi
  public:
      DeformableMaterial()
      {
-         QFile vf(":defaultshaders/imagevertex.shader");
+         QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
          vf.open(QFile::ReadOnly);
          m_vertex_code = QByteArray(SHADER_DEFINES)
              + QByteArray("#define DEFORM\n#define COLOR\n")
              + vf.readAll();
  
-         QFile ff(":defaultshaders/imagefragment.shader");
+         QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
          ff.open(QFile::ReadOnly);
          m_fragment_code = QByteArray(SHADER_DEFINES)
              + QByteArray("#define DEFORM\n#define COLOR\n")
          QSGSimpleMaterialShader<DeformableMaterialData>::initialize();
          program()->bind();
          program()->setUniformValue("texture", 0);
-         glFuncs = QGLContext::currentContext()->functions();
+         glFuncs = QOpenGLContext::currentContext()->functions();
          m_timestamp_id = program()->uniformLocation("timestamp");
          m_entry_id = program()->uniformLocation("entry");
      }
      int m_timestamp_id;
      QByteArray m_vertex_code;
      QByteArray m_fragment_code;
-     QGLFunctions* glFuncs;
+     QOpenGLFunctions* glFuncs;
  };
  
  class SpriteMaterialData : public ImageMaterialData {};
@@@ -222,13 -222,13 +222,13 @@@ class SpriteMaterial : public QSGSimple
  public:
      SpriteMaterial()
      {
-         QFile vf(":defaultshaders/imagevertex.shader");
+         QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
          vf.open(QFile::ReadOnly);
          m_vertex_code = QByteArray(SHADER_DEFINES)
              + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
              + vf.readAll();
  
-         QFile ff(":defaultshaders/imagefragment.shader");
+         QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
          ff.open(QFile::ReadOnly);
          m_fragment_code = QByteArray(SHADER_DEFINES)
              + QByteArray("#define SPRITE\n#define TABLE\n#define DEFORM\n#define COLOR\n")
          program()->bind();
          program()->setUniformValue("texture", 0);
          program()->setUniformValue("colortable", 1);
-         glFuncs = QGLContext::currentContext()->functions();
+         glFuncs = QOpenGLContext::currentContext()->functions();
          m_timestamp_id = program()->uniformLocation("timestamp");
          m_framecount_id = program()->uniformLocation("framecount");
          m_animcount_id = program()->uniformLocation("animcount");
      int m_opacitytable_id;
      QByteArray m_vertex_code;
      QByteArray m_fragment_code;
-     QGLFunctions* glFuncs;
+     QOpenGLFunctions* glFuncs;
  };
  
  class ColoredMaterialData : public ImageMaterialData {};
@@@ -295,13 -295,13 +295,13 @@@ class ColoredMaterial : public QSGSimpl
  public:
      ColoredMaterial()
      {
-         QFile vf(":defaultshaders/imagevertex.shader");
+         QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
          vf.open(QFile::ReadOnly);
          m_vertex_code = QByteArray(SHADER_DEFINES)
              + QByteArray("#define COLOR\n")
              + vf.readAll();
  
-         QFile ff(":defaultshaders/imagefragment.shader");
+         QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
          ff.open(QFile::ReadOnly);
          m_fragment_code = QByteArray(SHADER_DEFINES)
              + QByteArray("#define COLOR\n")
  
      void activate() {
          QSGSimpleMaterialShader<ColoredMaterialData>::activate();
- #ifndef QT_OPENGL_ES_2
+ #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
          glEnable(GL_POINT_SPRITE);
          glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
  #endif
  
      void deactivate() {
          QSGSimpleMaterialShader<ColoredMaterialData>::deactivate();
- #ifndef QT_OPENGL_ES_2
+ #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
          glDisable(GL_POINT_SPRITE);
          glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
  #endif
          QSGSimpleMaterialShader<ColoredMaterialData>::initialize();
          program()->bind();
          program()->setUniformValue("texture", 0);
-         glFuncs = QGLContext::currentContext()->functions();
+         glFuncs = QOpenGLContext::currentContext()->functions();
          m_timestamp_id = program()->uniformLocation("timestamp");
          m_entry_id = program()->uniformLocation("entry");
      }
      int m_entry_id;
      QByteArray m_vertex_code;
      QByteArray m_fragment_code;
-     QGLFunctions* glFuncs;
+     QOpenGLFunctions* glFuncs;
  };
  
  class SimpleMaterialData : public ImageMaterialData {};
@@@ -366,12 -366,12 +366,12 @@@ class SimpleMaterial : public QSGSimple
  public:
      SimpleMaterial()
      {
-         QFile vf(":defaultshaders/imagevertex.shader");
+         QFile vf(QStringLiteral(":defaultshaders/imagevertex.shader"));
          vf.open(QFile::ReadOnly);
          m_vertex_code = QByteArray(SHADER_DEFINES)
              + vf.readAll();
  
-         QFile ff(":defaultshaders/imagefragment.shader");
+         QFile ff(QStringLiteral(":defaultshaders/imagefragment.shader"));
          ff.open(QFile::ReadOnly);
          m_fragment_code = QByteArray(SHADER_DEFINES)
              + ff.readAll();
  
      void activate() {
          QSGSimpleMaterialShader<SimpleMaterialData>::activate();
- #ifndef QT_OPENGL_ES_2
+ #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
          glEnable(GL_POINT_SPRITE);
          glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
  #endif
  
      void deactivate() {
          QSGSimpleMaterialShader<SimpleMaterialData>::deactivate();
- #ifndef QT_OPENGL_ES_2
+ #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN)
          glDisable(GL_POINT_SPRITE);
          glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
  #endif
          QSGSimpleMaterialShader<SimpleMaterialData>::initialize();
          program()->bind();
          program()->setUniformValue("texture", 0);
-         glFuncs = QGLContext::currentContext()->functions();
+         glFuncs = QOpenGLContext::currentContext()->functions();
          m_timestamp_id = program()->uniformLocation("timestamp");
          m_entry_id = program()->uniformLocation("entry");
      }
      int m_entry_id;
      QByteArray m_vertex_code;
      QByteArray m_fragment_code;
-     QGLFunctions* glFuncs;
+     QOpenGLFunctions* glFuncs;
  };
  
  void fillUniformArrayFromImage(float* array, const QImage& img, int size)
@@@ -629,11 -629,11 +629,11 @@@ QSGImageParticle::QSGImageParticle(QSGI
      , m_blueVariation(0.0)
      , m_rotation(0)
      , m_autoRotation(false)
 -    , m_xVector(0)
 -    , m_yVector(0)
      , m_rotationVariation(0)
      , m_rotationSpeed(0)
      , m_rotationSpeedVariation(0)
 +    , m_xVector(0)
 +    , m_yVector(0)
      , m_spriteEngine(0)
      , m_bloat(false)
      , perfLevel(Unknown)
@@@ -871,9 -871,9 +871,9 @@@ void QSGImageParticle::createEngine(
  }
  
  static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
-     { 0, 2, GL_FLOAT },             // Position
-     { 1, 4, GL_FLOAT },             // Data
-     { 2, 4, GL_FLOAT }             // Vectors
+     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
+     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
+     QSGGeometry::Attribute::create(2, 4, GL_FLOAT)             // Vectors
  };
  
  static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
  };
  
  static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
-     { 0, 2, GL_FLOAT },             // Position
-     { 1, 4, GL_FLOAT },             // Data
-     { 2, 4, GL_FLOAT },             // Vectors
-     { 3, 4, GL_UNSIGNED_BYTE },     // Colors
+     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
+     QSGGeometry::Attribute::create(1, 4, GL_FLOAT),             // Data
+     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Vectors
+     QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE),     // Colors
  };
  
  static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
  };
  
  static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
-     { 0, 2, GL_FLOAT },             // Position
-     { 1, 2, GL_FLOAT },             // TexCoord
-     { 2, 4, GL_FLOAT },             // Data
-     { 3, 4, GL_FLOAT },             // Vectors
-     { 4, 4, GL_UNSIGNED_BYTE },     // Colors
-     { 5, 4, GL_FLOAT },             // DeformationVectors
-     { 6, 3, GL_FLOAT },             // Rotation
+     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
+     QSGGeometry::Attribute::create(1, 2, GL_FLOAT),             // TexCoord
+     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Data
+     QSGGeometry::Attribute::create(3, 4, GL_FLOAT),             // Vectors
+     QSGGeometry::Attribute::create(4, 4, GL_UNSIGNED_BYTE),     // Colors
+     QSGGeometry::Attribute::create(5, 4, GL_FLOAT),             // DeformationVectors
+     QSGGeometry::Attribute::create(6, 3, GL_FLOAT),             // Rotation
  };
  
  static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
  };
  
  static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
-     { 0, 2, GL_FLOAT },             // Position
-     { 1, 2, GL_FLOAT },             // TexCoord
-     { 2, 4, GL_FLOAT },             // Data
-     { 3, 4, GL_FLOAT },             // Vectors
-     { 4, 4, GL_UNSIGNED_BYTE },     // Colors
-     { 5, 4, GL_FLOAT },             // DeformationVectors
-     { 6, 3, GL_FLOAT },             // Rotation
-     { 7, 4, GL_FLOAT }              // Anim Data
+     QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),             // Position
+     QSGGeometry::Attribute::create(1, 2, GL_FLOAT),             // TexCoord
+     QSGGeometry::Attribute::create(2, 4, GL_FLOAT),             // Data
+     QSGGeometry::Attribute::create(3, 4, GL_FLOAT),             // Vectors
+     QSGGeometry::Attribute::create(4, 4, GL_UNSIGNED_BYTE),     // Colors
+     QSGGeometry::Attribute::create(5, 4, GL_FLOAT),             // DeformationVectors
+     QSGGeometry::Attribute::create(6, 3, GL_FLOAT),             // Rotation
+     QSGGeometry::Attribute::create(7, 4, GL_FLOAT)              // Anim Data
  };
  
  static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
@@@ -1001,7 -1001,7 +1001,7 @@@ QSGGeometryNode* QSGImageParticle::buil
          sizetable = QImage(m_sizetable_name.toLocalFile());
          opacitytable = QImage(m_opacitytable_name.toLocalFile());
          if (colortable.isNull())
-             colortable = QImage(":defaultshaders/identitytable.png");
+             colortable = QImage(QStringLiteral(":defaultshaders/identitytable.png"));
          Q_ASSERT(!colortable.isNull());
          getState<ImageMaterialData>(m_material)->colorTable = sceneGraphEngine()->createTextureFromImage(colortable);
          fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE);
          m_material->setFlag(QSGMaterial::Blending);
      }
  
 -    foreach (const QString &str, m_particles){
 +    foreach (const QString &str, m_groups){
          int gIdx = m_system->m_groupIds[str];
          int count = m_system->m_groupData[gIdx]->size();
          QSGGeometryNode* node = new QSGGeometryNode();
@@@ -1151,7 -1151,7 +1151,7 @@@ void QSGImageParticle::prepareNextFrame
          //Advance State
          getState<ImageMaterialData>(m_material)->animcount = m_spriteEngine->spriteCount();
          m_spriteEngine->updateSprites(timeStamp);
 -        foreach (const QString &str, m_particles){
 +        foreach (const QString &str, m_groups){
              int gIdx = m_system->m_groupIds[str];
              int count = m_system->m_groupData[gIdx]->size();
  
@@@ -1199,7 -1199,7 +1199,7 @@@ void QSGImageParticle::initialize(int g
              datum->animT = datum->t;
              datum->animIdx = 0;
              if (m_spriteEngine){
 -                m_spriteEngine->startSprite(spriteIdx);
 +                m_spriteEngine->start(spriteIdx);
                  datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx);
                  datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
              }else{
@@@ -45,6 -45,7 +45,7 @@@
  #include "qsgdirection_p.h"
  #include <QDeclarativeListProperty>
  #include <qsgsimplematerial.h>
+ #include <QtGui/qcolor.h>
  
  QT_BEGIN_HEADER
  
@@@ -56,7 -57,7 +57,7 @@@ class ImageMaterialData
  class QSGGeometryNode;
  
  class QSGSprite;
 -class QSGSpriteEngine;
 +class QSGStochasticEngine;
  
  struct SimpleVertex {
      float x;
@@@ -186,7 -187,7 +187,7 @@@ public
  
  
      QDeclarativeListProperty<QSGSprite> sprites();
 -    QSGSpriteEngine* spriteEngine() {return m_spriteEngine;}
 +    QSGStochasticEngine* spriteEngine() {return m_spriteEngine;}
  
      enum EntryEffect {
          None = 0,
@@@ -50,7 -50,7 +50,7 @@@
  #include <QDir>
  #include <QStyle>
  #include <QInputContext>
- #include <private/qapplication_p.h>
+ #include <QtWidgets/5.0.0/QtWidgets/private/qapplication_p.h>
  #include <private/qsgdistancefieldglyphcache_p.h>
  #include <QtOpenGL/QGLShaderProgram>
  #include <math.h>
@@@ -156,9 -156,6 +156,6 @@@ private
  };
  void tst_qsgtextinput::initTestCase()
  {
-     QSGView canvas;
-     if (!QGLShaderProgram::hasOpenGLShaderPrograms(canvas.context()))
-         QSKIP("TextInput item needs OpenGL 2.0", SkipAll);
  }
  
  void tst_qsgtextinput::cleanupTestCase()
@@@ -964,9 -961,10 +961,10 @@@ void tst_qsgtextinput::dragMouseSelecti
      QSGView canvas(QUrl::fromLocalFile(qmlfile));
  
      canvas.show();
-     QApplication::setActiveWindow(&canvas);
+     canvas.requestActivateWindow();
      QTest::qWaitForWindowShown(&canvas);
-     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+     QTRY_COMPARE(canvas.windowState(), Qt::WindowActive);
  
      QVERIFY(canvas.rootObject() != 0);
      QSGTextInput *textInputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
@@@ -1022,9 -1020,9 +1020,9 @@@ void tst_qsgtextinput::mouseSelectionMo
      QSGView canvas(QUrl::fromLocalFile(qmlfile));
  
      canvas.show();
-     QApplication::setActiveWindow(&canvas);
+     canvas.requestActivateWindow();
      QTest::qWaitForWindowShown(&canvas);
-     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+     QTRY_COMPARE(canvas.windowState(), Qt::WindowActive);
  
      QVERIFY(canvas.rootObject() != 0);
      QSGTextInput *textInputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
@@@ -1066,9 -1064,9 +1064,9 @@@ void tst_qsgtextinput::horizontalAlignm
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/horizontalAlignment.qml"));
  
      canvas.show();
-     QApplication::setActiveWindow(&canvas);
+     canvas.requestActivateWindow();
      QTest::qWaitForWindowShown(&canvas);
-     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+     QTRY_COMPARE(canvas.windowState(), Qt::WindowActive);
      QObject *ob = canvas.rootObject();
      QVERIFY(ob != 0);
      ob->setProperty("horizontalAlignment",hAlign);
@@@ -1197,8 -1195,7 +1195,7 @@@ void tst_qsgtextinput::positionAt(
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/positionAt.qml"));
      QVERIFY(canvas.rootObject() != 0);
      canvas.show();
-     canvas.setFocus();
-     QApplication::setActiveWindow(&canvas);
+     canvas.requestActivateWindow();
      QTest::qWaitForWindowShown(&canvas);
  
      QSGTextInput *textinputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
@@@ -1329,8 -1326,7 +1326,7 @@@ void tst_qsgtextinput::maxLength(
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/maxLength.qml"));
      QVERIFY(canvas.rootObject() != 0);
      canvas.show();
-     canvas.setFocus();
-     QApplication::setActiveWindow(&canvas);
+     canvas.requestActivateWindow();
      QTest::qWaitForWindowShown(&canvas);
  
      QSGTextInput *textinputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
@@@ -1359,7 -1355,7 +1355,7 @@@ void tst_qsgtextinput::masks(
      //QString componentStr = "import QtQuick 2.0\nTextInput {  inputMask: 'HHHHhhhh'; }";
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/masks.qml"));
      canvas.show();
-     canvas.setFocus();
+     canvas.requestActivateWindow();
      QVERIFY(canvas.rootObject() != 0);
      QSGTextInput *textinputObject = qobject_cast<QSGTextInput *>(canvas.rootObject());
      QVERIFY(textinputObject != 0);
@@@ -1383,7 -1379,7 +1379,7 @@@ void tst_qsgtextinput::validators(
  
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/validators.qml"));
      canvas.show();
-     canvas.setFocus();
+     canvas.requestActivateWindow();
  
      QVERIFY(canvas.rootObject() != 0);
  
@@@ -1471,8 -1467,7 +1467,7 @@@ void tst_qsgtextinput::inputMethods(
  {
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/inputmethods.qml"));
      canvas.show();
-     canvas.setFocus();
-     QApplication::setActiveWindow(&canvas);
+     canvas.requestActivateWindow();
      QTest::qWaitForWindowShown(&canvas);
  
      // test input method hints
@@@ -1519,7 -1514,7 +1514,7 @@@ void tst_qsgtextinput::navigation(
  {
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/navigation.qml"));
      canvas.show();
-     canvas.setFocus();
+     canvas.requestActivateWindow();
  
      QVERIFY(canvas.rootObject() != 0);
  
@@@ -1558,7 -1553,7 +1553,7 @@@ void tst_qsgtextinput::navigation_RTL(
  {
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/navigation.qml"));
      canvas.show();
-     canvas.setFocus();
+     canvas.requestActivateWindow();
  
      QVERIFY(canvas.rootObject() != 0);
  
@@@ -1730,7 -1725,7 +1725,7 @@@ void tst_qsgtextinput::cursorDelegate(
  {
      QSGView view(QUrl::fromLocalFile(SRCDIR "/data/cursorTest.qml"));
      view.show();
-     view.setFocus();
+     view.requestActivateWindow();
      QSGTextInput *textInputObject = view.rootObject()->findChild<QSGTextInput*>("textInputObject");
      QVERIFY(textInputObject != 0);
      QVERIFY(textInputObject->findChild<QSGItem*>("cursorInstance"));
@@@ -1756,10 -1751,9 +1751,9 @@@ void tst_qsgtextinput::cursorVisible(
  {
      QSGView view(QUrl::fromLocalFile(SRCDIR "/data/cursorVisible.qml"));
      view.show();
-     QApplication::setActiveWindow(&view);
+     view.requestActivateWindow();
      QTest::qWaitForWindowShown(&view);
-     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
-     view.setFocus();
+     QTRY_COMPARE(view.windowState(), Qt::WindowActive);
  
      QSGTextInput input;
      QSignalSpy spy(&input, SIGNAL(cursorVisibleChanged(bool)));
      QCOMPARE(input.isCursorVisible(), true);
      QCOMPARE(spy.count(), 5);
  
-     view.clearFocus();
+     view.setWindowState(Qt::WindowNoState);
      QCOMPARE(input.isCursorVisible(), false);
      QCOMPARE(spy.count(), 6);
  
-     view.setFocus();
+     view.requestActivateWindow();
      QCOMPARE(input.isCursorVisible(), true);
      QCOMPARE(spy.count(), 7);
  
      QCOMPARE(input.isCursorVisible(), false);
      QCOMPARE(spy.count(), 8);
  
-     QApplication::setActiveWindow(&view);
-     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&view));
+     view.requestActivateWindow();
+     QTRY_COMPARE(view.windowState(), Qt::WindowActive);
      QCOMPARE(input.isCursorVisible(), true);
      QCOMPARE(spy.count(), 9);
  #endif
@@@ -1870,7 -1864,7 +1864,7 @@@ void tst_qsgtextinput::readOnly(
  {
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/readOnly.qml"));
      canvas.show();
-     canvas.setFocus();
+     canvas.requestActivateWindow();
  
      QVERIFY(canvas.rootObject() != 0);
  
@@@ -1897,10 -1891,9 +1891,9 @@@ void tst_qsgtextinput::echoMode(
  {
      QSGView canvas(QUrl::fromLocalFile(SRCDIR "/data/echoMode.qml"));
      canvas.show();
-     canvas.setFocus();
-     QApplication::setActiveWindow(&canvas);
+     canvas.requestActivateWindow();
      QTest::qWaitForWindowShown(&canvas);
-     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&canvas));
+     QTRY_COMPARE(canvas.windowState(), Qt::WindowActive);
  
      QVERIFY(canvas.rootObject() != 0);
  
@@@ -2268,7 -2261,7 +2261,7 @@@ public
      virtual QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data)
      {
         nbPaint++;
 -//       return QSGTextInput::updatePaintNode(node, data);
 +       return QSGTextInput::updatePaintNode(node, data);
      }
      int nbPaint;
  };