QQuickCanvas renames
[profile/ivi/qtdeclarative.git] / src / quick / items / context2d / qquickcontext2d.cpp
index 3025394..2a99a2e 100644 (file)
@@ -1,10 +1,9 @@
 /****************************************************************************
 **
 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Contact: http://www.qt-project.org/
 **
-** This file is part of the QtDeclarative module of the Qt Toolkit.
+** This file is part of the QtQml module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
 ** GNU Lesser General Public License Usage
@@ -35,6 +34,7 @@
 **
 **
 **
+**
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
 #include "qquickcontext2d_p.h"
 #include "qquickcontext2dcommandbuffer_p.h"
 #include "qquickcanvasitem_p.h"
+#include <private/qquickcontext2dtexture_p.h>
 #include <private/qquickitem_p.h>
 #include <QtQuick/private/qquickshadereffectsource_p.h>
 #include <QtGui/qopenglframebufferobject.h>
 
-#include <QtCore/qdebug.h>
 #include <QtQuick/private/qsgcontext_p.h>
-#include <private/qdeclarativesvgparser_p.h>
-#include <private/qdeclarativepath_p.h>
+#include <private/qquicksvgparser_p.h>
+#include <private/qquickpath_p.h>
 
 #include <private/qquickimage_p_p.h>
 
 #include <QtGui/qguiapplication.h>
-#include <qdeclarativeinfo.h>
+#include <qqmlinfo.h>
 #include <QtCore/qmath.h>
 #include <private/qv8engine_p.h>
 
-#include <qdeclarativeengine.h>
+#include <qqmlengine.h>
 #include <private/qv8domerrors_p.h>
 #include <QtCore/qnumeric.h>
+#include <private/qquickwindow_p.h>
+#include <private/qquickwindowmanager_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+
+#ifdef Q_OS_QNX
+#include <ctype.h>
+#endif
 
 QT_BEGIN_NAMESPACE
 /*!
     \qmlclass Context2D QQuickContext2D
     \inqmlmodule QtQuick 2
+    \ingroup qtquick-canvas
     \since QtQuick 2.0
-    \brief The Context2D API allows you to draw 2d graphic shapes on the \c Canvas item.
+    \brief Provides 2D context for shapes on a Canvas item
 
-    The Context2D object can be created by \c Canvas item's \c getContext() method:
+    The Context2D object can be created by \c Canvas item's \c getContext()
+    method:
     \code
     Canvas {
       id:canvas
@@ -79,33 +89,36 @@ QT_BEGIN_NAMESPACE
       }
     }
     \endcode
-    The Context2D API implements the same \l {http://www.w3.org/TR/2dcontext}{W3C Canvas 2D Context API standard}
-    with some enhanced features.
+    The Context2D API implements the same \l
+    {http://www.w3.org/TR/2dcontext}{W3C Canvas 2D Context API standard} with
+    some enhanced features.
 
-    The Context2D API provides the rendering \bold{context} which defines the methods and attributes needed to draw
-    on the \c Canvas item. The following assigns the canvas rendering context to a \c{context}
-    variable:
+    The Context2D API provides the rendering \b{context} which defines the
+    methods and attributes needed to draw on the \c Canvas item. The following
+    assigns the canvas rendering context to a \c{context} variable:
     \code
     var context = mycanvas.getContext("2d")
     \endcode
 
-    The Context2D API renders the canvas as a coordinate system whose origin (0,0) is
-    at the top left corner, as shown in the figure below. Coordinates increase along
-    the \c{x} axis from left to right and along the \c{y} axis from top to bottom of
-    the canvas.
+    The Context2D API renders the canvas as a coordinate system whose origin
+    (0,0) is at the top left corner, as shown in the figure below. Coordinates
+    increase along the \c{x} axis from left to right and along the \c{y} axis
+    from top to bottom of the canvas.
     \image qml-item-canvas-context.gif
 */
 
+
+
 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
 
 static const double Q_PI   = 3.14159265358979323846;   // pi
 
 #define DEGREES(t) ((t) * 180.0 / Q_PI)
 
-#define CHECK_CONTEXT(r)     if (!r || !r->context || !r->context->buffer()) \
+#define CHECK_CONTEXT(r)     if (!r || !r->context || !r->context->bufferValid()) \
                                 V8THROW_ERROR("Not a Context2D object");
 
-#define CHECK_CONTEXT_SETTER(r)     if (!r || !r->context || !r->context->buffer()) \
+#define CHECK_CONTEXT_SETTER(r)     if (!r || !r->context || !r->context->bufferValid()) \
                                        V8THROW_ERROR_SETTER("Not a Context2D object");
 #define qClamp(val, min, max) qMin(qMax(val, min), max)
 #define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
@@ -175,7 +188,7 @@ QColor qt_color_from_string(v8::Local<v8::Value> name)
         if (*p != ')') return QColor();
         if (isRgb)
             return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)));
-        else
+        else if (isHsl)
             return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255));
     }
     return QColor();
@@ -185,7 +198,7 @@ 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(" "));
+     const QStringList tokens = fontString.split(QLatin1Char(' '));
      foreach (const QString &token, tokens) {
          if (token == QLatin1String("italic"))
              font.setItalic(true);
@@ -224,7 +237,7 @@ class QV8Context2DResource : public QV8ObjectResource
 {
     V8_RESOURCE_TYPE(Context2DType)
 public:
-    QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
+    QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e), context(0) {}
     QQuickContext2D* context;
 };
 
@@ -474,8 +487,6 @@ static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
     CHECK_CONTEXT(r)
 
     r->context->reset();
-    r->context->m_path = QPainterPath();
-    r->context->m_path.setFillRule(Qt::WindingFill);
 
     return args.This();
 }
@@ -489,22 +500,22 @@ static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
     Each state consists of the current transformation matrix, clipping region,
     and values of the following attributes:
     \list
-    \o\a QtQuick2::Context2D::strokeStyle
-    \o\a QtQuick2::Context2D::fillStyle
-    \o\a QtQuick2::Context2D::fillRule
-    \o\a QtQuick2::Context2D::globalAlpha
-    \o\a QtQuick2::Context2D::lineWidth
-    \o\a QtQuick2::Context2D::lineCap
-    \o\a QtQuick2::Context2D::lineJoin
-    \o\a QtQuick2::Context2D::miterLimit
-    \o\a QtQuick2::Context2D::shadowOffsetX
-    \o\a QtQuick2::Context2D::shadowOffsetY
-    \o\a QtQuick2::Context2D::shadowBlur
-    \o\a QtQuick2::Context2D::shadowColor
-    \o\a QtQuick2::Context2D::globalCompositeOperation
-    \o\a QtQuick2::Context2D::font
-    \o\a QtQuick2::Context2D::textAlign
-    \o\a QtQuick2::Context2D::textBaseline
+    \li\a QtQuick2::Context2D::strokeStyle
+    \li\a QtQuick2::Context2D::fillStyle
+    \li\a QtQuick2::Context2D::fillRule
+    \li\a QtQuick2::Context2D::globalAlpha
+    \li\a QtQuick2::Context2D::lineWidth
+    \li\a QtQuick2::Context2D::lineCap
+    \li\a QtQuick2::Context2D::lineJoin
+    \li\a QtQuick2::Context2D::miterLimit
+    \li\a QtQuick2::Context2D::shadowOffsetX
+    \li\a QtQuick2::Context2D::shadowOffsetY
+    \li\a QtQuick2::Context2D::shadowBlur
+    \li\a QtQuick2::Context2D::shadowColor
+    \li\a QtQuick2::Context2D::globalCompositeOperation
+    \li\a QtQuick2::Context2D::font
+    \li\a QtQuick2::Context2D::textAlign
+    \li\a QtQuick2::Context2D::textBaseline
     \endlist
 
     The current path is NOT part of the drawing state. The path can be reset by
