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)
  
@@@ -720,44 -541,14 +724,51 @@@ static v8::Handle<v8::Value> ctx2d_glob
      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());
@@@ -2107,632 -1271,391 +2118,646 @@@ static v8::Handle<v8::Value> ctx2d_draw
  }
  
  // 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
@@@ -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