Refactor context2d thread logic
[profile/ivi/qtdeclarative.git] / src / quick / items / context2d / qquickcontext2d.cpp
index ba709b7..40a9b8e 100644 (file)
@@ -3,7 +3,7 @@
 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
 ** 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
 #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>
+
+#ifdef Q_OS_QNX
+#include <ctype.h>
+#endif
 
 QT_BEGIN_NAMESPACE
 /*!
-    \qmlclass Context2D QQuickContext2D
+    \qmltype Context2D
+    \instantiates 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:
@@ -86,7 +92,7 @@ QT_BEGIN_NAMESPACE
     {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
+    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
@@ -100,21 +106,6 @@ QT_BEGIN_NAMESPACE
     \image qml-item-canvas-context.gif
 */
 
-QLockedCommandBuffer::QLockedCommandBuffer(QQuickContext2DCommandBuffer *b)
-    : m_buffer(b)
-{
-    m_buffer->lockQueue();
-}
-
-QLockedCommandBuffer::~QLockedCommandBuffer()
-{
-    m_buffer->unlockQueue();
-}
-
-QQuickContext2DCommandBuffer* QLockedCommandBuffer::operator->() const
-{
-    return m_buffer;
-}
 
 
 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
@@ -196,7 +187,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();
@@ -206,7 +197,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);
@@ -245,7 +236,7 @@ class QV8Context2DResource : public QV8ObjectResource
 {
     V8_RESOURCE_TYPE(Context2DType)
 public:
-    QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
+    QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e), context(0) {}
     QQuickContext2D* context;
 };
 
@@ -495,8 +486,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();
 }
@@ -510,22 +499,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
@@ -562,15 +551,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();
 }
 
@@ -594,17 +576,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();
 }
 
@@ -621,19 +594,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)
@@ -647,25 +620,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();
 }
@@ -686,25 +647,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();
 }
@@ -724,17 +673,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();
 }
 
@@ -750,8 +690,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();
 }
@@ -766,16 +705,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
@@ -814,22 +746,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
@@ -873,12 +805,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.
@@ -946,8 +878,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.
@@ -1086,8 +1018,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);
@@ -1135,8 +1069,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")
@@ -1179,11 +1115,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);
@@ -1198,20 +1138,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
  */
@@ -1224,10 +1164,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.
@@ -1264,7 +1204,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()) {
@@ -1302,9 +1242,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.
 */
@@ -1360,9 +1300,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.
 */
@@ -1400,7 +1340,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;
 
@@ -1586,12 +1526,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;
 }
@@ -1607,17 +1547,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();
 }
@@ -1632,18 +1566,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();
 }
 
@@ -1662,18 +1586,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();
 }
@@ -1683,8 +1597,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)
 {
@@ -1698,15 +1612,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(),
@@ -1726,9 +1633,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
@@ -1737,33 +1644,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();
@@ -1835,10 +1734,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
@@ -1856,14 +1755,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();
 }
 
@@ -1898,9 +1790,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();
 }
 
@@ -1986,19 +1876,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();
 }
 
@@ -2013,23 +1892,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();
 }
 
@@ -2047,18 +1916,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();
 }
@@ -2100,9 +1959,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();
 }
 
@@ -2119,32 +1976,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
 /*!
@@ -2183,11 +2038,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".
   */
@@ -2246,12 +2101,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".
   */
@@ -2342,21 +2197,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
+  \qmltype 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.
 