@@ -541,15 +552,8 @@ 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)  {
-        qreal angle = args[0]->NumberValue();
-        if (!qIsFinite(angle))
-            return args.This();
-
-        r->context->state.matrix.rotate(DEGREES(angle));
-        r->context->buffer()->updateMatrix(r->context->state.matrix);
-    }
-
+    if (args.Length() == 1)
+        r->context->rotate(args[0]->NumberValue());
     return args.This();
 }
 
@@ -573,17 +577,8 @@ static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
     CHECK_CONTEXT(r)
 
 
-    if (args.Length() == 2) {
-        qreal x, y;
-        x = args[0]->NumberValue();
-        y = args[1]->NumberValue();
-        if (!qIsFinite(x) || !qIsFinite(y))
-            return args.This();
-
-        r->context->state.matrix.scale(x, y);
-        r->context->buffer()->updateMatrix(r->context->state.matrix);
-    }
-
+    if (args.Length() == 2)
+        r->context->scale(args[0]->NumberValue(), args[1]->NumberValue());
     return args.This();
 }
 
@@ -600,19 +595,19 @@ static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
     \image qml-item-canvas-math.png
     where:
     \list
-    \o \c{a} is the scale factor in the horizontal (x) direction
+    \li \c{a} is the scale factor in the horizontal (x) direction
     \image qml-item-canvas-scalex.png
-    \o \c{c} is the skew factor in the x direction
+    \li \c{c} is the skew factor in the x direction
     \image qml-item-canvas-canvas-skewx.png
-    \o \c{e} is the translation in the x direction
+    \li \c{e} is the translation in the x direction
     \image qml-item-canvas-canvas-translate.png
-    \o \c{b} is the skew factor in the y (vertical) direction
+    \li \c{b} is the skew factor in the y (vertical) direction
     \image qml-item-canvas-canvas-skewy.png
-    \o \c{d} is the scale factor in the y direction
+    \li \c{d} is the scale factor in the y direction
     \image qml-item-canvas-canvas-scaley.png
-    \o \c{f} is the translation in the y direction
+    \li \c{f} is the translation in the y direction
     \image qml-item-canvas-canvas-translatey.png
-    \o the last row remains constant
+    \li the last row remains constant
     \endlist
     The scale factors and skew factors are multiples; \c{e} and \c{f} are
     coordinate space units, just like the units in the \a QtQuick2::Context2D::translate(x,y)
@@ -626,25 +621,13 @@ static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
     CHECK_CONTEXT(r)
 
 
-    if (args.Length() == 6) {
-        qreal a = args[0]->NumberValue();
-        qreal b = args[1]->NumberValue();
-        qreal c = args[2]->NumberValue();
-        qreal d = args[3]->NumberValue();
-        qreal e = args[4]->NumberValue();
-        qreal f = args[5]->NumberValue();
-
-        if (!qIsFinite(a)
-         || !qIsFinite(b)
-         || !qIsFinite(c)
-         || !qIsFinite(d)
-         || !qIsFinite(e)
-         || !qIsFinite(f))
-            return args.This();
-
-        r->context->state.matrix = QTransform(a, b, c, d, e, f);
-        r->context->buffer()->updateMatrix(r->context->state.matrix);
-    }
+    if (args.Length() == 6)
+        r->context->setTransform( args[0]->NumberValue()
+                                                        , args[1]->NumberValue()
+                                                        , args[2]->NumberValue()
+                                                        , args[3]->NumberValue()
+                                                        , args[4]->NumberValue()
+                                                        , args[5]->NumberValue());
 
     return args.This();
 }
@@ -665,25 +648,13 @@ static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
     CHECK_CONTEXT(r)
 
 
-    if (args.Length() == 6) {
-        qreal a = args[0]->NumberValue();
-        qreal b = args[1]->NumberValue();
-        qreal c = args[2]->NumberValue();
-        qreal d = args[3]->NumberValue();
-        qreal e = args[4]->NumberValue();
-        qreal f = args[5]->NumberValue();
-
-        if (!qIsFinite(a)
-         || !qIsFinite(b)
-         || !qIsFinite(c)
-         || !qIsFinite(d)
-         || !qIsFinite(e)
-         || !qIsFinite(f))
-            return args.This();
-
-        r->context->state.matrix *= QTransform(a, b, c, d, e, f);
-        r->context->buffer()->updateMatrix(r->context->state.matrix);
-    }
+    if (args.Length() == 6)
+        r->context->transform( args[0]->NumberValue()
+                                                  , args[1]->NumberValue()
+                                                  , args[2]->NumberValue()
+                                                  , args[3]->NumberValue()
+                                                  , args[4]->NumberValue()
+                                                  , args[5]->NumberValue());
 
     return args.This();
 }
@@ -703,17 +674,8 @@ static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
     CHECK_CONTEXT(r)
 
 
-    if (args.Length() == 2) {
-        qreal x = args[0]->NumberValue();
-        qreal y = args[1]->NumberValue();
-
-        if (!qIsFinite(x) || !qIsFinite(y))
-            return args.This();
-
-        r->context->state.matrix.translate(x, y);
-        r->context->buffer()->updateMatrix(r->context->state.matrix);
-    }
-
+    if (args.Length() == 2)
+            r->context->translate(args[0]->NumberValue(), args[1]->NumberValue());
     return args.This();
 }
 
@@ -729,8 +691,7 @@ static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
     CHECK_CONTEXT(r)
 
-    r->context->state.matrix = QTransform();
-    r->context->buffer()->updateMatrix(r->context->state.matrix);
+    r->context->setTransform(1, 0, 0, 1, 0, 0);
 
     return args.This();
 }
@@ -745,16 +706,9 @@ static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
     CHECK_CONTEXT(r)
 
-    if (args.Length() == 2) {
-        qreal sh = args[0]->NumberValue();
-        qreal sv = args[1]->NumberValue();
-
-        if (!qIsFinite(sh) || !qIsFinite(sv))
-            return args.This();
+    if (args.Length() == 2)
+            r->context->shear(args[0]->NumberValue(), args[1]->NumberValue());
 
-        r->context->state.matrix.shear(sh, sv);
-        r->context->buffer()->updateMatrix(r->context->state.matrix);
-    }
     return args.This();
 }
 // compositing
@@ -793,22 +747,22 @@ static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> va
     \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.
+     \li 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.
+     \li 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.
+     \li 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.
+     \li 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.
+     \li destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
+     \li destination-in   - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
+     \li destination-out  - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
+     \li destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
+     \li lighter          - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
+     \li copy             - A (B is ignored). Display the source image instead of the destination image.
+     \li xor              - A xor B. Exclusive OR of the source image and destination image.
      \endlist
 
      Additionally, this property also accepts the compositon modes listed in \a {QPainter::CompositionMode}. According to the W3C standard, these
@@ -852,12 +806,12 @@ static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<
      The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object. Invalid values are ignored.
      This property accepts several color syntaxes:
      \list
-     \o 'rgb(red, green, blue)' - for example: 'rgb(255, 100, 55)' or 'rgb(100%, 70%, 30%)'
-     \o 'rgba(red, green, blue, alpha)' - for example: 'rgb(255, 100, 55, 1.0)' or 'rgb(100%, 70%, 30%, 0.5)'
-     \o 'hsl(hue, saturation, lightness)'
-     \o 'hsla(hue, saturation, lightness, alpha)'
-     \o '#RRGGBB' - for example: '#00FFCC'
-     \o Qt.rgba(red, green, blue, alpha) - for example: Qt.rgba(0.3, 0.7, 1, 1.0)
+     \li 'rgb(red, green, blue)' - for example: 'rgb(255, 100, 55)' or 'rgb(100%, 70%, 30%)'
+     \li 'rgba(red, green, blue, alpha)' - for example: 'rgb(255, 100, 55, 1.0)' or 'rgb(100%, 70%, 30%, 0.5)'
+     \li 'hsl(hue, saturation, lightness)'
+     \li 'hsla(hue, saturation, lightness, alpha)'
+     \li '#RRGGBB' - for example: '#00FFCC'
+     \li Qt.rgba(red, green, blue, alpha) - for example: Qt.rgba(0.3, 0.7, 1, 1.0)
      \endlist
      If the \a fillStyle or \a strokeStyle is assigned many times in a loop, the last Qt.rgba() syntax should be chosen, as it has the
      best performance, because it's already a valid QColor value, does not need to be parsed everytime.
@@ -925,8 +879,8 @@ static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> valu
     \qmlproperty enumeration QtQuick2::Context2D::fillRule
      Holds the current fill rule used for filling shapes. The following fill rules supported:
      \list
-     \o Qt.OddEvenFill
-     \o Qt.WindingFill
+     \li Qt.OddEvenFill
+     \li Qt.WindingFill
      \endlist
      Note: Unlike the \a QPainterPath, the Canvas API uses the winding fill as the default fill rule.
      The fillRule property is part of the context rendering state.
@@ -1065,8 +1019,10 @@ static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &arg
         if (!qIsFinite(x0)
          || !qIsFinite(y0)
          || !qIsFinite(x1)
-         || !qIsFinite(y1))
+         || !qIsFinite(y1)) {
+            delete r;
             V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
+        }
 
         r->brush = QLinearGradient(x0, y0, x1, y1);
         gradient->SetExternalResource(r);
@@ -1114,8 +1070,10 @@ static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &arg
          || !qIsFinite(x1)
          || !qIsFinite(r0)
          || !qIsFinite(r1)
-         || !qIsFinite(y1))
+         || !qIsFinite(y1)) {
+            delete r;
             V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
+        }
 
         if (r0 < 0 || r1 < 0)
             V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
@@ -1158,11 +1116,15 @@ static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &ar
         qreal x = args[0]->NumberValue();
         qreal y = args[1]->NumberValue();
         qreal angle = DEGREES(args[2]->NumberValue());
-        if (!qIsFinite(x) || !qIsFinite(y))
+        if (!qIsFinite(x) || !qIsFinite(y)) {
+            delete r;
             V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
+        }
 
-        if (!qIsFinite(angle))
+        if (!qIsFinite(angle)) {
+            delete r;
             V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
+        }
 
         r->brush = QConicalGradient(x, y, angle);
         gradient->SetExternalResource(r);
@@ -1177,20 +1139,20 @@ static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &ar
   Returns a CanvasPattern object that uses the given \c color and \c patternMode.
   The valid pattern modes are:
     \list
-    \o Qt.SolidPattern
-    \o Qt.Dense1Pattern
-    \o Qt.Dense2Pattern
-    \o Qt.Dense3Pattern
-    \o Qt.Dense4Pattern
-    \o Qt.Dense5Pattern
-    \o Qt.Dense6Pattern
-    \o Qt.Dense7Pattern
-    \o Qt.HorPattern
-    \o Qt.VerPattern
-    \o Qt.CrossPattern
-    \o Qt.BDiagPattern
-    \o Qt.FDiagPattern
-    \o Qt.DiagCrossPattern
+    \li Qt.SolidPattern
+    \li Qt.Dense1Pattern
+    \li Qt.Dense2Pattern
+    \li Qt.Dense3Pattern
+    \li Qt.Dense4Pattern
+    \li Qt.Dense5Pattern
+    \li Qt.Dense6Pattern
+    \li Qt.Dense7Pattern
+    \li Qt.HorPattern
+    \li Qt.VerPattern
+    \li Qt.CrossPattern
+    \li Qt.BDiagPattern
+    \li Qt.FDiagPattern
+    \li Qt.DiagCrossPattern
 \endlist
     \sa Qt::BrushStyle
  */
@@ -1203,10 +1165,10 @@ static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &ar
   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
+  \li "repeat"    - both directions
+  \li "repeat-x   - horizontal only
+  \li "repeat-y"  - vertical only
+  \li "no-repeat" - neither
   \endlist
 
   If the repetition argument is empty or null, the value "repeat" is used.
@@ -1243,7 +1205,7 @@ static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
                     patternTexture = pixelData->image;
                 }
             } else {
-                patternTexture = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
+                patternTexture = r->context->createPixmap(QUrl(engine->toString(args[0]->ToString())))->image();
             }
 
             if (!patternTexture.isNull()) {
@@ -1281,9 +1243,9 @@ static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
      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.
+    \li butt - the end of each line has a flat edge perpendicular to the direction of the line, this is the default line cap value.
+    \li 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.
+    \li 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.
 */
@@ -1339,9 +1301,9 @@ static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value,
 
     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.
+    \li bevel - this is all that is rendered at joins.
+    \li 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.
+    \li 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.
 */
@@ -1379,7 +1341,7 @@ static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value
     else if (lineJoin == QLatin1String("bevel"))
         join = Qt::BevelJoin;
     else if (lineJoin == QLatin1String("miter"))
-        join = Qt::MiterJoin;
+        join = Qt::SvgMiterJoin;
     else
         return;
 
@@ -1565,12 +1527,12 @@ static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, co
 
     r->context->beginPath();
     if (value->IsObject()) {
-        QDeclarativePath* path = qobject_cast<QDeclarativePath*>(engine->toQObject(value));
+        QQuickPath* path = qobject_cast<QQuickPath*>(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);
+        QQuickSvgParser::parsePathDataFast(path, r->context->m_path);
     }
     r->context->m_v8path = value;
 }
@@ -1586,17 +1548,11 @@ static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
     CHECK_CONTEXT(r)
 
 
-    if (args.Length() == 4) {
-        qreal x = args[0]->NumberValue();
-        qreal y = args[1]->NumberValue();
-        qreal w = args[2]->NumberValue();
-        qreal h = args[3]->NumberValue();
-
-        if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
-            return args.This();
-
-        r->context->buffer()->clearRect(x, y, w, h);
-    }
+    if (args.Length() == 4)
+        r->context->clearRect(args[0]->NumberValue(),
+                              args[1]->NumberValue(),
+                              args[2]->NumberValue(),
+                              args[3]->NumberValue());
 
     return args.This();
 }
@@ -1611,18 +1567,8 @@ static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
     CHECK_CONTEXT(r)
 
-    if (args.Length() == 4) {
-        qreal x = args[0]->NumberValue();
-        qreal y = args[1]->NumberValue();
-        qreal w = args[2]->NumberValue();
-        qreal h = args[3]->NumberValue();
-
-        if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
-            return args.This();
-
-        r->context->buffer()->fillRect(x, y, w, h);
-    }
-
+    if (args.Length() == 4)
+        r->context->fillRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
     return args.This();
 }
 
@@ -1641,18 +1587,8 @@ static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
     CHECK_CONTEXT(r)
 