@@ -2432,7 +2283,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.
 
 
@@ -2461,44 +2312,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();
@@ -2526,22 +2388,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
+    \qmltype 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
@@ -2590,7 +2458,11 @@ v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::Acce
 }
 
 /*!
-  \qmlclass QtQuick2::CanvasPixelArray
+    \qmltype CanvasPixelArray
+    \inqmlmodule QtQuick 2
+    \ingroup qtquick-canvas
+    \brief Provides ordered and indexed access to the components of each pixel in image data
+
   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
@@ -2697,7 +2569,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) {
@@ -2819,16 +2691,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
+    \qmltype CanvasGradient
     \inqmlmodule QtQuick 2
     \since QtQuick 2.0
-    \brief The Context2D opaque CanvasGradient interface.
+    \ingroup qtquick-canvas
+    \brief Provides an opaque CanvasGradient interface
   */
 
 /*!
@@ -2879,16 +2752,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();
@@ -2900,29 +2978,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)
@@ -2980,69 +3082,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 (!m_path.elementCount()) {
+    if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2) || !qIsFinite(radius))
+        return;
+
+    QPointF st(x1, y1);
+    QPointF end(x2, y2);
+
+    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
@@ -3079,17 +3212,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);
@@ -3133,10 +3263,15 @@ static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetr
     return offset;
 }
 
+void QQuickContext2D::setGrabbedImage(const QImage& grab)
+{
+    m_grabbedImage = grab;
+    m_grabbed = true;
+}
 
-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)
@@ -3153,21 +3288,77 @@ 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(QObject *parent)
     : QQuickCanvasContext(parent)
     , m_buffer(new QQuickContext2DCommandBuffer)
     , m_v8engine(0)
+    , m_windowManager(0)
+    , m_surface(0)
+    , m_glContext(0)
+    , m_thread(0)
+    , m_grabbed(false)
 {
 }
 
 QQuickContext2D::~QQuickContext2D()
 {
     delete m_buffer;
+    m_texture->deleteLater();
 }
 
 v8::Handle<v8::Object> QQuickContext2D::v8value() const
@@ -3187,16 +3378,13 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
     m_canvas = canvasItem;
     m_renderTarget = canvasItem->renderTarget();
 
-    // For the FBO target we only (currently) support Cooperative
-    if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
-        canvasItem->setRenderStrategy(QQuickCanvasItem::Cooperative);
-    }
-
+    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); // ?? || Coop
+        m_texture = new QQuickContext2DImageTexture;
         break;
     case QQuickCanvasItem::FramebufferObject:
         m_texture = new QQuickContext2DFBOTexture;
@@ -3209,6 +3397,29 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
     m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
     m_texture->setSmooth(canvasItem->smooth());
 
+    m_thread = QThread::currentThread();
+
+    QThread *renderThread = m_thread;
+    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 (renderThread && renderThread != QThread::currentThread())
+        m_texture->moveToThread(renderThread);
+
+    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();
@@ -3216,32 +3427,24 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
 
 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);
+    QMetaObject::invokeMethod(m_texture,
+                                                               "canvasChanged",
+                                                               Qt::AutoConnection,
+                                                               Q_ARG(QSize, canvasSize),
+                                                               Q_ARG(QSize, tileSize),
+                                                               Q_ARG(QRect, canvasWindow),
+                                                               Q_ARG(QRect, dirtyRect),
+                                                               Q_ARG(bool, smooth));
 }
 
 void QQuickContext2D::flush()
 {
-    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:
-        // Add to the update list in SG
-        m_canvas->update(); // FIXME
-        break;
-    }
-}
-
-// On SG render thread
-void QQuickContext2D::sync()
-{
-    if (m_renderStrategy == QQuickCanvasItem::Cooperative)
-        m_texture->paint();
+    if (m_buffer)
+        QMetaObject::invokeMethod(m_texture,
+                                                                   "paint",
+                                                                   Qt::AutoConnection,
+                                                                   Q_ARG(QQuickContext2DCommandBuffer*, m_buffer));
+    m_buffer = new QQuickContext2DCommandBuffer();
 }
 
 QSGDynamicTexture *QQuickContext2D::texture() const
@@ -3251,7 +3454,22 @@ QSGDynamicTexture *QQuickContext2D::texture() const
 
 QImage QQuickContext2D::toImage(const QRectF& bounds)
 {
-    return m_texture->toImage(bounds);
+    flush();
+    if (m_texture->thread() == QThread::currentThread())
+        m_texture->grabImage(bounds);
+    else if (m_renderStrategy == QQuickCanvasItem::Cooperative) {
+        qWarning() << "Pixel read back is not support in Cooperative mode, please try Theaded or Immediate mode";
+        return QImage();
+    } else {
+        QMetaObject::invokeMethod(m_texture,
+                                  "grabImage",
+                                  Qt::BlockingQueuedConnection,
+                                  Q_ARG(QRectF, bounds));
+    }
+    QImage img = m_grabbedImage;
+    m_grabbedImage = QImage();
+    m_grabbed = false;
+    return img;
 }
 
 
@@ -3407,7 +3625,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()
 {
@@ -3419,6 +3639,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());
@@ -3433,6 +3655,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;
@@ -3451,7 +3674,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)
@@ -3475,4 +3698,10 @@ void QQuickContext2D::setV8Engine(QV8Engine *engine)
     }
 }
 
+QQuickContext2DCommandBuffer* QQuickContext2D::nextBuffer()
+{
+    QMutexLocker lock(&m_mutex);
+    return m_bufferQueue.isEmpty() ? 0 : m_bufferQueue.dequeue();
+}
+
 QT_END_NAMESPACE