-
-    if (args.Length() == 4) {
-        qreal x = args[0]->NumberValue();
-        qreal y = args[1]->NumberValue();
-        qreal w = args[2]->NumberValue();
-        qreal h = args[3]->NumberValue();
-
-        if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
-            return args.This();
-
-        r->context->buffer()->strokeRect(x, y, w, h);
-    }
+    if (args.Length() == 4)
+        r->context->strokeRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
 
     return args.This();
 }
@@ -1662,8 +1598,8 @@ static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
   \qmlmethod object QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
   Adds an arc to the current subpath that lies on the circumference of the circle whose center is at the point (\c x,\cy) and whose radius is \c radius.
   \image qml-item-canvas-arcTo2.png
-  \sa  QtQuick2::Context2D::arcTo
-  See {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
+  \sa QtQuick2::Context2D::arcTo,
+      {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
   */
 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
 {
@@ -1677,15 +1613,8 @@ static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
             antiClockwise = args[5]->BooleanValue();
 
         qreal radius = args[2]->NumberValue();
-        qreal x = args[0]->NumberValue();
-        qreal y = args[1]->NumberValue();
-        qreal sa = args[3]->NumberValue();
-        qreal ea = args[4]->NumberValue();
 
-        if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(sa) || !qIsFinite(ea))
-            return args.This();
-
-        if (radius < 0)
+        if (qIsFinite(radius) && radius < 0)
            V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
 
         r->context->arc(args[0]->NumberValue(),
@@ -1705,9 +1634,9 @@ static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
    Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
    To draw an arc, you begin with the same steps your followed to create a line:
     \list
-    \o Call the context.beginPath() method to set a new path.
-    \o Call the context.moveTo(\c x, \c y) method to set your starting position on the canvas at the point (\c x,\c y).
-    \o To draw an arc or circle, call the context.arcTo(\c x1, \c y1, \c x2, \c y2,\c radius) method.
+    \li Call the context.beginPath() method to set a new path.
+    \li Call the context.moveTo(\c x, \c y) method to set your starting position on the canvas at the point (\c x,\c y).
+    \li To draw an arc or circle, call the context.arcTo(\c x1, \c y1, \c x2, \c y2,\c radius) method.
        This adds an arc with starting point (\c x1,\c y1), ending point (\c x2, \c y2), and radius \c radius to the current subpath and connects
        it to the previous subpath by a straight line.
     \endlist
@@ -1716,33 +1645,25 @@ static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
 
     \image qml-item-canvas-startAngle.png
     The anticlockwise has the value TRUE for each arc in the figure above because they are all drawn in the counterclockwise direction.
-  \sa  QtQuick2::Context2D::arc
-  \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d context standard for arcTo}
+  \sa QtQuick2::Context2D::arc, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d
+      context standard for arcTo}
   */
 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
 {
     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
     CHECK_CONTEXT(r)
 
-
-
     if (args.Length() == 5) {
-        qreal x1 = args[0]->NumberValue();
-        qreal y1 = args[1]->NumberValue();
-        qreal x2 = args[2]->NumberValue();
-        qreal y2 = args[3]->NumberValue();
-
-        if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
-            return args.This();
-
         qreal radius = args[4]->NumberValue();
-        if (radius < 0)
+
+        if (qIsFinite(radius) && radius < 0)
            V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
+
         r->context->arcTo(args[0]->NumberValue(),
                           args[1]->NumberValue(),
                           args[2]->NumberValue(),
                           args[3]->NumberValue(),
-                          args[4]->NumberValue());
+                          radius);
     }
 
     return args.This();
@@ -1814,10 +1735,10 @@ static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
    To create a complex shape using the \a clip() method:
 
     \list 1
-    \o Call the \c{context.beginPath()} method to set the clipping path.
-    \o Define the clipping path by calling any combination of the \c{lineTo},
+    \li Call the \c{context.beginPath()} method to set the clipping path.
+    \li Define the clipping path by calling any combination of the \c{lineTo},
     \c{arcTo}, \c{arc}, \c{moveTo}, etc and \c{closePath} methods.
-    \o Call the \c{context.clip()} method.
+    \li Call the \c{context.clip()} method.
     \endlist
 
     The new shape displays.  The following shows how a clipping path can
@@ -1835,14 +1756,7 @@ static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
     CHECK_CONTEXT(r)
 
-    QPainterPath clipPath = r->context->m_path;
-    clipPath.closeSubpath();
-    if (!r->context->state.clipPath.isEmpty())
-        r->context->state.clipPath = clipPath.intersected(r->context->state.clipPath);
-    else
-        r->context->state.clipPath = clipPath;
-    r->context->buffer()->clip(r->context->state.clipPath);
-
+    r->context->clip();
     return args.This();
 }
 
@@ -1877,9 +1791,7 @@ 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 args.This();
 }
 
@@ -1965,19 +1877,8 @@ static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
     CHECK_CONTEXT(r)
 
-
-    if (args.Length() == 4) {
-        qreal x = args[0]->NumberValue();
-        qreal y = args[1]->NumberValue();
-        qreal w = args[2]->NumberValue();
-        qreal h = args[3]->NumberValue();
-
-        if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
-            return args.This();
-
-        r->context->rect(x, y, w, h);
-    }
-
+    if (args.Length() == 4)
+        r->context->rect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
     return args.This();
 }
 
@@ -1992,23 +1893,13 @@ static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
     CHECK_CONTEXT(r)
 
-    if (args.Length() == 6) {
-        qreal x = args[0]->NumberValue();
-        qreal y = args[1]->NumberValue();
-        qreal w = args[2]->NumberValue();
-        qreal h = args[3]->NumberValue();
-        qreal xr = args[4]->NumberValue();
-        qreal yr = args[5]->NumberValue();
-
-        if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
-            return args.This();
-
-        if (!qIsFinite(xr) || !qIsFinite(yr))
-            V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "roundedRect(): Invalid arguments");
-
-        r->context->roundedRect(x, y, w, h, xr, yr);
-    }
-
+    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 args.This();
 }
 
@@ -2026,18 +1917,8 @@ static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
     CHECK_CONTEXT(r)
 
 
-    if (args.Length() == 4) {
-        qreal x = args[0]->NumberValue();
-        qreal y = args[1]->NumberValue();
-        qreal w = args[2]->NumberValue();
-        qreal h = args[3]->NumberValue();
-
-        if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
-            return args.This();
-
-
-        r->context->ellipse(x, y, w, h);
-    }
+    if (args.Length() == 4)
+        r->context->ellipse(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
 
     return args.This();
 }
@@ -2079,9 +1960,7 @@ static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
     CHECK_CONTEXT(r)
 
-
-    r->context->buffer()->stroke(r->context->m_path);
-
+    r->context->stroke();
     return args.This();
 }
 
@@ -2098,32 +1977,30 @@ static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
     CHECK_CONTEXT(r)
 
     bool pointInPath = false;
-    if (args.Length() == 2) {
-        qreal x = args[0]->NumberValue();
-        qreal y = args[1]->NumberValue();
-        if (!qIsFinite(x) || !qIsFinite(y))
-            return v8::Boolean::New(false);
-        pointInPath = r->context->isPointInPath(x, y);
-    }
+    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_drawFocusRing(const v8::Arguments &args)
 {
+    Q_UNUSED(args);
+
     V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
-    return args.This();
 }
 
 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
 {
+    Q_UNUSED(args);
+
     V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
-    return args.This();
 }
 
 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
 {
+    Q_UNUSED(args);
+
     V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
-    return args.This();
 }
 // text
 /*!
@@ -2162,11 +2039,11 @@ static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, co
   Holds the current text alignment settings.
   The possible values are:
   \list
-    \o start
-    \o end
-    \o left
-    \o right
-    \o center
+    \li start
+    \li end
+    \li left
+    \li right
+    \li center
   \endlist
   Other values are ignored. The default value is "start".
   */
@@ -2225,12 +2102,12 @@ static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> valu
   Holds the current baseline alignment settings.
   The possible values are:
   \list
-    \o top
-    \o hanging
-    \o middle
-    \o alphabetic
-    \o ideographic
-    \o bottom
+    \li top
+    \li hanging
+    \li middle
+    \li alphabetic
+    \li ideographic
+    \li bottom
   \endlist
   Other values are ignored. The default value is "alphabetic".
   */
@@ -2321,21 +2198,17 @@ static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
     CHECK_CONTEXT(r)
 
     QV8Engine *engine = V8ENGINE();
-    if (args.Length() == 3) {
-        qreal x = args[1]->NumberValue();
-        qreal y = args[2]->NumberValue();
-        if (!qIsFinite(x) || !qIsFinite(y))
-            return args.This();
-        QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
-        r->context->buffer()->stroke(textPath);
-    }
+    if (args.Length() == 3)
+        r->context->drawText(engine->toString(args[0]), args[1]->NumberValue(), args[2]->NumberValue(), false);
     return args.This();
 }
 /*!
-  \qmlclass QtQuick2::TextMetrics
+  \qmlclass TextMetrics
     \inqmlmodule QtQuick 2
     \since QtQuick 2.0
-    \brief The Context2D TextMetrics interface.
+    \ingroup qtquick-canvas
+    \brief Provides a Context2D TextMetrics interface
+
     The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
     See {http://www.w3.org/TR/2dcontext/#textmetrics}{W3C 2d context TexMetrics} for more details.
 
@@ -2411,7 +2284,7 @@ static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
 /*!
   \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
   This is an overloaded function.
-  Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
+  Draws the given item as \a image from source point (\a sx, \a sy) and source width \a sw, source height \a sh
   onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
 
 
@@ -2440,44 +2313,55 @@ static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
     if (!args.Length())
         return args.This();
 
-    QImage image;
+    //FIXME:This function should be moved to QQuickContext2D::drawImage(...)
+    if (!r->context->state.invertibleCTM)
+        return args.This();
+
+    QQmlRefPointer<QQuickCanvasPixmap> pixmap;
+
     if (args[0]->IsString()) {
         QUrl url(engine->toString(args[0]->ToString()));
         if (!url.isValid())
             V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
 
-        image = r->context->createImage(url);
+        pixmap = r->context->createPixmap(url);
     } else if (args[0]->IsObject()) {
         QQuickImage *imageItem = qobject_cast<QQuickImage*>(engine->toQObject(args[0]->ToObject()));
         QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(engine->toQObject(args[0]->ToObject()));
 
         QV8Context2DPixelArrayResource *pix = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->GetInternalField(0)->ToObject());
-        if (pix) {
-            image = pix->image;
+        if (pix && !pix->image.isNull()) {
+            pixmap.take(new QQuickCanvasPixmap(pix->image, r->context->canvas()->window()));
         } else if (imageItem) {
-            image = imageItem->image();
+            pixmap.take(r->context->createPixmap(imageItem->source()));
         } else if (canvas) {
-            image = canvas->toImage();
+            QImage img = canvas->toImage();
+            if (!img.isNull())
+                pixmap.take(new QQuickCanvasPixmap(img, canvas->window()));
         } else {
             V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
         }
     } else {
         V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
     }
+
+    if (pixmap.isNull() || !pixmap->isValid())
+        return args.This();
+
     if (args.Length() == 3) {
         dx = args[1]->NumberValue();
         dy = args[2]->NumberValue();
         sx = 0;
         sy = 0;
-        sw = image.width();
-        sh = image.height();
+        sw = pixmap->width();
+        sh = pixmap->height();
         dw = sw;
         dh = sh;
     } else if (args.Length() == 5) {
         sx = 0;
         sy = 0;
-        sw = image.width();
-        sh = image.height();
+        sw = pixmap->width();
+        sh = pixmap->height();
         dx = args[1]->NumberValue();
         dy = args[2]->NumberValue();
         dw = args[3]->NumberValue();
@@ -2505,22 +2389,28 @@ static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
      || !qIsFinite(dh))
         return args.This();
 
-    if (!image.isNull()) {
-        if (sx < 0 || sy < 0 || sw == 0 || sh == 0
-         || sx + sw > image.width() || sy + sh > image.height()
-         || sx + sw < 0 || sy + sh < 0) {
+    if (sx < 0
+    || sy < 0
+    || sw == 0
+    || sh == 0
+    || sx + sw > pixmap->width()
+    || sy + sh > pixmap->height()
+    || sx + sw < 0 || sy + sh < 0) {
             V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
-        }
-
-        r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
     }
 
+    r->context->buffer()->drawPixmap(pixmap, QRectF(sx, sy, sw, sh), QRectF(dx, dy, dw, dh));
+
     return args.This();
 }
 
 // pixel manipulation
 /*!
-  \qmlclass QtQuick2::CanvasImageData
+    \qmlclass CanvasImageData
+    \inqmlmodule QtQuick 2
+    \ingroup qtquick-canvas
+    \brief Contains image pixel data in RGBA order
+
      The \a QtQuick2::CanvasImageData object holds the image pixel data.
 
      The \a QtQuick2::CanvasImageData object has the actual dimensions of the data stored in
@@ -2569,167 +2459,11 @@ v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::Acce
 }
 
 /*!
-  \qmlmethod void QtQuick2::CanvasImageData::mirrr( bool horizontal = false, bool vertical = true)
-  Mirrors the image data in place in the  \c horizontal and/or the \c vertical direction depending on
-  whether horizontal and vertical are set to true or false.
-  The default \c horizontal value is false, the default \c vertical value is true.
-*/
-static v8::Handle<v8::Value> ctx2d_imageData_mirror(const v8::Arguments &args)
-{
-    bool horizontal = false, vertical = true;
-    QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
-
-    if (!r) {
-        //error
-        return v8::Undefined();
-    }
-
-    if (args.Length() > 2) {
-      //error
-      return v8::Undefined();
-    }
-
-    if (args.Length() == 1) {
-        horizontal = args[0]->BooleanValue();
-    } else if (args.Length() == 2) {
-        horizontal = args[0]->BooleanValue();
-        vertical = args[1]->BooleanValue();
-    }
-    r->image = r->image.mirrored(horizontal, vertical);
-    return args.This();
-}
-
-/*!
-  \qmlmethod void QtQuick2::CanvasImageData::filter(enumeration mode, args)
-   Filters the image data as defined by one of the following modes:
-    \list
-    \o Canvas.Threshold - converts the image to black and white pixels depending
-                          if they are above or below the threshold defined by the level parameter.
-                          The level must be between 0.0 (black) and 1.0(white).
-                          If no level is specified, 0.5 is used.
-    \o Canvas.Mono - converts the image to the 1-bit per pixel format.
-    \o Canvas.GrayScale - converts any colors in the image to grayscale equivalents.
-    \o Canvas.Brightness -increase/decrease a fixed \c adjustment value to each pixel's RGB channel value.
-    \o Canvas.Invert - sets each pixel to its inverse value.
-    \o Canvas.Blur - executes a box blur with the pixel \c radius parameter specifying the range of the blurring for each pixel.
-                     the default blur \c radius is 3. This filter also accepts another \c quality parameter, if true, the filter will
-                     execute 3-passes box blur to simulate the Guassian blur. The default \c quality value is false.
-    \o Canvas.Opaque - sets the alpha channel to entirely opaque.
-    \o Canvas.Convolute - executes a generic {http://en.wikipedia.org/wiki/Convolution}{Convolution} filter, the second
-                          parameter contains the convoluton matrix data as a number array.
-    \endlist
-
-*/
-static v8::Handle<v8::Value> ctx2d_imageData_filter(const v8::Arguments &args)
-{
-    QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
-
-    if (!r) {
-        //error
-        return v8::Undefined();
-    }
-
-    if (args.Length() >= 1) {
-        int filterFlag = args[0]->IntegerValue();
-        switch (filterFlag) {
-        case QQuickCanvasItem::Mono :
-        {
-            r->image = r->image.convertToFormat(QImage::Format_Mono).convertToFormat(QImage::Format_ARGB32_Premultiplied);
-        }
-            break;
-        case QQuickCanvasItem::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 QQuickCanvasItem::Threshold :
-        {
-            qreal threshold = 0.5;
-            if (args.Length() > 1)
-                threshold = args[1]->NumberValue();
-
-            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 ? 255 : 0;
-                  rgb[0] = rgb[1] = rgb[2] = v;
-              }
-            }
-        }
-            break;
-        case QQuickCanvasItem::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 QQuickCanvasItem::Invert :
-        {
-            r->image.invertPixels();
-        }
-            break;
-        case QQuickCanvasItem::Blur :
-        {
-            int radius = 3;
-            bool quality = false;
-
-            if (args.Length() > 1)
-                radius = args[1]->IntegerValue() / 2;
-            if (args.Length() > 2)
-                quality = args[2]->BooleanValue();
-
-            qt_image_boxblur(r->image, radius, quality);
-        }
-            break;
-        case QQuickCanvasItem::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 QQuickCanvasItem::Convolute :
-        {
-            if (args.Length() > 1 && args[1]->IsArray()) {
-                v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(args[1]);
-                QVector<qreal> weights;
-                for (uint32_t i = 0; i < array->Length(); ++i)
-                    weights.append(array->Get(i)->NumberValue());
-                r->image = qt_image_convolute_filter(r->image, weights);
-            } else {
-                //error
-            }
-        }
-            break;
-        default:
-            break;
-        }
-    }
+    \qmlclass CanvasPixelArray
+    \inqmlmodule QtQuick 2
+    \ingroup qtquick-canvas
+    \brief Provides ordered and indexed access to the components of each pixel in image data
 
-    return args.This();
-}
-/*!
-  \qmlclass QtQuick2::CanvasPixelArray
   The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
   The CanvasPixelArray can be accessed as normal Javascript array.
     \sa QtQuick2::CanvasImageData
@@ -2836,7 +2570,7 @@ static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
                 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())));
+            QImage image = r->context->createPixmap(QUrl(engine->toString(args[0]->ToString())))->image();
             return qt_create_image_data(image.width(), image.height(), engine, image);
         }
     } else if (args.Length() == 2) {
@@ -2958,16 +2692,17 @@ static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
         }
 
         QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
-        r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
+        r->context->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight));
     }
     return args.This();
 }
 
 /*!
-  \qmlclass QtQuick2::CanvasGradient
+    \qmlclass CanvasGradient
     \inqmlmodule QtQuick 2
     \since QtQuick 2.0
-    \brief The Context2D opaque CanvasGradient interface.
+    \ingroup qtquick-canvas
+    \brief Provides an opaque CanvasGradient interface
   */
 
 /*!
@@ -3018,16 +2753,221 @@ static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &ar
     return args.This();
 }
 
+void QQuickContext2D::scale(qreal x,  qreal y)
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(x) || !qIsFinite(y))
+        return;
+
+    QTransform newTransform = state.matrix;
+    newTransform.scale(x, y);
+
+    if (!newTransform.isInvertible()) {
+        state.invertibleCTM = false;
+        return;
+    }
+
+    state.matrix = newTransform;
+    buffer()->updateMatrix(state.matrix);
+    m_path = QTransform().scale(1.0 / x, 1.0 / y).map(m_path);
+}
+
+void QQuickContext2D::rotate(qreal angle)
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(angle))
+        return;
+
+    QTransform newTransform =state.matrix;
+    newTransform.rotate(DEGREES(angle));
+
+    if (!newTransform.isInvertible()) {
+        state.invertibleCTM = false;
+        return;
+    }
+
+    state.matrix = newTransform;
+    buffer()->updateMatrix(state.matrix);
+    m_path = QTransform().rotate(-DEGREES(angle)).map(m_path);
+}
+
+void QQuickContext2D::shear(qreal h, qreal v)
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(h) || !qIsFinite(v))
+        return ;
+
+    QTransform newTransform = state.matrix;
+    newTransform.shear(h, v);
+
+    if (!newTransform.isInvertible()) {
+        state.invertibleCTM = false;
+        return;
+    }
+
+    state.matrix = newTransform;
+    buffer()->updateMatrix(state.matrix);
+    m_path = QTransform().shear(-h, -v).map(m_path);
+}
+
+void QQuickContext2D::translate(qreal x, qreal y)
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(x) || !qIsFinite(y))
+        return ;
+
+    QTransform newTransform = state.matrix;
+    newTransform.translate(x, y);
+
+    if (!newTransform.isInvertible()) {
+        state.invertibleCTM = false;
+        return;
+    }
+
+    state.matrix = newTransform;
+    buffer()->updateMatrix(state.matrix);
+    m_path = QTransform().translate(-x, -y).map(m_path);
+}
+
+void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
+        return;
+
+    QTransform transform(a, b, c, d, e, f);
+    QTransform newTransform = state.matrix * transform;
+
+    if (!newTransform.isInvertible()) {
+        state.invertibleCTM = false;
+        return;
+    }
+    state.matrix = newTransform;
+    buffer()->updateMatrix(state.matrix);
+    m_path = transform.inverted().map(m_path);
+}
+
+void QQuickContext2D::setTransform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
+{
+    if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
+        return;
+
+    QTransform ctm = state.matrix;
+    if (!ctm.isInvertible())
+        return;
+
+    state.matrix = ctm.inverted() * state.matrix;
+    m_path = ctm.map(m_path);
+    state.invertibleCTM = true;
+    transform(a, b, c, d, e, f);
+}
+
+void QQuickContext2D::fill()
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!m_path.elementCount())
+        return;
+
+    m_path.setFillRule(state.fillRule);
+    buffer()->fill(m_path);
+}
+
+void QQuickContext2D::clip()
+{
+    if (!state.invertibleCTM)
+        return;
+
+    QPainterPath clipPath = m_path;
+    clipPath.closeSubpath();
+    if (!state.clipPath.isEmpty())
+        state.clipPath = clipPath.intersected(state.clipPath);
+    else
+        state.clipPath = clipPath;
+    buffer()->clip(state.clipPath);
+}
+
+void QQuickContext2D::stroke()
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!m_path.elementCount())
+        return;
+
+    buffer()->stroke(m_path);
+}
+
+void QQuickContext2D::fillRect(qreal x, qreal y, qreal w, qreal h)
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+        return;
+
+    buffer()->fillRect(QRectF(x, y, w, h));
+}
+
+void QQuickContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+        return;
+
+    buffer()->strokeRect(QRectF(x, y, w, h));
+}
+
+void QQuickContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+        return;
+
+    buffer()->clearRect(QRectF(x, y, w, h));
+}
+
+void QQuickContext2D::drawText(const QString& text, qreal x, qreal y, bool fill)
+{
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(x) || !qIsFinite(y))
+        return;
+
+    QPainterPath textPath = createTextGlyphs(x, y, text);
+    if (fill)
+        buffer()->fill(textPath);
+    else
+        buffer()->stroke(textPath);
+}
+
 
 void QQuickContext2D::beginPath()
 {
+    if (!m_path.elementCount())
+        return;
     m_path = QPainterPath();
-    m_path.setFillRule(state.fillRule);
 }
 
 void QQuickContext2D::closePath()
 {
-    if (m_path.isEmpty())
+    if (!m_path.elementCount())
         return;
 
     QRectF boundRect = m_path.boundingRect();
@@ -3039,29 +2979,53 @@ void QQuickContext2D::closePath()
 
 void QQuickContext2D::moveTo( qreal x, qreal y)
 {
+    if (!state.invertibleCTM)
+        return;
+
     //FIXME: moveTo should not close the previous subpath
-    m_path.moveTo(state.matrix.map(QPointF(x, y)));
+    m_path.moveTo(QPointF(x, y));
 }
 
 void QQuickContext2D::lineTo( qreal x, qreal y)
 {
-    m_path.lineTo(state.matrix.map(QPointF(x, y)));
+    if (!state.invertibleCTM)
+        return;
+
+    QPointF pt(x, y);
+
+    if (!m_path.elementCount())
+        m_path.moveTo(pt);
+    else if (m_path.currentPosition() != pt)
+        m_path.lineTo(pt);
 }
 
 void QQuickContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
                                            qreal x, qreal y)
 {
-    m_path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
-                      state.matrix.map(QPointF(x, y)));
+    if (!state.invertibleCTM)
+        return;
+
+    if (!m_path.elementCount())
+        m_path.moveTo(QPointF(cpx, cpy));
+
+    QPointF pt(x, y);
+    if (m_path.currentPosition() != pt)
+        m_path.quadTo(QPointF(cpx, cpy), pt);
 }
 
 void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
                                         qreal cp2x, qreal cp2y,
                                         qreal x, qreal y)
 {
-    m_path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
-                       state.matrix.map(QPointF(cp2x, cp2y)),
-                       state.matrix.map(QPointF(x, y)));
+    if (!state.invertibleCTM)
+        return;
+
+    if (!m_path.elementCount())
+        m_path.moveTo(QPointF(cp1x, cp1y));
+
+    QPointF pt(x, y);
+    if (m_path.currentPosition() != pt)
+        m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y),  pt);
 }
 
 void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
@@ -3119,69 +3083,100 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu
     if ((sa < ea) && ((ea - sa) > Q_PI))
         anticlockwise = true;
 
-    arc(p.x(), p.y(), radius, sa, ea, anticlockwise, false);
+    arc(p.x(), p.y(), radius, sa, ea, anticlockwise);
 }
 
 void QQuickContext2D::arcTo(qreal x1, qreal y1,
                                 qreal x2, qreal y2,
                                 qreal radius)
 {
-    QPointF st  = state.matrix.map(QPointF(x1, y1));
-    QPointF end = state.matrix.map(QPointF(x2, y2));
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2) || !qIsFinite(radius))
+        return;
+
+    QPointF st(x1, y1);
+    QPointF end(x2, y2);
 
-    if (!m_path.elementCount()) {
+    if (!m_path.elementCount())
         m_path.moveTo(st);
-    } else if (st == m_path.currentPosition() || st == end || !radius) {
-        m_path.lineTo(st);
-    } else {
+    else if (st == m_path.currentPosition() || st == end || !radius)
+        lineTo(x1, y1);
+    else
         addArcTo(st, end, radius);
-    }
-}
+ }
 
-void QQuickContext2D::rect(qreal x, qreal y,
-                               qreal w, qreal h)
+void QQuickContext2D::rect(qreal x, qreal y, qreal w, qreal h)
 {
-    m_path.addPolygon(state.matrix.map(QRectF(x, y, w, h)));
+    if (!state.invertibleCTM)
+        return;
+    if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+        return;
+
+    if (!w && !h) {
+        m_path.moveTo(x, y);
+        return;
+    }
+    m_path.addRect(x, y, w, h);
 }
 
 void QQuickContext2D::roundedRect(qreal x, qreal y,
                                qreal w, qreal h,
                                qreal xr, qreal yr)
 {
-    QPainterPath path;
-    path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
-    m_path.addPath(state.matrix.map(path));
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h) || !qIsFinite(xr) || !qIsFinite(yr))
+        return;
+
+    if (!w && !h) {
+        m_path.moveTo(x, y);
+        return;
+    }
+    m_path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
 }
 
 void QQuickContext2D::ellipse(qreal x, qreal y,
                            qreal w, qreal h)
 {
-    QPainterPath path;
-    path.addEllipse(x, y, w, h);
-    m_path.addPath(state.matrix.map(path));
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
+        return;
+
+    if (!w && !h) {
+        m_path.moveTo(x, y);
+        return;
+    }
+
+    m_path.addEllipse(x, y, w, h);
 }
 
 void QQuickContext2D::text(const QString& str, qreal x, qreal y)
 {
+    if (!state.invertibleCTM)
+        return;
+
     QPainterPath path;
     path.addText(x, y, state.font, str);
-    m_path.addPath(state.matrix.map(path));
+    m_path.addPath(path);
 }
 
-void QQuickContext2D::arc(qreal xc,
-                       qreal yc,
-                       qreal radius,
-                       qreal sar,
-                       qreal ear,
-                       bool antiClockWise,
-                       bool transform)
+void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear, bool antiClockWise)
 {
+    if (!state.invertibleCTM)
+        return;
+
+    if (!qIsFinite(xc) || !qIsFinite(yc) || !qIsFinite(sar) || !qIsFinite(ear) || !qIsFinite(radius))
+        return;
+
+    if (sar == ear)
+        return;
+
 
-    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
@@ -3218,17 +3213,14 @@ void QQuickContext2D::arc(qreal xc,
               qFuzzyCompare(qAbs(span), 360))) {
             span   += ea - sa;
         }
-        if (!m_path.elementCount())
-            m_path.moveTo(xs, ys);
     }
 
-
-    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);
+    // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
+    if (!m_path.elementCount())
+        m_path.arcMoveTo(xs, ys, width, height, sa);
+    else if (!radius) {
+        m_path.lineTo(xc, yc);
+        return;
     }
 
     m_path.arcTo(xs, ys, width, height, sa, span);
@@ -3273,9 +3265,9 @@ static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetr
 }
 
 
-QImage QQuickContext2D::createImage(const QUrl& url)
+QQmlRefPointer<QQuickCanvasPixmap> QQuickContext2D::createPixmap(const QUrl& url)
 {
-    return m_canvas->loadedImage(url);
+    return m_canvas->loadedPixmap(url);
 }
 
 QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
@@ -3292,17 +3284,69 @@ QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString&
 }
 
 
+static inline bool areCollinear(const QPointF& a, const QPointF& b, const QPointF& c)
+{
+    // Solved from comparing the slopes of a to b and b to c: (ay-by)/(ax-bx) == (cy-by)/(cx-bx)
+    return qFuzzyCompare((c.y() - b.y()) * (a.x() - b.x()), (a.y() - b.y()) * (c.x() - b.x()));
+}
+
+static inline bool withinRange(qreal p, qreal a, qreal b)
+{
+    return (p >= a && p <= b) || (p >= b && p <= a);
+}
+
 bool QQuickContext2D::isPointInPath(qreal x, qreal y) const
 {
-    return m_path.contains(QPointF(x, y));
+    if (!state.invertibleCTM)
+        return false;
+
+    if (!m_path.elementCount())
+        return false;
+
+    if (!qIsFinite(x) || !qIsFinite(y))
+        return false;
+
+    QPointF point(x, y);
+    QTransform ctm = state.matrix;
+    QPointF p = ctm.inverted().map(point);
+    if (!qIsFinite(p.x()) || !qIsFinite(p.y()))
+        return false;
+
+    const_cast<QQuickContext2D *>(this)->m_path.setFillRule(state.fillRule);
+
+    bool contains = m_path.contains(p);
+
+    if (!contains) {
+        // check whether the point is on the border
+        QPolygonF border = m_path.toFillPolygon();
+
+        QPointF p1 = border.at(0);
+        QPointF p2;
+
+        for (int i = 1; i < border.size(); ++i) {
+            p2 = border.at(i);
+            if (areCollinear(p, p1, p2)
+                    // Once we know that the points are collinear we
+                    // only need to check one of the coordinates
+                    && (qAbs(p2.x() - p1.x()) > qAbs(p2.y() - p1.y()) ?
+                        withinRange(p.x(), p1.x(), p2.x()) :
+                        withinRange(p.y(), p1.y(), p2.y()))) {
+                return true;
+            }
+            p1 = p2;
+        }
+    }
+    return contains;
 }
 
-QQuickContext2D::QQuickContext2D(QQuickCanvasItem* item)
-    : m_canvas(item)
+QQuickContext2D::QQuickContext2D(QObject *parent)
+    : QQuickCanvasContext(parent)
     , m_buffer(new QQuickContext2DCommandBuffer)
     , m_v8engine(0)
+    , m_windowManager(0)
+    , m_surface(0)
+    , m_glContext(0)
 {
-    reset();
 }
 
 QQuickContext2D::~QQuickContext2D()
@@ -3315,6 +3359,115 @@ v8::Handle<v8::Object> QQuickContext2D::v8value() const
     return m_v8value;
 }
 
+QStringList QQuickContext2D::contextNames() const
+{
+    return QStringList() << QLatin1String("2d");
+}
+
+void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args)
+{
+    Q_UNUSED(args);
+
+    m_canvas = canvasItem;
+    m_renderTarget = canvasItem->renderTarget();
+
+    QQuickWindow *window = canvasItem->window();
+    m_windowManager =  QQuickWindowPrivate::get(window)->windowManager;
+    m_renderStrategy = canvasItem->renderStrategy();
+
+    switch (m_renderTarget) {
+    case QQuickCanvasItem::Image:
+        m_texture = new QQuickContext2DImageTexture(m_renderStrategy == QQuickCanvasItem::Threaded);
+        break;
+    case QQuickCanvasItem::FramebufferObject:
+    {
+        m_texture = new QQuickContext2DFBOTexture;
+        // No BufferQueueingOpenGL, falls back to Cooperative mode
+        if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL))
+            m_renderStrategy = QQuickCanvasItem::Cooperative;
+    }
+        break;
+    }
+
+    m_texture->setItem(canvasItem);
+    m_texture->setCanvasWindow(canvasItem->canvasWindow().toRect());
+    m_texture->setTileSize(canvasItem->tileSize());
+    m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
+    m_texture->setSmooth(canvasItem->smooth());
+
+    QThread *renderThread = QThread::currentThread();
+    QThread *sceneGraphThread = window->openglContext() ? window->openglContext()->thread() : 0;
+
+    if (m_renderStrategy == QQuickCanvasItem::Threaded)
+        renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem));
+    else if (m_renderStrategy == QQuickCanvasItem::Cooperative)
+        renderThread = sceneGraphThread;
+
+    if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) {
+         QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->glContext();
+         m_surface = window;
+         m_glContext = new QOpenGLContext;
+         m_glContext->setFormat(cc->format());
+         m_glContext->setShareContext(cc);
+         if (renderThread != QThread::currentThread())
+             m_glContext->moveToThread(renderThread);
+    }
+
+    connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
+
+    reset();
+}
+
+void QQuickContext2D::prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth)
+{
+    m_texture->canvasChanged(canvasSize, tileSize, canvasWindow, dirtyRect, smooth);
+}
+
+void QQuickContext2D::flush()
+{
+    if (!m_buffer->isEmpty()) {
+        QMutexLocker lock(&m_bufferMutex);
+        m_bufferQueue.enqueue(m_buffer);
+        m_buffer = new QQuickContext2DCommandBuffer;
+    } else
+        return;
+
+    switch (m_renderStrategy) {
+    case QQuickCanvasItem::Immediate:
+        // Cause the texture to consume paint commands immediately
+        m_texture->paint();
+        break;
+    case QQuickCanvasItem::Threaded:
+        // wake up thread to consume paint commands
+        m_texture->paint();
+        break;
+    case QQuickCanvasItem::Cooperative:
+        // NOTE: On SG Thread
+        m_texture->paint();
+        break;
+    }
+}
+
+QSGDynamicTexture *QQuickContext2D::texture() const
+{
+    return m_texture;
+}
+
+QImage QQuickContext2D::toImage(const QRectF& bounds)
+{
+    switch (m_renderStrategy) {
+    case QQuickCanvasItem::Immediate:
+    case QQuickCanvasItem::Threaded:
+        flush();
+        break;
+    case QQuickCanvasItem::Cooperative:
+        break;
+    }
+
+    return m_texture->toImage(bounds);
+}
+
+
 QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
 {
     v8::HandleScope handle_scope;
@@ -3405,8 +3558,6 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
     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());
 }
@@ -3469,7 +3620,9 @@ void QQuickContext2D::popState()
 
     if (newState.shadowOffsetY != state.shadowOffsetY)
         buffer()->setShadowOffsetY(newState.shadowOffsetY);
+    m_path = state.matrix.map(m_path);
     state = newState;
+    m_path = state.matrix.inverted().map(m_path);
 }
 void QQuickContext2D::pushState()
 {
@@ -3481,6 +3634,8 @@ void QQuickContext2D::reset()
     QQuickContext2D::State newState;
     newState.matrix = QTransform();
 
+    m_path = QPainterPath();
+
     QPainterPath defaultClipPath;
 
     QRect r(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
@@ -3495,6 +3650,7 @@ void QQuickContext2D::reset()
     newState.fillPatternRepeatY = false;
     newState.strokePatternRepeatX = false;
     newState.strokePatternRepeatY = false;
+    newState.invertibleCTM = true;
     newState.fillRule = Qt::WindingFill;
     newState.globalAlpha = 1.0;
     newState.lineWidth = 1;
@@ -3513,7 +3669,7 @@ void QQuickContext2D::reset()
     m_stateStack.clear();
     m_stateStack.push(newState);
     popState();
-    m_buffer->clearRect(0, 0, m_canvas->width(), m_canvas->height());
+    m_buffer->clearRect(QRectF(0, 0, m_canvas->width(), m_canvas->height()));
 }
 
 void QQuickContext2D::setV8Engine(QV8Engine *engine)
@@ -3537,4 +3693,10 @@ void QQuickContext2D::setV8Engine(QV8Engine *engine)
     }
 }
 
+QQuickContext2DCommandBuffer* QQuickContext2D::nextBuffer()
+{
+    QMutexLocker lock(&m_bufferMutex);
+    return m_bufferQueue.isEmpty() ? 0 : m_bufferQueue.dequeue();
+}
+
 QT_END_NAMESPACE