Doc: Fix \sa usage
[profile/ivi/qtdeclarative.git] / src / quick / items / context2d / qquickcontext2d.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickcontext2d_p.h"
43 #include "qquickcontext2dcommandbuffer_p.h"
44 #include "qquickcanvasitem_p.h"
45 #include <private/qquickcontext2dtexture_p.h>
46 #include <private/qquickitem_p.h>
47 #include <QtQuick/private/qquickshadereffectsource_p.h>
48 #include <QtGui/qopenglframebufferobject.h>
49
50 #include <QtQuick/private/qsgcontext_p.h>
51 #include <private/qquicksvgparser_p.h>
52 #include <private/qquickpath_p.h>
53
54 #include <private/qquickimage_p_p.h>
55
56 #include <QtGui/qguiapplication.h>
57 #include <qqmlinfo.h>
58 #include <QtCore/qmath.h>
59 #include <private/qv8engine_p.h>
60
61 #include <qqmlengine.h>
62 #include <private/qv8domerrors_p.h>
63 #include <QtCore/qnumeric.h>
64
65 #ifdef Q_OS_QNX
66 #include <ctype.h>
67 #endif
68
69 QT_BEGIN_NAMESPACE
70 /*!
71     \qmlclass Context2D QQuickContext2D
72     \inqmlmodule QtQuick 2
73     \since QtQuick 2.0
74     \brief The Context2D API allows you to draw 2d graphic shapes on the \c
75     Canvas item.
76
77     The Context2D object can be created by \c Canvas item's \c getContext()
78     method:
79     \code
80     Canvas {
81       id:canvas
82       onPaint:{
83          var ctx = canvas.getContext('2d');
84          //...
85       }
86     }
87     \endcode
88     The Context2D API implements the same \l
89     {http://www.w3.org/TR/2dcontext}{W3C Canvas 2D Context API standard} with
90     some enhanced features.
91
92     The Context2D API provides the rendering \b{context} which defines the
93     methods and attributes needed to draw on the \c Canvas item. The following
94     assigns the canvas rendering context to a \c{context} variable:
95     \code
96     var context = mycanvas.getContext("2d")
97     \endcode
98
99     The Context2D API renders the canvas as a coordinate system whose origin
100     (0,0) is at the top left corner, as shown in the figure below. Coordinates
101     increase along the \c{x} axis from left to right and along the \c{y} axis
102     from top to bottom of the canvas.
103     \image qml-item-canvas-context.gif
104 */
105
106
107
108 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
109
110 static const double Q_PI   = 3.14159265358979323846;   // pi
111
112 #define DEGREES(t) ((t) * 180.0 / Q_PI)
113
114 #define CHECK_CONTEXT(r)     if (!r || !r->context || !r->context->bufferValid()) \
115                                 V8THROW_ERROR("Not a Context2D object");
116
117 #define CHECK_CONTEXT_SETTER(r)     if (!r || !r->context || !r->context->bufferValid()) \
118                                        V8THROW_ERROR_SETTER("Not a Context2D object");
119 #define qClamp(val, min, max) qMin(qMax(val, min), max)
120 #define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
121 QColor qt_color_from_string(v8::Local<v8::Value> name)
122 {
123     v8::String::AsciiValue str(name);
124
125     char *p = *str;
126     int len = str.length();
127     //rgb/hsl color string has at least 7 characters
128     if (!p || len > 255 || len <= 7)
129         return QColor(p);
130     else {
131         bool isRgb(false), isHsl(false), hasAlpha(false);
132         Q_UNUSED(isHsl)
133
134         while (isspace(*p)) p++;
135         if (strncmp(p, "rgb", 3) == 0)
136             isRgb = true;
137         else if (strncmp(p, "hsl", 3) == 0)
138             isHsl = true;
139         else
140             return QColor(p);
141
142         p+=3; //skip "rgb" or "hsl"
143         hasAlpha = (*p == 'a') ? true : false;
144
145         ++p; //skip "("
146
147         if (hasAlpha) ++p; //skip "a"
148
149         int rh, gs, bl, alpha = 255;
150
151         //red
152         while (isspace(*p)) p++;
153         rh = strtol(p, &p, 10);
154         if (*p == '%') {
155             rh = qRound(rh/100.0 * 255);
156             ++p;
157         }
158         if (*p++ != ',') return QColor();
159
160         //green
161         while (isspace(*p)) p++;
162         gs = strtol(p, &p, 10);
163         if (*p == '%') {
164             gs = qRound(gs/100.0 * 255);
165             ++p;
166         }
167         if (*p++ != ',') return QColor();
168
169         //blue
170         while (isspace(*p)) p++;
171         bl = strtol(p, &p, 10);
172         if (*p == '%') {
173             bl = qRound(bl/100.0 * 255);
174             ++p;
175         }
176
177         if (hasAlpha) {
178             if (*p++!= ',') return QColor();
179             while (isspace(*p)) p++;
180             bool ok = false;
181             alpha = qRound(qstrtod(p, const_cast<const char **>(&p), &ok) * 255);
182         }
183
184         if (*p != ')') return QColor();
185         if (isRgb)
186             return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)));
187         else if (isHsl)
188             return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255));
189     }
190     return QColor();
191 }
192
193 QFont qt_font_from_string(const QString& fontString) {
194     QFont font;
195      // ### this is simplified and incomplete
196     // ### TODO:get code from Qt webkit
197      QStringList tokens = fontString.split(QLatin1String(" "));
198      foreach (const QString &token, tokens) {
199          if (token == QLatin1String("italic"))
200              font.setItalic(true);
201          else if (token == QLatin1String("bold"))
202              font.setBold(true);
203          else if (token.endsWith(QLatin1String("px"))) {
204              QString number = token;
205              number.remove(QLatin1String("px"));
206              //font.setPointSizeF(number.trimmed().toFloat());
207              font.setPixelSize(number.trimmed().toInt());
208          } else
209              font.setFamily(token);
210      }
211
212      return font;
213 }
214
215
216
217 class QQuickContext2DEngineData : public QV8Engine::Deletable
218 {
219 public:
220     QQuickContext2DEngineData(QV8Engine *engine);
221     ~QQuickContext2DEngineData();
222
223     v8::Persistent<v8::Function> constructorContext;
224     v8::Persistent<v8::Function> constructorGradient;
225     v8::Persistent<v8::Function> constructorPattern;
226     v8::Persistent<v8::Function> constructorPixelArray;
227     v8::Persistent<v8::Function> constructorImageData;
228 };
229
230 V8_DEFINE_EXTENSION(QQuickContext2DEngineData, engineData)
231
232 class QV8Context2DResource : public QV8ObjectResource
233 {
234     V8_RESOURCE_TYPE(Context2DType)
235 public:
236     QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
237     QQuickContext2D* context;
238 };
239
240 class QV8Context2DStyleResource : public QV8ObjectResource
241 {
242     V8_RESOURCE_TYPE(Context2DStyleType)
243 public:
244     QV8Context2DStyleResource(QV8Engine *e)
245       : QV8ObjectResource(e)
246       , patternRepeatX(false)
247       , patternRepeatY(false)
248     {}
249     QBrush brush;
250     bool patternRepeatX:1;
251     bool patternRepeatY:1;
252 };
253
254 class QV8Context2DPixelArrayResource : public QV8ObjectResource
255 {
256     V8_RESOURCE_TYPE(Context2DPixelArrayType)
257 public:
258     QV8Context2DPixelArrayResource(QV8Engine *e) : QV8ObjectResource(e) {}
259
260     QImage image;
261 };
262
263 QImage qt_image_convolute_filter(const QImage& src, const QVector<qreal>& weights, int radius = 0)
264 {
265     int sides = radius ? radius : qRound(qSqrt(weights.size()));
266     int half = qFloor(sides/2);
267
268     QImage dst = QImage(src.size(), src.format());
269     int w = src.width();
270     int h = src.height();
271     for (int y = 0; y < dst.height(); ++y) {
272       QRgb *dr = (QRgb*)dst.scanLine(y);
273       for (int x = 0; x < dst.width(); ++x) {
274           unsigned char* dRgb = ((unsigned char*)&dr[x]);
275           unsigned char red=0, green=0, blue=0, alpha=0;
276           int sy = y;
277           int sx = x;
278
279           for (int cy=0; cy<sides; cy++) {
280              for (int cx=0; cx<sides; cx++) {
281                int scy = sy + cy - half;
282                int scx = sx + cx - half;
283                if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
284                   const QRgb *sr = (const QRgb*)(src.constScanLine(scy));
285                   const unsigned char* sRgb = ((const unsigned char*)&sr[scx]);
286                   qreal wt = radius ? weights[0] : weights[cy*sides+cx];
287                   red += sRgb[0] * wt;
288                   green += sRgb[1] * wt;
289                   blue += sRgb[2] * wt;
290                   alpha += sRgb[3] * wt;
291                }
292              }
293           }
294           dRgb[0] = red;
295           dRgb[1] = green;
296           dRgb[2] = blue;
297           dRgb[3] = alpha;
298       }
299     }
300     return dst;
301 }
302
303 void qt_image_boxblur(QImage& image, int radius, bool quality)
304 {
305     int passes = quality? 3: 1;
306     for (int i=0; i < passes; i++) {
307         image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0/(radius * radius * 1.0), radius);
308     }
309 }
310
311 static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
312 {
313     if (compositeOperator == QLatin1String("source-over")) {
314         return QPainter::CompositionMode_SourceOver;
315     } else if (compositeOperator == QLatin1String("source-out")) {
316         return QPainter::CompositionMode_SourceOut;
317     } else if (compositeOperator == QLatin1String("source-in")) {
318         return QPainter::CompositionMode_SourceIn;
319     } else if (compositeOperator == QLatin1String("source-atop")) {
320         return QPainter::CompositionMode_SourceAtop;
321     } else if (compositeOperator == QLatin1String("destination-atop")) {
322         return QPainter::CompositionMode_DestinationAtop;
323     } else if (compositeOperator == QLatin1String("destination-in")) {
324         return QPainter::CompositionMode_DestinationIn;
325     } else if (compositeOperator == QLatin1String("destination-out")) {
326         return QPainter::CompositionMode_DestinationOut;
327     } else if (compositeOperator == QLatin1String("destination-over")) {
328         return QPainter::CompositionMode_DestinationOver;
329     } else if (compositeOperator == QLatin1String("lighter")) {
330         return QPainter::CompositionMode_Lighten;
331     } else if (compositeOperator == QLatin1String("copy")) {
332         return QPainter::CompositionMode_Source;
333     } else if (compositeOperator == QLatin1String("xor")) {
334         return QPainter::CompositionMode_Xor;
335     } else if (compositeOperator == QLatin1String("qt-clear")) {
336         return QPainter::CompositionMode_Clear;
337     } else if (compositeOperator == QLatin1String("qt-destination")) {
338         return QPainter::CompositionMode_Destination;
339     } else if (compositeOperator == QLatin1String("qt-multiply")) {
340         return QPainter::CompositionMode_Multiply;
341     } else if (compositeOperator == QLatin1String("qt-screen")) {
342         return QPainter::CompositionMode_Screen;
343     } else if (compositeOperator == QLatin1String("qt-overlay")) {
344         return QPainter::CompositionMode_Overlay;
345     } else if (compositeOperator == QLatin1String("qt-darken")) {
346         return QPainter::CompositionMode_Darken;
347     } else if (compositeOperator == QLatin1String("qt-lighten")) {
348         return QPainter::CompositionMode_Lighten;
349     } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
350         return QPainter::CompositionMode_ColorDodge;
351     } else if (compositeOperator == QLatin1String("qt-color-burn")) {
352         return QPainter::CompositionMode_ColorBurn;
353     } else if (compositeOperator == QLatin1String("qt-hard-light")) {
354         return QPainter::CompositionMode_HardLight;
355     } else if (compositeOperator == QLatin1String("qt-soft-light")) {
356         return QPainter::CompositionMode_SoftLight;
357     } else if (compositeOperator == QLatin1String("qt-difference")) {
358         return QPainter::CompositionMode_Difference;
359     } else if (compositeOperator == QLatin1String("qt-exclusion")) {
360         return QPainter::CompositionMode_Exclusion;
361     }
362     return QPainter::CompositionMode_SourceOver;
363 }
364
365 static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
366 {
367     switch (op) {
368     case QPainter::CompositionMode_SourceOver:
369         return QLatin1String("source-over");
370     case QPainter::CompositionMode_DestinationOver:
371         return QLatin1String("destination-over");
372     case QPainter::CompositionMode_Clear:
373         return QLatin1String("qt-clear");
374     case QPainter::CompositionMode_Source:
375         return QLatin1String("copy");
376     case QPainter::CompositionMode_Destination:
377         return QLatin1String("qt-destination");
378     case QPainter::CompositionMode_SourceIn:
379         return QLatin1String("source-in");
380     case QPainter::CompositionMode_DestinationIn:
381         return QLatin1String("destination-in");
382     case QPainter::CompositionMode_SourceOut:
383         return QLatin1String("source-out");
384     case QPainter::CompositionMode_DestinationOut:
385         return QLatin1String("destination-out");
386     case QPainter::CompositionMode_SourceAtop:
387         return QLatin1String("source-atop");
388     case QPainter::CompositionMode_DestinationAtop:
389         return QLatin1String("destination-atop");
390     case QPainter::CompositionMode_Xor:
391         return QLatin1String("xor");
392     case QPainter::CompositionMode_Plus:
393         return QLatin1String("plus");
394     case QPainter::CompositionMode_Multiply:
395         return QLatin1String("qt-multiply");
396     case QPainter::CompositionMode_Screen:
397         return QLatin1String("qt-screen");
398     case QPainter::CompositionMode_Overlay:
399         return QLatin1String("qt-overlay");
400     case QPainter::CompositionMode_Darken:
401         return QLatin1String("qt-darken");
402     case QPainter::CompositionMode_Lighten:
403         return QLatin1String("lighter");
404     case QPainter::CompositionMode_ColorDodge:
405         return QLatin1String("qt-color-dodge");
406     case QPainter::CompositionMode_ColorBurn:
407         return QLatin1String("qt-color-burn");
408     case QPainter::CompositionMode_HardLight:
409         return QLatin1String("qt-hard-light");
410     case QPainter::CompositionMode_SoftLight:
411         return QLatin1String("qt-soft-light");
412     case QPainter::CompositionMode_Difference:
413         return QLatin1String("qt-difference");
414     case QPainter::CompositionMode_Exclusion:
415         return QLatin1String("qt-exclusion");
416     default:
417         break;
418     }
419     return QString();
420 }
421
422
423 static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
424 {
425     QQuickContext2DEngineData *ed = engineData(engine);
426     v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
427     QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
428     if (image.isNull()) {
429         r->image = QImage(w, h, QImage::Format_ARGB32);
430         r->image.fill(0x00000000);
431     } else {
432         Q_ASSERT(image.width() == w && image.height() == h);
433         r->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
434     }
435     v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
436     pixelData->SetExternalResource(r);
437
438     imageData->SetInternalField(0, pixelData);
439     return imageData;
440 }
441
442 //static script functions
443
444 /*!
445     \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
446      Holds the canvas item that the context paints on.
447
448      This property is read only.
449 */
450 static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
451 {
452     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
453     CHECK_CONTEXT(r)
454
455
456     QV8Engine *engine = V8ENGINE_ACCESSOR();
457
458     return engine->newQObject(r->context->canvas());
459 }
460
461 /*!
462     \qmlmethod object QtQuick2::Context2D::restore()
463     Pops the top state on the stack, restoring the context to that state.
464
465     \sa QtQuick2::Context2D::save()
466 */
467 static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
468 {
469     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
470     CHECK_CONTEXT(r)
471
472     r->context->popState();
473     return args.This();
474 }
475
476 /*!
477     \qmlmethod object QtQuick2::Context2D::reset()
478     Resets the context state and properties to the default values.
479 */
480 static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
481 {
482     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
483     CHECK_CONTEXT(r)
484
485     r->context->reset();
486
487     return args.This();
488 }
489
490 /*!
491     \qmlmethod object QtQuick2::Context2D::save()
492     Pushes the current state onto the state stack.
493
494     Before changing any state attributes, you should save the current state
495     for future reference. The context maintains a stack of drawing states.
496     Each state consists of the current transformation matrix, clipping region,
497     and values of the following attributes:
498     \list
499     \li\a QtQuick2::Context2D::strokeStyle
500     \li\a QtQuick2::Context2D::fillStyle
501     \li\a QtQuick2::Context2D::fillRule
502     \li\a QtQuick2::Context2D::globalAlpha
503     \li\a QtQuick2::Context2D::lineWidth
504     \li\a QtQuick2::Context2D::lineCap
505     \li\a QtQuick2::Context2D::lineJoin
506     \li\a QtQuick2::Context2D::miterLimit
507     \li\a QtQuick2::Context2D::shadowOffsetX
508     \li\a QtQuick2::Context2D::shadowOffsetY
509     \li\a QtQuick2::Context2D::shadowBlur
510     \li\a QtQuick2::Context2D::shadowColor
511     \li\a QtQuick2::Context2D::globalCompositeOperation
512     \li\a QtQuick2::Context2D::font
513     \li\a QtQuick2::Context2D::textAlign
514     \li\a QtQuick2::Context2D::textBaseline
515     \endlist
516
517     The current path is NOT part of the drawing state. The path can be reset by
518     invoking the \a QtQuick2::Context2D::beginPath() method.
519 */
520 static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
521 {
522     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
523     CHECK_CONTEXT(r)
524
525     r->context->pushState();
526
527     return args.This();
528 }
529
530 // transformations
531 /*!
532     \qmlmethod object QtQuick2::Context2D::rotate(real angle)
533     Rotate the canvas around the current origin by \c angle in radians and clockwise direction.
534     \code
535     ctx.rotate(Math.PI/2);
536     \endcode
537     \image qml-item-canvas-rotate.png
538
539     The rotation transformation matrix is as follows:
540
541     \image qml-item-canvas-math-rotate.png
542
543     where the \c angle of rotation is in radians.
544
545 */
546 static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
547 {
548     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
549     CHECK_CONTEXT(r)
550
551     if (args.Length() == 1)
552         r->context->rotate(args[0]->NumberValue());
553     return args.This();
554 }
555
556 /*!
557     \qmlmethod object QtQuick2::Context2D::scale(real x, real y)
558     Increases or decreases the size of each unit in the canvas grid by multiplying the scale factors
559     to the current tranform matrix.
560     Where \c x is the scale factor in the horizontal direction and \c y is the scale factor in the
561     vertical direction.
562     The following code doubles the horizontal size of an object drawn on the canvas and half its
563     vertical size:
564     \code
565     ctx.scale(2.0, 0.5);
566     \endcode
567     \image qml-item-canvas-scale.png
568
569 */
570 static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
571 {
572     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
573     CHECK_CONTEXT(r)
574
575
576     if (args.Length() == 2)
577         r->context->scale(args[0]->NumberValue(), args[1]->NumberValue());
578     return args.This();
579 }
580
581 /*!
582     \qmlmethod object QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
583     Changes the transformation matrix to the matrix given by the arguments as described below.
584
585     Modifying the transformation matrix directly enables you to perform scaling,
586     rotating, and translating transformations in a single step.
587
588     Each point on the canvas is multiplied by the matrix before anything is
589     drawn. The \l{HTML5 Canvas API} defines the transformation matrix as:
590
591     \image qml-item-canvas-math.png
592     where:
593     \list
594     \li \c{a} is the scale factor in the horizontal (x) direction
595     \image qml-item-canvas-scalex.png
596     \li \c{c} is the skew factor in the x direction
597     \image qml-item-canvas-canvas-skewx.png
598     \li \c{e} is the translation in the x direction
599     \image qml-item-canvas-canvas-translate.png
600     \li \c{b} is the skew factor in the y (vertical) direction
601     \image qml-item-canvas-canvas-skewy.png
602     \li \c{d} is the scale factor in the y direction
603     \image qml-item-canvas-canvas-scaley.png
604     \li \c{f} is the translation in the y direction
605     \image qml-item-canvas-canvas-translatey.png
606     \li the last row remains constant
607     \endlist
608     The scale factors and skew factors are multiples; \c{e} and \c{f} are
609     coordinate space units, just like the units in the \a QtQuick2::Context2D::translate(x,y)
610     method.
611
612     \sa QtQuick2::Context2D::transform()
613 */
614 static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
615 {
616     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
617     CHECK_CONTEXT(r)
618
619
620     if (args.Length() == 6)
621         r->context->setTransform( args[0]->NumberValue()
622                                                         , args[1]->NumberValue()
623                                                         , args[2]->NumberValue()
624                                                         , args[3]->NumberValue()
625                                                         , args[4]->NumberValue()
626                                                         , args[5]->NumberValue());
627
628     return args.This();
629 }
630
631 /*!
632     \qmlmethod object QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
633     This method is very similar to \a QtQuick2::Context2D::setTransform(), but instead of replacing the old
634     tranform matrix, this method applies the given tranform matrix to the current matrix by mulitplying to it.
635
636     The \a setTransform(a, b, c, d, e, f) method actually resets the current transform to the identity matrix,
637     and then invokes the transform(a, b, c, d, e, f) method with the same arguments.
638
639     \sa QtQuick2::Context2D::setTransform()
640 */
641 static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
642 {
643     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
644     CHECK_CONTEXT(r)
645
646
647     if (args.Length() == 6)
648         r->context->transform( args[0]->NumberValue()
649                                                   , args[1]->NumberValue()
650                                                   , args[2]->NumberValue()
651                                                   , args[3]->NumberValue()
652                                                   , args[4]->NumberValue()
653                                                   , args[5]->NumberValue());
654
655     return args.This();
656 }
657
658 /*!
659     \qmlmethod object QtQuick2::Context2D::translate(real x, real y)
660     Translates the origin of the canvas to point (\c x, \c y).
661
662     \c x is the horizontal distance that the origin is translated, in coordinate space units,
663     \c y is the vertical distance that the origin is translated, in coordinate space units.
664     Translating the origin enables you to draw patterns of different objects on the canvas
665     without having to measure the coordinates manually for each shape.
666 */
667 static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
668 {
669     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
670     CHECK_CONTEXT(r)
671
672
673     if (args.Length() == 2)
674             r->context->translate(args[0]->NumberValue(), args[1]->NumberValue());
675     return args.This();
676 }
677
678
679 /*!
680     \qmlmethod object QtQuick2::Context2D::resetTransform()
681     Reset the transformation matrix to default value.
682
683     \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform(), QtQuick2::Context2D::reset()
684 */
685 static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
686 {
687     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
688     CHECK_CONTEXT(r)
689
690     r->context->setTransform(1, 0, 0, 1, 0, 0);
691
692     return args.This();
693 }
694
695
696 /*!
697     \qmlmethod object QtQuick2::Context2D::shear(real sh, real sv )
698     Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
699 */
700 static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
701 {
702     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
703     CHECK_CONTEXT(r)
704
705     if (args.Length() == 2)
706             r->context->shear(args[0]->NumberValue(), args[1]->NumberValue());
707
708     return args.This();
709 }
710 // compositing
711
712 /*!
713     \qmlproperty real QtQuick2::Context2D::globalAlpha
714      Holds the the current alpha value applied to rendering operations.
715      The value must be in the range from 0.0 (fully transparent) to 1.0 (fully opque).
716      The default value is 1.0.
717 */
718 static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
719 {
720     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
721     CHECK_CONTEXT(r)
722
723     return v8::Number::New(r->context->state.globalAlpha);
724 }
725
726 static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
727 {
728     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
729     CHECK_CONTEXT_SETTER(r)
730
731     qreal globalAlpha = value->NumberValue();
732
733     if (!qIsFinite(globalAlpha))
734         return;
735
736     if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
737         r->context->state.globalAlpha = globalAlpha;
738         r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
739     }
740 }
741
742 /*!
743     \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
744      Holds the the current the current composition operation, from the list below:
745      \list
746      \li source-atop      - A atop B. Display the source image wherever both images are opaque.
747                            Display the destination image wherever the destination image is opaque but the source image is transparent.
748                            Display transparency elsewhere.
749      \li source-in        - A in B. Display the source image wherever both the source image and destination image are opaque.
750                            Display transparency elsewhere.
751      \li source-out       - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
752                            Display transparency elsewhere.
753      \li source-over      - (default) A over B. Display the source image wherever the source image is opaque.
754                            Display the destination image elsewhere.
755      \li destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
756      \li destination-in   - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
757      \li destination-out  - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
758      \li destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
759      \li lighter          - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
760      \li copy             - A (B is ignored). Display the source image instead of the destination image.
761      \li xor              - A xor B. Exclusive OR of the source image and destination image.
762      \endlist
763
764      Additionally, this property also accepts the compositon modes listed in \a {QPainter::CompositionMode}. According to the W3C standard, these
765      extension composition modes are provided as "vendorName-operationName" syntax, for example: \c {QPainter::CompositionMode_Exclusion} is porvided as
766      "qt-exclusion".
767 */
768 static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
769 {
770     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
771     CHECK_CONTEXT(r)
772
773
774     QV8Engine *engine = V8ENGINE_ACCESSOR();
775
776     return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
777 }
778
779 static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
780 {
781     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
782     CHECK_CONTEXT_SETTER(r)
783
784     QV8Engine *engine = V8ENGINE_ACCESSOR();
785
786
787     QString mode = engine->toString(value);
788     QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
789     if (cm == QPainter::CompositionMode_SourceOver && mode != QStringLiteral("source-over"))
790         return;
791
792     if (cm != r->context->state.globalCompositeOperation) {
793         r->context->state.globalCompositeOperation = cm;
794         r->context->buffer()->setGlobalCompositeOperation(cm);
795     }
796 }
797
798 // colors and styles
799 /*!
800     \qmlproperty variant QtQuick2::Context2D::fillStyle
801      Holds the current style used for filling shapes.
802      The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object. Invalid values are ignored.
803      This property accepts several color syntaxes:
804      \list
805      \li 'rgb(red, green, blue)' - for example: 'rgb(255, 100, 55)' or 'rgb(100%, 70%, 30%)'
806      \li 'rgba(red, green, blue, alpha)' - for example: 'rgb(255, 100, 55, 1.0)' or 'rgb(100%, 70%, 30%, 0.5)'
807      \li 'hsl(hue, saturation, lightness)'
808      \li 'hsla(hue, saturation, lightness, alpha)'
809      \li '#RRGGBB' - for example: '#00FFCC'
810      \li Qt.rgba(red, green, blue, alpha) - for example: Qt.rgba(0.3, 0.7, 1, 1.0)
811      \endlist
812      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
813      best performance, because it's already a valid QColor value, does not need to be parsed everytime.
814
815      The default value is  '#000000'.
816      \sa QtQuick2::Context2D::createLinearGradient
817      \sa QtQuick2::Context2D::createRadialGradient
818      \sa QtQuick2::Context2D::createPattern
819      \sa QtQuick2::Context2D::strokeStyle
820  */
821 static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
822 {
823     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
824     CHECK_CONTEXT(r)
825
826     QV8Engine *engine = V8ENGINE_ACCESSOR();
827
828     QColor color = r->context->state.fillStyle.color();
829     if (color.isValid()) {
830         if (color.alpha() == 255)
831             return engine->toString(color.name());
832         QString alphaString = QString::number(color.alphaF(), 'f');
833         while (alphaString.endsWith(QLatin1Char('0')))
834             alphaString.chop(1);
835         if (alphaString.endsWith(QLatin1Char('.')))
836             alphaString += QLatin1Char('0');
837         return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
838     }
839     return r->context->m_fillStyle;
840 }
841
842 static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
843 {
844     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
845     CHECK_CONTEXT_SETTER(r)
846
847     QV8Engine *engine = V8ENGINE_ACCESSOR();
848
849    if (value->IsObject()) {
850        QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
851        if (color.isValid()) {
852            r->context->state.fillStyle = color;
853            r->context->buffer()->setFillStyle(color);
854            r->context->m_fillStyle = value;
855        } else {
856            QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
857            if (style && style->brush != r->context->state.fillStyle) {
858                r->context->state.fillStyle = style->brush;
859                r->context->buffer()->setFillStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
860                r->context->m_fillStyle = value;
861                r->context->state.fillPatternRepeatX = style->patternRepeatX;
862                r->context->state.fillPatternRepeatY = style->patternRepeatY;
863            }
864        }
865    } else if (value->IsString()) {
866        QColor color = qt_color_from_string(value);
867        if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
868             r->context->state.fillStyle = QBrush(color);
869             r->context->buffer()->setFillStyle(r->context->state.fillStyle);
870             r->context->m_fillStyle = value;
871        }
872    }
873 }
874 /*!
875     \qmlproperty enumeration QtQuick2::Context2D::fillRule
876      Holds the current fill rule used for filling shapes. The following fill rules supported:
877      \list
878      \li Qt.OddEvenFill
879      \li Qt.WindingFill
880      \endlist
881      Note: Unlike the \a QPainterPath, the Canvas API uses the winding fill as the default fill rule.
882      The fillRule property is part of the context rendering state.
883
884      \sa QtQuick2::Context2D::fillStyle
885  */
886 static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
887 {
888     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
889     CHECK_CONTEXT(r)
890     QV8Engine *engine = V8ENGINE_ACCESSOR();
891
892     return engine->fromVariant(r->context->state.fillRule);
893 }
894
895 static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
896 {
897     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
898     CHECK_CONTEXT_SETTER(r)
899
900     QV8Engine *engine = V8ENGINE_ACCESSOR();
901
902     if ((value->IsString() && engine->toString(value) == QStringLiteral("WindingFill"))
903       ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
904         r->context->state.fillRule = Qt::WindingFill;
905     } else if ((value->IsString() && engine->toString(value) == QStringLiteral("OddEvenFill"))
906                ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
907         r->context->state.fillRule = Qt::OddEvenFill;
908     } else {
909         //error
910     }
911     r->context->m_path.setFillRule(r->context->state.fillRule);
912 }
913 /*!
914     \qmlproperty variant QtQuick2::Context2D::strokeStyle
915      Holds the current color or style to use for the lines around shapes,
916      The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object.
917      Invalid values are ignored.
918
919      The default value is  '#000000'.
920
921      \sa QtQuick2::Context2D::createLinearGradient
922      \sa QtQuick2::Context2D::createRadialGradient
923      \sa QtQuick2::Context2D::createPattern
924      \sa QtQuick2::Context2D::fillStyle
925  */
926 v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
927 {
928     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
929     CHECK_CONTEXT(r)
930
931     QV8Engine *engine = V8ENGINE_ACCESSOR();
932
933     QColor color = r->context->state.strokeStyle.color();
934     if (color.isValid()) {
935         if (color.alpha() == 255)
936             return engine->toString(color.name());
937         QString alphaString = QString::number(color.alphaF(), 'f');
938         while (alphaString.endsWith(QLatin1Char('0')))
939             alphaString.chop(1);
940         if (alphaString.endsWith(QLatin1Char('.')))
941             alphaString += QLatin1Char('0');
942         return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
943     }
944     return r->context->m_strokeStyle;
945 }
946
947 static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
948 {
949     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
950     CHECK_CONTEXT_SETTER(r)
951
952     QV8Engine *engine = V8ENGINE_ACCESSOR();
953
954     if (value->IsObject()) {
955         QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
956         if (color.isValid()) {
957             r->context->state.fillStyle = color;
958             r->context->buffer()->setStrokeStyle(color);
959             r->context->m_strokeStyle = value;
960         } else {
961             QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
962             if (style && style->brush != r->context->state.strokeStyle) {
963                 r->context->state.strokeStyle = style->brush;
964                 r->context->buffer()->setStrokeStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
965                 r->context->m_strokeStyle = value;
966                 r->context->state.strokePatternRepeatX = style->patternRepeatX;
967                 r->context->state.strokePatternRepeatY = style->patternRepeatY;
968
969             }
970         }
971     } else if (value->IsString()) {
972         QColor color = qt_color_from_string(value);
973         if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
974              r->context->state.strokeStyle = QBrush(color);
975              r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
976              r->context->m_strokeStyle = value;
977         }
978     }
979 }
980
981 /*!
982   \qmlmethod object QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
983    Returns a CanvasGradient object that represents a linear gradient that transitions the color along a line between
984    the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
985
986    A gradient is a smooth transition between colors. There are two types of gradients: linear and radial.
987    Gradients must have two or more color stops, representing color shifts positioned from 0 to 1 between
988    to the gradient's starting and end points or circles.
989
990     \sa QtQuick2::Context2D::CanvasGradient::addColorStop
991     \sa QtQuick2::Context2D::createRadialGradient
992     \sa QtQuick2::Context2D::ctx2d_createConicalGradient
993     \sa QtQuick2::Context2D::createPattern
994     \sa QtQuick2::Context2D::fillStyle
995     \sa QtQuick2::Context2D::strokeStyle
996   */
997
998 static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
999 {
1000     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1001     CHECK_CONTEXT(r)
1002
1003
1004     QV8Engine *engine = V8ENGINE();
1005
1006     if (args.Length() == 4) {
1007         QQuickContext2DEngineData *ed = engineData(engine);
1008         v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1009         QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1010         qreal x0 = args[0]->NumberValue();
1011         qreal y0 = args[1]->NumberValue();
1012         qreal x1 = args[2]->NumberValue();
1013         qreal y1 = args[3]->NumberValue();
1014
1015         if (!qIsFinite(x0)
1016          || !qIsFinite(y0)
1017          || !qIsFinite(x1)
1018          || !qIsFinite(y1))
1019             V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
1020
1021         r->brush = QLinearGradient(x0, y0, x1, y1);
1022         gradient->SetExternalResource(r);
1023         return gradient;
1024     }
1025
1026     return args.This();
1027 }
1028
1029 /*!
1030   \qmlmethod object QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
1031    Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
1032    origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
1033
1034     \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1035     \sa QtQuick2::Context2D::createLinearGradient
1036     \sa QtQuick2::Context2D::ctx2d_createConicalGradient
1037     \sa QtQuick2::Context2D::createPattern
1038     \sa QtQuick2::Context2D::fillStyle
1039     \sa QtQuick2::Context2D::strokeStyle
1040   */
1041
1042 static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
1043 {
1044     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1045     CHECK_CONTEXT(r)
1046
1047
1048     QV8Engine *engine = V8ENGINE();
1049
1050     if (args.Length() == 6) {
1051         QQuickContext2DEngineData *ed = engineData(engine);
1052         v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1053         QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1054
1055         qreal x0 = args[0]->NumberValue();
1056         qreal y0 = args[1]->NumberValue();
1057         qreal r0 = args[2]->NumberValue();
1058         qreal x1 = args[3]->NumberValue();
1059         qreal y1 = args[4]->NumberValue();
1060         qreal r1 = args[5]->NumberValue();
1061
1062         if (!qIsFinite(x0)
1063          || !qIsFinite(y0)
1064          || !qIsFinite(x1)
1065          || !qIsFinite(r0)
1066          || !qIsFinite(r1)
1067          || !qIsFinite(y1))
1068             V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
1069
1070         if (r0 < 0 || r1 < 0)
1071             V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
1072
1073
1074         r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
1075         gradient->SetExternalResource(r);
1076         return gradient;
1077     }
1078
1079     return args.This();
1080 }
1081
1082 /*!
1083   \qmlmethod object QtQuick2::Context2D::createConicalGradient(real x, real y, real angle)
1084    Returns a CanvasGradient object that represents a conical gradient that interpolate colors counter-clockwise around a center point (\c x, \c y)
1085    with start angle \c angle in units of radians.
1086
1087     \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1088     \sa QtQuick2::Context2D::createLinearGradient
1089     \sa QtQuick2::Context2D::ctx2d_createRadialGradient
1090     \sa QtQuick2::Context2D::createPattern
1091     \sa QtQuick2::Context2D::fillStyle
1092     \sa QtQuick2::Context2D::strokeStyle
1093   */
1094
1095 static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &args)
1096 {
1097     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1098     CHECK_CONTEXT(r)
1099
1100
1101     QV8Engine *engine = V8ENGINE();
1102
1103     if (args.Length() == 6) {
1104         QQuickContext2DEngineData *ed = engineData(engine);
1105         v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1106         QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1107
1108         qreal x = args[0]->NumberValue();
1109         qreal y = args[1]->NumberValue();
1110         qreal angle = DEGREES(args[2]->NumberValue());
1111         if (!qIsFinite(x) || !qIsFinite(y))
1112             V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
1113
1114         if (!qIsFinite(angle))
1115             V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
1116
1117         r->brush = QConicalGradient(x, y, angle);
1118         gradient->SetExternalResource(r);
1119         return gradient;
1120     }
1121
1122     return args.This();
1123 }
1124 /*!
1125   \qmlmethod variant createPattern(Color color, enumeration patternMode)
1126   This is a overload function.
1127   Returns a CanvasPattern object that uses the given \c color and \c patternMode.
1128   The valid pattern modes are:
1129     \list
1130     \li Qt.SolidPattern
1131     \li Qt.Dense1Pattern
1132     \li Qt.Dense2Pattern
1133     \li Qt.Dense3Pattern
1134     \li Qt.Dense4Pattern
1135     \li Qt.Dense5Pattern
1136     \li Qt.Dense6Pattern
1137     \li Qt.Dense7Pattern
1138     \li Qt.HorPattern
1139     \li Qt.VerPattern
1140     \li Qt.CrossPattern
1141     \li Qt.BDiagPattern
1142     \li Qt.FDiagPattern
1143     \li Qt.DiagCrossPattern
1144 \endlist
1145     \sa Qt::BrushStyle
1146  */
1147 /*!
1148   \qmlmethod variant createPattern(Image image, string repetition)
1149   Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
1150
1151   The \a image parameter must be a valid Image item, a valid \a QtQuick2::CanvasImageData object or loaded image url, if there is no image data, throws an INVALID_STATE_ERR exception.
1152
1153   The allowed values for \a repetition are:
1154
1155   \list
1156   \li "repeat"    - both directions
1157   \li "repeat-x   - horizontal only
1158   \li "repeat-y"  - vertical only
1159   \li "no-repeat" - neither
1160   \endlist
1161
1162   If the repetition argument is empty or null, the value "repeat" is used.
1163
1164   \sa QtQuick2::Context2D::strokeStyle
1165   \sa QtQuick2::Context2D::fillStyle
1166   */
1167 static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
1168 {
1169     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1170     CHECK_CONTEXT(r)
1171
1172
1173     QV8Engine *engine = V8ENGINE();
1174
1175     if (args.Length() == 2) {
1176         QQuickContext2DEngineData *ed = engineData(engine);
1177         QV8Context2DStyleResource *styleResouce = new QV8Context2DStyleResource(engine);
1178
1179         QColor color = engine->toVariant(args[0], qMetaTypeId<QColor>()).value<QColor>();
1180         if (color.isValid()) {
1181             int patternMode = args[1]->IntegerValue();
1182             Qt::BrushStyle style = Qt::SolidPattern;
1183             if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
1184                 style = static_cast<Qt::BrushStyle>(patternMode);
1185             }
1186             styleResouce->brush = QBrush(color, style);
1187         } else {
1188             QImage patternTexture;
1189
1190             if (args[0]->IsObject()) {
1191                 QV8Context2DPixelArrayResource *pixelData = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->Get(v8::String::New("data"))->ToObject());
1192                 if (pixelData) {
1193                     patternTexture = pixelData->image;
1194                 }
1195             } else {
1196                 patternTexture = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
1197             }
1198
1199             if (!patternTexture.isNull()) {
1200                 styleResouce->brush.setTextureImage(patternTexture);
1201
1202                 QString repetition = engine->toString(args[1]);
1203                 if (repetition == QStringLiteral("repeat") || repetition.isEmpty()) {
1204                     styleResouce->patternRepeatX = true;
1205                     styleResouce->patternRepeatY = true;
1206                 } else if (repetition == QStringLiteral("repeat-x")) {
1207                     styleResouce->patternRepeatX = true;
1208                 } else if (repetition == QStringLiteral("repeat-y")) {
1209                     styleResouce->patternRepeatY = true;
1210                 } else if (repetition == QStringLiteral("no-repeat")) {
1211                     styleResouce->patternRepeatY = false;
1212                     styleResouce->patternRepeatY = false;
1213                 } else {
1214                     //TODO: exception: SYNTAX_ERR
1215                 }
1216
1217             }
1218         }
1219
1220         v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
1221         pattern->SetExternalResource(styleResouce);
1222         return pattern;
1223
1224     }
1225     return v8::Undefined();
1226 }
1227
1228 // line styles
1229 /*!
1230     \qmlproperty string QtQuick2::Context2D::lineCap
1231      Holds the the current line cap style.
1232      The possible line cap styles are:
1233     \list
1234     \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.
1235     \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.
1236     \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.
1237     \endlist
1238     Other values are ignored.
1239 */
1240 v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
1241 {
1242     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1243     CHECK_CONTEXT(r)
1244
1245
1246     QV8Engine *engine = V8ENGINE_ACCESSOR();
1247     switch (r->context->state.lineCap) {
1248     case Qt::RoundCap:
1249         return engine->toString(QLatin1String("round"));
1250     case Qt::FlatCap:
1251         return engine->toString(QLatin1String("butt"));
1252     case Qt::SquareCap:
1253         return engine->toString(QLatin1String("square"));
1254     default:
1255         break;
1256     }
1257     return engine->toString(QLatin1String("butt"));;
1258 }
1259
1260 static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1261 {
1262     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1263     CHECK_CONTEXT_SETTER(r)
1264
1265     QV8Engine *engine = V8ENGINE_ACCESSOR();
1266
1267     QString lineCap = engine->toString(value);
1268     Qt::PenCapStyle cap;
1269     if (lineCap == QLatin1String("round"))
1270         cap = Qt::RoundCap;
1271     else if (lineCap == QLatin1String("butt"))
1272         cap = Qt::FlatCap;
1273     else if (lineCap == QLatin1String("square"))
1274         cap = Qt::SquareCap;
1275     else
1276         return;
1277
1278     if (cap != r->context->state.lineCap) {
1279         r->context->state.lineCap = cap;
1280         r->context->buffer()->setLineCap(cap);
1281     }
1282 }
1283
1284 /*!
1285     \qmlproperty string QtQuick2::Context2D::lineJoin
1286      Holds the the current line join style. A join exists at any point in a subpath
1287      shared by two consecutive lines. When a subpath is closed, then a join also exists
1288      at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
1289
1290     The possible line join styles are:
1291     \list
1292     \li bevel - this is all that is rendered at joins.
1293     \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.
1294     \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.
1295     \endlist
1296     Other values are ignored.
1297 */
1298 v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
1299 {
1300     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1301     CHECK_CONTEXT(r)
1302
1303
1304     QV8Engine *engine = V8ENGINE_ACCESSOR();
1305     switch (r->context->state.lineJoin) {
1306     case Qt::RoundJoin:
1307         return engine->toString(QLatin1String("round"));
1308     case Qt::BevelJoin:
1309         return engine->toString(QLatin1String("bevel"));
1310     case Qt::MiterJoin:
1311         return engine->toString(QLatin1String("miter"));
1312     default:
1313         break;
1314     }
1315     return engine->toString(QLatin1String("miter"));
1316 }
1317
1318 static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1319 {
1320     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1321     CHECK_CONTEXT_SETTER(r)
1322
1323     QV8Engine *engine = V8ENGINE_ACCESSOR();
1324
1325     QString lineJoin = engine->toString(value);
1326     Qt::PenJoinStyle join;
1327     if (lineJoin == QLatin1String("round"))
1328         join = Qt::RoundJoin;
1329     else if (lineJoin == QLatin1String("bevel"))
1330         join = Qt::BevelJoin;
1331     else if (lineJoin == QLatin1String("miter"))
1332         join = Qt::SvgMiterJoin;
1333     else
1334         return;
1335
1336     if (join != r->context->state.lineJoin) {
1337         r->context->state.lineJoin = join;
1338         r->context->buffer()->setLineJoin(join);
1339     }
1340 }
1341
1342 /*!
1343     \qmlproperty real QtQuick2::Context2D::lineWidth
1344      Holds the the current line width. Values that are not finite values greater than zero are ignored.
1345  */
1346 v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
1347 {
1348     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1349     CHECK_CONTEXT(r)
1350
1351
1352     return v8::Number::New(r->context->state.lineWidth);
1353 }
1354
1355 static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1356 {
1357     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1358     CHECK_CONTEXT_SETTER(r)
1359
1360     qreal w = value->NumberValue();
1361
1362     if (w > 0 && qIsFinite(w) && w != r->context->state.lineWidth) {
1363         r->context->state.lineWidth = w;
1364         r->context->buffer()->setLineWidth(w);
1365     }
1366 }
1367
1368 /*!
1369     \qmlproperty real QtQuick2::Context2D::miterLimit
1370      Holds the current miter limit ratio.
1371      The default miter limit value is 10.0.
1372  */
1373 v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
1374 {
1375     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1376     CHECK_CONTEXT(r)
1377
1378
1379     return v8::Number::New(r->context->state.miterLimit);
1380 }
1381
1382 static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1383 {
1384     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1385     CHECK_CONTEXT_SETTER(r)
1386
1387     qreal ml = value->NumberValue();
1388
1389     if (ml > 0 && qIsFinite(ml) && ml != r->context->state.miterLimit) {
1390         r->context->state.miterLimit = ml;
1391         r->context->buffer()->setMiterLimit(ml);
1392     }
1393 }
1394
1395 // shadows
1396 /*!
1397     \qmlproperty real QtQuick2::Context2D::shadowBlur
1398      Holds the current level of blur applied to shadows
1399  */
1400 v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
1401 {
1402     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1403     CHECK_CONTEXT(r)
1404
1405
1406     return v8::Number::New(r->context->state.shadowBlur);
1407 }
1408
1409 static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1410 {
1411     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1412     CHECK_CONTEXT_SETTER(r)
1413     qreal blur = value->NumberValue();
1414
1415     if (blur > 0 && qIsFinite(blur) && blur != r->context->state.shadowBlur) {
1416         r->context->state.shadowBlur = blur;
1417         r->context->buffer()->setShadowBlur(blur);
1418     }
1419 }
1420
1421 /*!
1422     \qmlproperty string QtQuick2::Context2D::shadowColor
1423      Holds the current shadow color.
1424  */
1425 v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
1426 {
1427     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1428     CHECK_CONTEXT(r)
1429
1430
1431     QV8Engine *engine = V8ENGINE_ACCESSOR();
1432
1433     return engine->toString(r->context->state.shadowColor.name());
1434 }
1435
1436 static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1437 {
1438     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1439     CHECK_CONTEXT_SETTER(r)
1440
1441     QColor color = qt_color_from_string(value);
1442
1443     if (color.isValid() && color != r->context->state.shadowColor) {
1444         r->context->state.shadowColor = color;
1445         r->context->buffer()->setShadowColor(color);
1446     }
1447 }
1448
1449
1450 /*!
1451     \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
1452      Holds the current shadow offset in the positive horizontal distance.
1453
1454      \sa QtQuick2::Context2D::shadowOffsetY
1455  */
1456 v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
1457 {
1458     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1459     CHECK_CONTEXT(r)
1460
1461
1462     return v8::Number::New(r->context->state.shadowOffsetX);
1463 }
1464
1465 static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1466 {
1467     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1468     CHECK_CONTEXT_SETTER(r)
1469
1470     qreal offsetX = value->NumberValue();
1471     if (qIsFinite(offsetX) && offsetX != r->context->state.shadowOffsetX) {
1472         r->context->state.shadowOffsetX = offsetX;
1473         r->context->buffer()->setShadowOffsetX(offsetX);
1474     }
1475 }
1476 /*!
1477     \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
1478      Holds the current shadow offset in the positive vertical distance.
1479
1480      \sa QtQuick2::Context2D::shadowOffsetX
1481  */
1482 v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
1483 {
1484     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1485     CHECK_CONTEXT(r)
1486
1487
1488     return v8::Number::New(r->context->state.shadowOffsetY);
1489 }
1490
1491 static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1492 {
1493     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1494     CHECK_CONTEXT_SETTER(r)
1495
1496     qreal offsetY = value->NumberValue();
1497     if (qIsFinite(offsetY) && offsetY != r->context->state.shadowOffsetY) {
1498         r->context->state.shadowOffsetY = offsetY;
1499         r->context->buffer()->setShadowOffsetY(offsetY);
1500     }
1501 }
1502
1503 v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
1504 {
1505     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1506     CHECK_CONTEXT(r)
1507     return r->context->m_v8path;
1508 }
1509
1510 static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1511 {
1512     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1513     CHECK_CONTEXT_SETTER(r)
1514     QV8Engine *engine = V8ENGINE_ACCESSOR();
1515
1516     r->context->beginPath();
1517     if (value->IsObject()) {
1518         QQuickPath* path = qobject_cast<QQuickPath*>(engine->toQObject(value));
1519         if (path)
1520             r->context->m_path = path->path();
1521     } else {
1522         QString path = engine->toString(value->ToString());
1523         QQuickSvgParser::parsePathDataFast(path, r->context->m_path);
1524     }
1525     r->context->m_v8path = value;
1526 }
1527
1528 //rects
1529 /*!
1530   \qmlmethod object QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
1531   Clears all pixels on the canvas in the given rectangle to transparent black.
1532   */
1533 static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
1534 {
1535     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1536     CHECK_CONTEXT(r)
1537
1538
1539     if (args.Length() == 4)
1540         r->context->clearRect(args[0]->NumberValue(),
1541                               args[1]->NumberValue(),
1542                               args[2]->NumberValue(),
1543                               args[3]->NumberValue());
1544
1545     return args.This();
1546 }
1547 /*!
1548   \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1549    Paint the specified rectangular area using the fillStyle.
1550
1551    \sa QtQuick2::Context2D::fillStyle
1552   */
1553 static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
1554 {
1555     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1556     CHECK_CONTEXT(r)
1557
1558     if (args.Length() == 4)
1559         r->context->fillRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1560     return args.This();
1561 }
1562
1563 /*!
1564   \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1565    Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
1566    and (if appropriate) miterLimit attributes.
1567
1568    \sa QtQuick2::Context2D::strokeStyle
1569    \sa QtQuick2::Context2D::lineWidth
1570    \sa QtQuick2::Context2D::lineJoin
1571    \sa QtQuick2::Context2D::miterLimit
1572   */
1573 static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
1574 {
1575     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1576     CHECK_CONTEXT(r)
1577
1578     if (args.Length() == 4)
1579         r->context->strokeRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1580
1581     return args.This();
1582 }
1583
1584 // Complex shapes (paths) API
1585 /*!
1586   \qmlmethod object QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
1587   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.
1588   \image qml-item-canvas-arcTo2.png
1589   \sa QtQuick2::Context2D::arcTo,
1590       {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
1591   */
1592 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
1593 {
1594     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1595     CHECK_CONTEXT(r)
1596
1597     if (args.Length() >= 5) {
1598         bool antiClockwise = false;
1599
1600         if (args.Length() == 6)
1601             antiClockwise = args[5]->BooleanValue();
1602
1603         qreal radius = args[2]->NumberValue();
1604
1605         if (qIsFinite(radius) && radius < 0)
1606            V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1607
1608         r->context->arc(args[0]->NumberValue(),
1609                         args[1]->NumberValue(),
1610                         radius,
1611                         args[3]->NumberValue(),
1612                         args[4]->NumberValue(),
1613                         antiClockwise);
1614     }
1615
1616     return args.This();
1617 }
1618
1619 /*!
1620   \qmlmethod object QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
1621
1622    Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
1623    To draw an arc, you begin with the same steps your followed to create a line:
1624     \list
1625     \li Call the context.beginPath() method to set a new path.
1626     \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).
1627     \li To draw an arc or circle, call the context.arcTo(\c x1, \c y1, \c x2, \c y2,\c radius) method.
1628        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
1629        it to the previous subpath by a straight line.
1630     \endlist
1631     \image qml-item-canvas-arcTo.png
1632     Both startAngle and endAngle are measured from the x axis in units of radians.
1633
1634     \image qml-item-canvas-startAngle.png
1635     The anticlockwise has the value TRUE for each arc in the figure above because they are all drawn in the counterclockwise direction.
1636   \sa QtQuick2::Context2D::arc, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d
1637       context standard for arcTo}
1638   */
1639 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
1640 {
1641     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1642     CHECK_CONTEXT(r)
1643
1644     if (args.Length() == 5) {
1645         qreal radius = args[4]->NumberValue();
1646
1647         if (qIsFinite(radius) && radius < 0)
1648            V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1649
1650         r->context->arcTo(args[0]->NumberValue(),
1651                           args[1]->NumberValue(),
1652                           args[2]->NumberValue(),
1653                           args[3]->NumberValue(),
1654                           radius);
1655     }
1656
1657     return args.This();
1658 }
1659
1660 /*!
1661   \qmlmethod object QtQuick2::Context2D::beginPath()
1662
1663    Resets the current path to a new path.
1664   */
1665 static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
1666 {
1667     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1668     CHECK_CONTEXT(r)
1669
1670
1671     r->context->beginPath();
1672
1673     return args.This();
1674 }
1675
1676 /*!
1677   \qmlmethod object QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
1678
1679   Adds a cubic Bezier curve between the current position and the given endPoint using the control points specified by (\c cp1x, cp1y),
1680   and (\c cp2x, \c cp2y).
1681   After the curve is added, the current position is updated to be at the end point (\c x, \c y) of the curve.
1682   The following code produces the path shown below:
1683   \code
1684   ctx.strokeStyle = Qt.rgba(0, 0, 0, 1);
1685   ctx.lineWidth = 1;
1686   ctx.beginPath();
1687   ctx.moveTo(20, 0);//start point
1688   ctx.bezierCurveTo(-10, 90, 210, 90, 180, 0);
1689   ctx.stroke();
1690   \endcode
1691    \image qml-item-canvas-bezierCurveTo.png
1692   \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
1693   \sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
1694   */
1695 static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
1696 {
1697     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1698     CHECK_CONTEXT(r)
1699
1700
1701     if (args.Length() == 6) {
1702         qreal cp1x = args[0]->NumberValue();
1703         qreal cp1y = args[1]->NumberValue();
1704         qreal cp2x = args[2]->NumberValue();
1705         qreal cp2y = args[3]->NumberValue();
1706         qreal x = args[4]->NumberValue();
1707         qreal y = args[5]->NumberValue();
1708
1709         if (!qIsFinite(cp1x) || !qIsFinite(cp1y) || !qIsFinite(cp2x) || !qIsFinite(cp2y) || !qIsFinite(x) || !qIsFinite(y))
1710             return args.This();
1711
1712         r->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
1713     }
1714
1715     return args.This();
1716 }
1717
1718 /*!
1719   \qmlmethod object QtQuick2::Context2D::clip()
1720
1721    Creates the clipping region from the current path.
1722    Any parts of the shape outside the clipping path are not displayed.
1723    To create a complex shape using the \a clip() method:
1724
1725     \list 1
1726     \li Call the \c{context.beginPath()} method to set the clipping path.
1727     \li Define the clipping path by calling any combination of the \c{lineTo},
1728     \c{arcTo}, \c{arc}, \c{moveTo}, etc and \c{closePath} methods.
1729     \li Call the \c{context.clip()} method.
1730     \endlist
1731
1732     The new shape displays.  The following shows how a clipping path can
1733     modify how an image displays:
1734
1735     \image qml-canvas-clip-complex.png
1736     \sa QtQuick2::Context2D::beginPath()
1737     \sa QtQuick2::Context2D::closePath()
1738     \sa QtQuick2::Context2D::stroke()
1739     \sa QtQuick2::Context2D::fill()
1740    \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-clip}{W3C 2d context standard for clip}
1741   */
1742 static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
1743 {
1744     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1745     CHECK_CONTEXT(r)
1746
1747     r->context->clip();
1748     return args.This();
1749 }
1750
1751 /*!
1752   \qmlmethod object QtQuick2::Context2D::closePath()
1753    Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting a new path.
1754    The current point of the new path is the previous subpath's first point.
1755
1756    \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath}{W3C 2d context standard for closePath}
1757   */
1758 static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
1759 {
1760     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1761     CHECK_CONTEXT(r)
1762
1763
1764     r->context->closePath();
1765
1766     return args.This();
1767 }
1768
1769 /*!
1770   \qmlmethod object QtQuick2::Context2D::fill()
1771
1772    Fills the subpaths with the current fill style.
1773
1774    \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-fill}{W3C 2d context standard for fill}
1775
1776    \sa QtQuick2::Context2D::fillStyle
1777   */
1778 static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
1779 {
1780     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1781     CHECK_CONTEXT(r);
1782     r->context->fill();
1783     return args.This();
1784 }
1785
1786 /*!
1787   \qmlmethod object QtQuick2::Context2D::lineTo(real x, real y)
1788
1789    Draws a line from the current position to the point (x, y).
1790  */
1791 static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
1792 {
1793     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1794     CHECK_CONTEXT(r)
1795
1796
1797     if (args.Length() == 2) {
1798         qreal x = args[0]->NumberValue();
1799         qreal y = args[1]->NumberValue();
1800
1801         if (!qIsFinite(x) || !qIsFinite(y))
1802             return args.This();
1803
1804         r->context->lineTo(x, y);
1805     }
1806
1807     return args.This();
1808 }
1809
1810 /*!
1811   \qmlmethod object QtQuick2::Context2D::moveTo(real x, real y)
1812
1813    Creates a new subpath with the given point.
1814  */
1815 static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
1816 {
1817     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1818     CHECK_CONTEXT(r)
1819
1820     if (args.Length() == 2) {
1821         qreal x = args[0]->NumberValue();
1822         qreal y = args[1]->NumberValue();
1823
1824         if (!qIsFinite(x) || !qIsFinite(y))
1825             return args.This();
1826         r->context->moveTo(x, y);
1827     }
1828     return args.This();
1829 }
1830
1831 /*!
1832   \qmlmethod object QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
1833
1834    Adds a quadratic Bezier curve between the current point and the endpoint (\c x, \c y) with the control point specified by (\c cpx, \c cpy).
1835
1836    See {http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto}{W3C 2d context standard for  for quadraticCurveTo}
1837  */
1838 static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
1839 {
1840     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1841     CHECK_CONTEXT(r)
1842
1843     if (args.Length() == 4) {
1844         qreal cpx = args[0]->NumberValue();
1845         qreal cpy = args[1]->NumberValue();
1846         qreal x = args[2]->NumberValue();
1847         qreal y = args[3]->NumberValue();
1848
1849         if (!qIsFinite(cpx) || !qIsFinite(cpy) || !qIsFinite(x) || !qIsFinite(y))
1850             return args.This();
1851
1852         r->context->quadraticCurveTo(cpx, cpy, x, y);
1853     }
1854
1855     return args.This();
1856 }
1857
1858 /*!
1859   \qmlmethod object QtQuick2::Context2D::rect(real x, real y, real w, real h)
1860
1861    Adds a rectangle at position (\c x, \c y), with the given width \c w and height \c h, as a closed subpath.
1862  */
1863 static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
1864 {
1865     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1866     CHECK_CONTEXT(r)
1867
1868     if (args.Length() == 4)
1869         r->context->rect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1870     return args.This();
1871 }
1872
1873 /*!
1874   \qmlmethod object QtQuick2::Context2D::roundedRect(real x, real y, real w, real h,  real xRadius, real yRadius)
1875
1876    Adds the given rectangle rect with rounded corners to the path. The \c xRadius and \c yRadius arguments specify the radius of the
1877    ellipses defining the corners of the rounded rectangle.
1878  */
1879 static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
1880 {
1881     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1882     CHECK_CONTEXT(r)
1883
1884     if (args.Length() == 6)
1885         r->context->roundedRect(args[0]->NumberValue()
1886                               , args[1]->NumberValue()
1887                               , args[2]->NumberValue()
1888                               , args[3]->NumberValue()
1889                               , args[4]->NumberValue()
1890                               , args[5]->NumberValue());
1891     return args.This();
1892 }
1893
1894 /*!
1895   \qmlmethod object QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
1896
1897   Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
1898   and adds it to the path as a closed subpath.
1899
1900   The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
1901  */
1902 static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
1903 {
1904     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1905     CHECK_CONTEXT(r)
1906
1907
1908     if (args.Length() == 4)
1909         r->context->ellipse(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1910
1911     return args.This();
1912 }
1913
1914 /*!
1915   \qmlmethod object QtQuick2::Context2D::text(string text, real x, real y)
1916
1917   Adds the given \c text to the path as a set of closed subpaths created from the current context font supplied.
1918   The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (\c x, \c y).
1919  */
1920 static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
1921 {
1922     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1923     CHECK_CONTEXT(r)
1924
1925     QV8Engine *engine = V8ENGINE();
1926     if (args.Length() == 3) {
1927         qreal x = args[1]->NumberValue();
1928         qreal y = args[2]->NumberValue();
1929
1930         if (!qIsFinite(x) || !qIsFinite(y))
1931             return args.This();
1932         r->context->text(engine->toString(args[0]), x, y);
1933     }
1934     return args.This();
1935 }
1936
1937 /*!
1938   \qmlmethod object QtQuick2::Context2D::stroke()
1939
1940    Strokes the subpaths with the current stroke style.
1941
1942    See {http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke}{W3C 2d context standard for stroke}
1943
1944    \sa QtQuick2::Context2D::strokeStyle
1945   */
1946 static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
1947 {
1948     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1949     CHECK_CONTEXT(r)
1950
1951     r->context->stroke();
1952     return args.This();
1953 }
1954
1955 /*!
1956   \qmlmethod object QtQuick2::Context2D::isPointInPath(real x, real y)
1957
1958    Returns true if the given point is in the current path.
1959
1960    \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath}{W3C 2d context standard for isPointInPath}
1961   */
1962 static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
1963 {
1964     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1965     CHECK_CONTEXT(r)
1966
1967     bool pointInPath = false;
1968     if (args.Length() == 2)
1969         pointInPath = r->context->isPointInPath(args[0]->NumberValue(), args[1]->NumberValue());
1970     return v8::Boolean::New(pointInPath);
1971 }
1972
1973 static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
1974 {
1975     V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
1976     return args.This();
1977 }
1978
1979 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
1980 {
1981     V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
1982     return args.This();
1983 }
1984
1985 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
1986 {
1987     V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
1988     return args.This();
1989 }
1990 // text
1991 /*!
1992   \qmlproperty string QtQuick2::Context2D::font
1993   Holds the current font settings.
1994
1995   The default font value is "10px sans-serif".
1996   See {http://www.w3.org/TR/2dcontext/#dom-context-2d-font}{w3C 2d context standard for font}
1997   */
1998 v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
1999 {
2000     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2001     CHECK_CONTEXT(r)
2002
2003     QV8Engine *engine = V8ENGINE_ACCESSOR();
2004
2005     return engine->toString(r->context->state.font.toString());
2006 }
2007
2008 static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2009 {
2010     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2011     CHECK_CONTEXT_SETTER(r)
2012
2013     QV8Engine *engine = V8ENGINE_ACCESSOR();
2014     QString fs = engine->toString(value);
2015     QFont font = qt_font_from_string(fs);
2016     if (font != r->context->state.font) {
2017         r->context->state.font = font;
2018     }
2019 }
2020
2021 /*!
2022   \qmlproperty string QtQuick2::Context2D::textAlign
2023
2024   Holds the current text alignment settings.
2025   The possible values are:
2026   \list
2027     \li start
2028     \li end
2029     \li left
2030     \li right
2031     \li center
2032   \endlist
2033   Other values are ignored. The default value is "start".
2034   */
2035 v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
2036 {
2037     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2038     CHECK_CONTEXT(r)
2039     QV8Engine *engine = V8ENGINE_ACCESSOR();
2040     switch (r->context->state.textAlign) {
2041     case QQuickContext2D::Start:
2042         return engine->toString(QLatin1String("start"));
2043    case QQuickContext2D::End:
2044         return engine->toString(QLatin1String("end"));
2045    case QQuickContext2D::Left:
2046         return engine->toString(QLatin1String("left"));
2047    case QQuickContext2D::Right:
2048         return engine->toString(QLatin1String("right"));
2049    case QQuickContext2D::Center:
2050         return engine->toString(QLatin1String("center"));
2051     default:
2052         break;
2053     }
2054     return engine->toString(QLatin1String("start"));
2055 }
2056
2057 static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2058 {
2059     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2060     CHECK_CONTEXT_SETTER(r)
2061     QV8Engine *engine = V8ENGINE_ACCESSOR();
2062
2063     QString textAlign = engine->toString(value);
2064
2065     QQuickContext2D::TextAlignType ta;
2066     if (textAlign == QLatin1String("start"))
2067         ta = QQuickContext2D::Start;
2068     else if (textAlign == QLatin1String("end"))
2069         ta = QQuickContext2D::End;
2070     else if (textAlign == QLatin1String("left"))
2071         ta = QQuickContext2D::Left;
2072     else if (textAlign == QLatin1String("right"))
2073         ta = QQuickContext2D::Right;
2074     else if (textAlign == QLatin1String("center"))
2075         ta = QQuickContext2D::Center;
2076     else
2077         return;
2078
2079     if (ta != r->context->state.textAlign) {
2080         r->context->state.textAlign = ta;
2081     }
2082 }
2083
2084 /*!
2085   \qmlproperty string QtQuick2::Context2D::textBaseline
2086
2087   Holds the current baseline alignment settings.
2088   The possible values are:
2089   \list
2090     \li top
2091     \li hanging
2092     \li middle
2093     \li alphabetic
2094     \li ideographic
2095     \li bottom
2096   \endlist
2097   Other values are ignored. The default value is "alphabetic".
2098   */
2099 v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
2100 {
2101     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2102     CHECK_CONTEXT(r)
2103
2104     QV8Engine *engine = V8ENGINE_ACCESSOR();
2105     switch (r->context->state.textBaseline) {
2106     case QQuickContext2D::Alphabetic:
2107         return engine->toString(QLatin1String("alphabetic"));
2108     case QQuickContext2D::Hanging:
2109         return engine->toString(QLatin1String("hanging"));
2110     case QQuickContext2D::Top:
2111         return engine->toString(QLatin1String("top"));
2112     case QQuickContext2D::Bottom:
2113         return engine->toString(QLatin1String("bottom"));
2114     case QQuickContext2D::Middle:
2115         return engine->toString(QLatin1String("middle"));
2116     default:
2117         break;
2118     }
2119     return engine->toString(QLatin1String("alphabetic"));
2120 }
2121
2122 static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2123 {
2124     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2125     CHECK_CONTEXT_SETTER(r)
2126     QV8Engine *engine = V8ENGINE_ACCESSOR();
2127     QString textBaseline = engine->toString(value);
2128
2129     QQuickContext2D::TextBaseLineType tb;
2130     if (textBaseline == QLatin1String("alphabetic"))
2131         tb = QQuickContext2D::Alphabetic;
2132     else if (textBaseline == QLatin1String("hanging"))
2133         tb = QQuickContext2D::Hanging;
2134     else if (textBaseline == QLatin1String("top"))
2135         tb = QQuickContext2D::Top;
2136     else if (textBaseline == QLatin1String("bottom"))
2137         tb = QQuickContext2D::Bottom;
2138     else if (textBaseline == QLatin1String("middle"))
2139         tb = QQuickContext2D::Middle;
2140     else
2141         return;
2142
2143     if (tb != r->context->state.textBaseline) {
2144         r->context->state.textBaseline = tb;
2145     }
2146 }
2147
2148 /*!
2149   \qmlmethod object QtQuick2::Context2D::fillText(text, x, y)
2150   Fills the given text at the given position.
2151   \sa QtQuick2::Context2D::font
2152   \sa QtQuick2::Context2D::textAlign
2153   \sa QtQuick2::Context2D::textBaseline
2154   \sa QtQuick2::Context2D::strokeText
2155   */
2156 static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
2157 {
2158     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2159     CHECK_CONTEXT(r)
2160
2161     QV8Engine *engine = V8ENGINE();
2162     if (args.Length() == 3) {
2163         qreal x = args[1]->NumberValue();
2164         qreal y = args[2]->NumberValue();
2165         if (!qIsFinite(x) || !qIsFinite(y))
2166             return args.This();
2167         QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
2168         r->context->buffer()->fill(textPath);
2169     }
2170     return args.This();
2171 }
2172 /*!
2173   \qmlmethod object QtQuick2::Context2D::strokeText(text, x, y)
2174   Strokes the given text at the given position.
2175   \sa QtQuick2::Context2D::font
2176   \sa QtQuick2::Context2D::textAlign
2177   \sa QtQuick2::Context2D::textBaseline
2178   \sa QtQuick2::Context2D::fillText
2179   */
2180 static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
2181 {
2182     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2183     CHECK_CONTEXT(r)
2184
2185     QV8Engine *engine = V8ENGINE();
2186     if (args.Length() == 3)
2187         r->context->drawText(engine->toString(args[0]), args[1]->NumberValue(), args[2]->NumberValue(), false);
2188     return args.This();
2189 }
2190 /*!
2191   \qmlclass QtQuick2::TextMetrics
2192     \inqmlmodule QtQuick 2
2193     \since QtQuick 2.0
2194     \brief The Context2D TextMetrics interface.
2195     The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
2196     See {http://www.w3.org/TR/2dcontext/#textmetrics}{W3C 2d context TexMetrics} for more details.
2197
2198     \sa QtQuick2::Context2D::measureText
2199     \sa QtQuick2::TextMetrics::width
2200   */
2201
2202 /*!
2203   \qmlproperty int QtQuick2::TextMetrics::width
2204   Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
2205   This property is read only.
2206   */
2207
2208 /*!
2209   \qmlmethod variant QtQuick2::Context2D::measureText(text)
2210   Returns a TextMetrics object with the metrics of the given text in the current font.
2211   */
2212 static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
2213 {
2214     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2215     CHECK_CONTEXT(r)
2216
2217     QV8Engine *engine = V8ENGINE();
2218
2219     if (args.Length() == 1) {
2220         QFontMetrics fm(r->context->state.font);
2221         uint width = fm.width(engine->toString(args[0]));
2222         v8::Local<v8::Object> tm = v8::Object::New();
2223         tm->Set(v8::String::New("width"), v8::Number::New(width));
2224         return tm;
2225     }
2226     return v8::Undefined();
2227 }
2228
2229 // drawing images
2230 /*!
2231   \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
2232   Draws the given \a image on the canvas at position (\a dx, \a dy).
2233   Note:
2234   The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2235   When given as Image item, if the image isn't fully loaded, this method draws nothing.
2236   When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2237   This image been drawing is subject to the current context clip path, even the given \c image is a  {QtQuick2::CanvasImageData} object.
2238
2239   \sa QtQuick2::CanvasImageData
2240   \sa QtQuick2::Image
2241   \sa QtQuick2::Canvas::loadImage
2242   \sa QtQuick2::Canvas::isImageLoaded
2243   \sa QtQuick2::Canvas::imageLoaded
2244
2245   \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2246   */
2247 /*!
2248   \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
2249   This is an overloaded function.
2250   Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
2251   height \a dh.
2252
2253   Note:
2254   The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2255   When given as Image item, if the image isn't fully loaded, this method draws nothing.
2256   When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2257   This image been drawing is subject to the current context clip path, even the given \c image is a  {QtQuick2::CanvasImageData} object.
2258
2259   \sa QtQuick2::CanvasImageData
2260   \sa QtQuick2::Image
2261   \sa QtQuick2::Canvas::loadImage
2262   \sa QtQuick2::Canvas::isImageLoaded
2263   \sa QtQuick2::Canvas::imageLoaded
2264
2265   \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2266   */
2267 /*!
2268   \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
2269   This is an overloaded function.
2270   Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
2271   onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
2272
2273
2274   Note:
2275   The \a image type can be an Image or Canvas item, an image url or a \a {QtQuick2::CanvasImageData} object.
2276   When given as Image item, if the image isn't fully loaded, this method draws nothing.
2277   When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2278   This image been drawing is subject to the current context clip path, even the given \c image is a  {QtQuick2::CanvasImageData} object.
2279
2280   \sa QtQuick2::CanvasImageData
2281   \sa QtQuick2::Image
2282   \sa QtQuick2::Canvas::loadImage
2283   \sa QtQuick2::Canvas::isImageLoaded
2284   \sa QtQuick2::Canvas::imageLoaded
2285
2286   \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2287 */
2288 static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
2289 {
2290     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2291     CHECK_CONTEXT(r)
2292
2293     QV8Engine *engine = V8ENGINE();
2294     qreal sx, sy, sw, sh, dx, dy, dw, dh;
2295
2296     if (!args.Length())
2297         return args.This();
2298
2299     //FIXME:This function should be moved to QQuickContext2D::drawImage(...)
2300     if (!r->context->state.invertibleCTM)
2301         return args.This();
2302
2303     QImage image;
2304     if (args[0]->IsString()) {
2305         QUrl url(engine->toString(args[0]->ToString()));
2306         if (!url.isValid())
2307             V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2308
2309         image = r->context->createImage(url);
2310     } else if (args[0]->IsObject()) {
2311         QQuickImage *imageItem = qobject_cast<QQuickImage*>(engine->toQObject(args[0]->ToObject()));
2312         QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(engine->toQObject(args[0]->ToObject()));
2313
2314         QV8Context2DPixelArrayResource *pix = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->GetInternalField(0)->ToObject());
2315         if (pix) {
2316             image = pix->image;
2317         } else if (imageItem) {
2318             image = imageItem->image();
2319         } else if (canvas) {
2320             image = canvas->toImage();
2321         } else {
2322             V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2323         }
2324     } else {
2325         V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2326     }
2327     if (args.Length() == 3) {
2328         dx = args[1]->NumberValue();
2329         dy = args[2]->NumberValue();
2330         sx = 0;
2331         sy = 0;
2332         sw = image.width();
2333         sh = image.height();
2334         dw = sw;
2335         dh = sh;
2336     } else if (args.Length() == 5) {
2337         sx = 0;
2338         sy = 0;
2339         sw = image.width();
2340         sh = image.height();
2341         dx = args[1]->NumberValue();
2342         dy = args[2]->NumberValue();
2343         dw = args[3]->NumberValue();
2344         dh = args[4]->NumberValue();
2345     } else if (args.Length() == 9) {
2346         sx = args[1]->NumberValue();
2347         sy = args[2]->NumberValue();
2348         sw = args[3]->NumberValue();
2349         sh = args[4]->NumberValue();
2350         dx = args[5]->NumberValue();
2351         dy = args[6]->NumberValue();
2352         dw = args[7]->NumberValue();
2353         dh = args[8]->NumberValue();
2354     } else {
2355         return args.This();
2356     }
2357
2358     if (!qIsFinite(sx)
2359      || !qIsFinite(sy)
2360      || !qIsFinite(sw)
2361      || !qIsFinite(sh)
2362      || !qIsFinite(dx)
2363      || !qIsFinite(dy)
2364      || !qIsFinite(dw)
2365      || !qIsFinite(dh))
2366         return args.This();
2367
2368     if (!image.isNull()) {
2369         if (sx < 0 || sy < 0 || sw == 0 || sh == 0
2370          || sx + sw > image.width() || sy + sh > image.height()
2371          || sx + sw < 0 || sy + sh < 0) {
2372             V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
2373         }
2374
2375         r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
2376     }
2377
2378     return args.This();
2379 }
2380
2381 // pixel manipulation
2382 /*!
2383   \qmlclass QtQuick2::CanvasImageData
2384      The \a QtQuick2::CanvasImageData object holds the image pixel data.
2385
2386      The \a QtQuick2::CanvasImageData object has the actual dimensions of the data stored in
2387      this object and holds the one-dimensional array containing the data in RGBA order,
2388      as integers in the range 0 to 255.
2389
2390      \sa QtQuick2::CanvasImageData::width
2391      \sa QtQuick2::CanvasImageData::height
2392      \sa QtQuick2::CanvasImageData::data
2393      \sa QtQuick2::Context2D::createImageData
2394      \sa QtQuick2::Context2D::getImageData
2395      \sa QtQuick2::Context2D::putImageData
2396   */
2397 /*!
2398   \qmlproperty QtQuick2::CanvasImageData::width
2399   Holds the actual width dimension of the data in the ImageData object, in device pixels.
2400  */
2401 v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
2402 {
2403     QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2404     if (!r)
2405         return v8::Integer::New(0);
2406     return v8::Integer::New(r->image.width());
2407 }
2408
2409 /*!
2410   \qmlproperty QtQuick2::CanvasImageData::height
2411   Holds the actual height dimension of the data in the ImageData object, in device pixels.
2412   */
2413 v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
2414 {
2415     QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2416     if (!r)
2417         return v8::Integer::New(0);
2418
2419     return v8::Integer::New(r->image.height());
2420 }
2421
2422 /*!
2423   \qmlproperty QtQuick2::CanvasImageData::data
2424   Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
2425  */
2426 v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
2427 {
2428     return args.This()->GetInternalField(0);
2429 }
2430
2431 /*!
2432   \qmlclass QtQuick2::CanvasPixelArray
2433   The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
2434   The CanvasPixelArray can be accessed as normal Javascript array.
2435     \sa QtQuick2::CanvasImageData
2436     \sa {http://www.w3.org/TR/2dcontext/#canvaspixelarray}{W3C 2d context standard for PixelArray}
2437   */
2438
2439 /*!
2440   \qmlproperty QtQuick2::CanvasPixelArray::length
2441   The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
2442   The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
2443   This property is read only.
2444 */
2445 v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
2446 {
2447     QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2448     if (!r || r->image.isNull()) return v8::Undefined();
2449
2450     return v8::Integer::New(r->image.width() * r->image.height() * 4);
2451 }
2452
2453 v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
2454 {
2455     QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2456
2457     if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
2458         const quint32 w = r->image.width();
2459         const quint32 row = (index / 4) / w;
2460         const quint32 col = (index / 4) % w;
2461         const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
2462         pixel += col;
2463         switch (index % 4) {
2464         case 0:
2465             return v8::Integer::New(qRed(*pixel));
2466         case 1:
2467             return v8::Integer::New(qGreen(*pixel));
2468         case 2:
2469             return v8::Integer::New(qBlue(*pixel));
2470         case 3:
2471             return v8::Integer::New(qAlpha(*pixel));
2472         }
2473     }
2474     return v8::Undefined();
2475 }
2476
2477 v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
2478 {
2479     QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
2480
2481     const int v = value->Uint32Value();
2482     if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4) && v > 0 && v <= 255) {
2483         const quint32 w = r->image.width();
2484         const quint32 row = (index / 4) / w;
2485         const quint32 col = (index / 4) % w;
2486
2487         QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
2488         pixel += col;
2489         switch (index % 4) {
2490         case 0:
2491             *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
2492             break;
2493         case 1:
2494             *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
2495             break;
2496         case 2:
2497             *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
2498             break;
2499         case 3:
2500             *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
2501             break;
2502         }
2503     }
2504     return v8::Undefined();
2505 }
2506 /*!
2507   \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
2508    Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
2509   */
2510 /*!
2511   \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
2512    Creates a CanvasImageData object with the same dimensions as the argument.
2513   */
2514 /*!
2515   \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
2516    Creates a CanvasImageData object with the given image loaded from \a imageUrl.
2517    Note:The \a imageUrl must be already loaded before this function call, if not, an empty
2518    CanvasImageData obect will be returned.
2519
2520    \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
2521   */
2522 static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
2523 {
2524     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2525     CHECK_CONTEXT(r)
2526
2527     QV8Engine *engine = V8ENGINE();
2528
2529     if (args.Length() == 1) {
2530         if (args[0]->IsObject()) {
2531             v8::Local<v8::Object> imgData = args[0]->ToObject();
2532             QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
2533             if (pa) {
2534                 qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
2535                 qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
2536                 return qt_create_image_data(w, h, engine, QImage());
2537             }
2538         } else if (args[0]->IsString()) {
2539             QImage image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2540             return qt_create_image_data(image.width(), image.height(), engine, image);
2541         }
2542     } else if (args.Length() == 2) {
2543         qreal w = args[0]->NumberValue();
2544         qreal h = args[1]->NumberValue();
2545
2546         if (!qIsFinite(w) || !qIsFinite(h))
2547             V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
2548
2549         if (w > 0 && h > 0)
2550             return qt_create_image_data(w, h, engine, QImage());
2551         else
2552             V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createImageData(): invalid arguments");
2553     }
2554     return v8::Undefined();
2555 }
2556
2557 /*!
2558   \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
2559   Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
2560   */
2561 static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
2562 {
2563     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2564     CHECK_CONTEXT(r)
2565
2566     QV8Engine *engine = V8ENGINE();
2567     if (args.Length() == 4) {
2568         qreal x = args[0]->NumberValue();
2569         qreal y = args[1]->NumberValue();
2570         qreal w = args[2]->NumberValue();
2571         qreal h = args[3]->NumberValue();
2572         if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(w))
2573             V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
2574
2575         if (w <= 0 || h <= 0)
2576             V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
2577
2578         QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
2579         v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
2580
2581         return imageData;
2582     }
2583     return v8::Null();
2584 }
2585
2586 /*!
2587   \qmlmethod object QtQuick2::Context2D::putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
2588   Paints the data from the given ImageData object onto the canvas. If a dirty rectangle (\a dirtyX, \a dirtyY, \a dirtyWidth, \a dirtyHeight) is provided, only the pixels from that rectangle are painted.
2589   */
2590 static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
2591 {
2592     QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2593     CHECK_CONTEXT(r)
2594     if (args.Length() != 3 && args.Length() != 7)
2595         return v8::Undefined();
2596
2597     if (args[0]->IsNull() || !args[0]->IsObject()) {
2598         V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
2599     }
2600     qreal dx = args[1]->NumberValue();
2601     qreal dy = args[2]->NumberValue();
2602     qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
2603
2604     if (!qIsFinite(dx) || !qIsFinite(dy))
2605         V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2606
2607     v8::Local<v8::Object> imageData = args[0]->ToObject();
2608     QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
2609     if (pixelArray) {
2610         w = imageData->Get(v8::String::New("width"))->NumberValue();
2611         h = imageData->Get(v8::String::New("height"))->NumberValue();
2612
2613         if (args.Length() == 7) {
2614             dirtyX = args[3]->NumberValue();
2615             dirtyY = args[4]->NumberValue();
2616             dirtyWidth = args[5]->NumberValue();
2617             dirtyHeight = args[6]->NumberValue();
2618
2619             if (!qIsFinite(dirtyX) || !qIsFinite(dirtyY) || !qIsFinite(dirtyWidth) || !qIsFinite(dirtyHeight))
2620                 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2621
2622
2623             if (dirtyWidth < 0) {
2624                 dirtyX = dirtyX+dirtyWidth;
2625                 dirtyWidth = -dirtyWidth;
2626             }
2627
2628             if (dirtyHeight < 0) {
2629                 dirtyY = dirtyY+dirtyHeight;
2630                 dirtyHeight = -dirtyHeight;
2631             }
2632
2633             if (dirtyX < 0) {
2634                 dirtyWidth = dirtyWidth+dirtyX;
2635                 dirtyX = 0;
2636             }
2637
2638             if (dirtyY < 0) {
2639                 dirtyHeight = dirtyHeight+dirtyY;
2640                 dirtyY = 0;
2641             }
2642
2643             if (dirtyX+dirtyWidth > w) {
2644                 dirtyWidth = w - dirtyX;
2645             }
2646
2647             if (dirtyY+dirtyHeight > h) {
2648                 dirtyHeight = h - dirtyY;
2649             }
2650
2651             if (dirtyWidth <=0 || dirtyHeight <= 0)
2652                 return args.This();
2653         } else {
2654             dirtyX = 0;
2655             dirtyY = 0;
2656             dirtyWidth = w;
2657             dirtyHeight = h;
2658         }
2659
2660         QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2661         r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
2662     }
2663     return args.This();
2664 }
2665
2666 /*!
2667   \qmlclass QtQuick2::CanvasGradient
2668     \inqmlmodule QtQuick 2
2669     \since QtQuick 2.0
2670     \brief The Context2D opaque CanvasGradient interface.
2671   */
2672
2673 /*!
2674   \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
2675   Adds a color stop with the given color to the gradient at the given offset.
2676   0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
2677
2678   For example:
2679   \code
2680   var gradient = ctx.createLinearGradient(0, 0, 100, 100);
2681   gradient.addColorStop(0.3, Qt.rgba(1, 0, 0, 1));
2682   gradient.addColorStop(0.7, 'rgba(0, 255, 255, 1');
2683   \endcode
2684   */
2685 static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
2686 {
2687     QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
2688     if (!style)
2689         V8THROW_ERROR("Not a CanvasGradient object");
2690
2691     QV8Engine *engine = V8ENGINE();
2692
2693     if (args.Length() == 2) {
2694
2695         if (!style->brush.gradient())
2696             V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
2697         QGradient gradient = *(style->brush.gradient());
2698         qreal pos = args[0]->NumberValue();
2699         QColor color;
2700
2701         if (args[1]->IsObject()) {
2702             color = engine->toVariant(args[1], qMetaTypeId<QColor>()).value<QColor>();
2703         } else {
2704             color = qt_color_from_string(args[1]);
2705         }
2706         if (pos < 0.0 || pos > 1.0 || !qIsFinite(pos)) {
2707             V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
2708         }
2709
2710         if (color.isValid()) {
2711             gradient.setColorAt(pos, color);
2712         } else {
2713             V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string");
2714         }
2715         style->brush = gradient;
2716     }
2717
2718     return args.This();
2719 }
2720
2721 void QQuickContext2D::scale(qreal x,  qreal y)
2722 {
2723     if (!state.invertibleCTM)
2724         return;
2725
2726     if (!qIsFinite(x) || !qIsFinite(y))
2727         return;
2728
2729     QTransform newTransform = state.matrix;
2730     newTransform.scale(x, y);
2731
2732     if (!newTransform.isInvertible()) {
2733         state.invertibleCTM = false;
2734         return;
2735     }
2736
2737     state.matrix = newTransform;
2738     buffer()->updateMatrix(state.matrix);
2739     m_path = QTransform().scale(1.0 / x, 1.0 / y).map(m_path);
2740 }
2741
2742 void QQuickContext2D::rotate(qreal angle)
2743 {
2744     if (!state.invertibleCTM)
2745         return;
2746
2747     if (!qIsFinite(angle))
2748         return;
2749
2750     QTransform newTransform =state.matrix;
2751     newTransform.rotate(DEGREES(angle));
2752
2753     if (!newTransform.isInvertible()) {
2754         state.invertibleCTM = false;
2755         return;
2756     }
2757
2758     state.matrix = newTransform;
2759     buffer()->updateMatrix(state.matrix);
2760     m_path = QTransform().rotate(-DEGREES(angle)).map(m_path);
2761 }
2762
2763 void QQuickContext2D::shear(qreal h, qreal v)
2764 {
2765     if (!state.invertibleCTM)
2766         return;
2767
2768     if (!qIsFinite(h) || !qIsFinite(v))
2769         return ;
2770
2771     QTransform newTransform = state.matrix;
2772     newTransform.shear(h, v);
2773
2774     if (!newTransform.isInvertible()) {
2775         state.invertibleCTM = false;
2776         return;
2777     }
2778
2779     state.matrix = newTransform;
2780     buffer()->updateMatrix(state.matrix);
2781     m_path = QTransform().shear(-h, -v).map(m_path);
2782 }
2783
2784 void QQuickContext2D::translate(qreal x, qreal y)
2785 {
2786     if (!state.invertibleCTM)
2787         return;
2788
2789     if (!qIsFinite(x) || !qIsFinite(y))
2790         return ;
2791
2792     QTransform newTransform = state.matrix;
2793     newTransform.translate(x, y);
2794
2795     if (!newTransform.isInvertible()) {
2796         state.invertibleCTM = false;
2797         return;
2798     }
2799
2800     state.matrix = newTransform;
2801     buffer()->updateMatrix(state.matrix);
2802     m_path = QTransform().translate(-x, -y).map(m_path);
2803 }
2804
2805 void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
2806 {
2807     if (!state.invertibleCTM)
2808         return;
2809
2810     if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
2811         return;
2812
2813     QTransform transform(a, b, c, d, e, f);
2814     QTransform newTransform = state.matrix * transform;
2815
2816     if (!newTransform.isInvertible()) {
2817         state.invertibleCTM = false;
2818         return;
2819     }
2820     state.matrix = newTransform;
2821     buffer()->updateMatrix(state.matrix);
2822     m_path = transform.inverted().map(m_path);
2823 }
2824
2825 void QQuickContext2D::setTransform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
2826 {
2827     if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
2828         return;
2829
2830     QTransform ctm = state.matrix;
2831     if (!ctm.isInvertible())
2832         return;
2833
2834     state.matrix = ctm.inverted() * state.matrix;
2835     m_path = ctm.map(m_path);
2836     state.invertibleCTM = true;
2837     transform(a, b, c, d, e, f);
2838 }
2839
2840 void QQuickContext2D::fill()
2841 {
2842     if (!state.invertibleCTM)
2843         return;
2844
2845     if (!m_path.elementCount())
2846         return;
2847
2848     m_path.setFillRule(state.fillRule);
2849     buffer()->fill(m_path);
2850 }
2851
2852 void QQuickContext2D::clip()
2853 {
2854     if (!state.invertibleCTM)
2855         return;
2856
2857     QPainterPath clipPath = m_path;
2858     clipPath.closeSubpath();
2859     if (!state.clipPath.isEmpty())
2860         state.clipPath = clipPath.intersected(state.clipPath);
2861     else
2862         state.clipPath = clipPath;
2863     buffer()->clip(state.clipPath);
2864 }
2865
2866 void QQuickContext2D::stroke()
2867 {
2868     if (!state.invertibleCTM)
2869         return;
2870
2871     if (!m_path.elementCount())
2872         return;
2873
2874     buffer()->stroke(m_path);
2875 }
2876
2877 void QQuickContext2D::fillRect(qreal x, qreal y, qreal w, qreal h)
2878 {
2879     if (!state.invertibleCTM)
2880         return;
2881
2882     if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2883         return;
2884
2885     buffer()->fillRect(x, y, w, h);
2886 }
2887
2888 void QQuickContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
2889 {
2890     if (!state.invertibleCTM)
2891         return;
2892
2893     if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2894         return;
2895
2896     buffer()->strokeRect(x, y, w, h);
2897 }
2898
2899 void QQuickContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
2900 {
2901     if (!state.invertibleCTM)
2902         return;
2903
2904     if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2905         return;
2906
2907     buffer()->clearRect(x, y, w, h);
2908 }
2909
2910 void QQuickContext2D::drawText(const QString& text, qreal x, qreal y, bool fill)
2911 {
2912     if (!state.invertibleCTM)
2913         return;
2914
2915     if (!qIsFinite(x) || !qIsFinite(y))
2916         return;
2917
2918     QPainterPath textPath = createTextGlyphs(x, y, text);
2919     if (fill)
2920         buffer()->fill(textPath);
2921     else
2922         buffer()->stroke(textPath);
2923 }
2924
2925
2926 void QQuickContext2D::beginPath()
2927 {
2928     if (!m_path.elementCount())
2929         return;
2930     m_path = QPainterPath();
2931 }
2932
2933 void QQuickContext2D::closePath()
2934 {
2935     if (!m_path.elementCount())
2936         return;
2937
2938     QRectF boundRect = m_path.boundingRect();
2939     if (boundRect.width() || boundRect.height())
2940         m_path.closeSubpath();
2941     //FIXME:QPainterPath set the current point to (0,0) after close subpath
2942     //should be the first point of the previous subpath
2943 }
2944
2945 void QQuickContext2D::moveTo( qreal x, qreal y)
2946 {
2947     if (!state.invertibleCTM)
2948         return;
2949
2950     //FIXME: moveTo should not close the previous subpath
2951     m_path.moveTo(QPointF(x, y));
2952 }
2953
2954 void QQuickContext2D::lineTo( qreal x, qreal y)
2955 {
2956     if (!state.invertibleCTM)
2957         return;
2958
2959     QPointF pt(x, y);
2960
2961     if (!m_path.elementCount())
2962         m_path.moveTo(pt);
2963     else if (m_path.currentPosition() != pt)
2964         m_path.lineTo(pt);
2965 }
2966
2967 void QQuickContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
2968                                            qreal x, qreal y)
2969 {
2970     if (!state.invertibleCTM)
2971         return;
2972
2973     if (!m_path.elementCount())
2974         m_path.moveTo(QPointF(cpx, cpy));
2975
2976     QPointF pt(x, y);
2977     if (m_path.currentPosition() != pt)
2978         m_path.quadTo(QPointF(cpx, cpy), pt);
2979 }
2980
2981 void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
2982                                         qreal cp2x, qreal cp2y,
2983                                         qreal x, qreal y)
2984 {
2985     if (!state.invertibleCTM)
2986         return;
2987
2988     if (!m_path.elementCount())
2989         m_path.moveTo(QPointF(cp1x, cp1y));
2990
2991     QPointF pt(x, y);
2992     if (m_path.currentPosition() != pt)
2993         m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y),  pt);
2994 }
2995
2996 void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
2997 {
2998     QPointF p0(m_path.currentPosition());
2999
3000     QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
3001     QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
3002     float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
3003     float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
3004
3005     double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
3006
3007     // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
3008     // We could have used areCollinear() here, but since we're reusing
3009     // the variables computed above later on we keep this logic.
3010     if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
3011         m_path.lineTo(p1);
3012         return;
3013     }
3014
3015     float tangent = radius / tan(acos(cos_phi) / 2);
3016     float factor_p1p0 = tangent / p1p0_length;
3017     QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
3018
3019     QPointF orth_p1p0(p1p0.y(), -p1p0.x());
3020     float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
3021     float factor_ra = radius / orth_p1p0_length;
3022
3023     // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
3024     double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
3025     if (cos_alpha < 0.f)
3026         orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3027
3028     QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
3029
3030     // calculate angles for addArc
3031     orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3032     float sa = acos(orth_p1p0.x() / orth_p1p0_length);
3033     if (orth_p1p0.y() < 0.f)
3034         sa = 2 * Q_PI - sa;
3035
3036     // anticlockwise logic
3037     bool anticlockwise = false;
3038
3039     float factor_p1p2 = tangent / p1p2_length;
3040     QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
3041     QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
3042     float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
3043     float ea = acos(orth_p1p2.x() / orth_p1p2_length);
3044     if (orth_p1p2.y() < 0)
3045         ea = 2 * Q_PI - ea;
3046     if ((sa > ea) && ((sa - ea) < Q_PI))
3047         anticlockwise = true;
3048     if ((sa < ea) && ((ea - sa) > Q_PI))
3049         anticlockwise = true;
3050
3051     arc(p.x(), p.y(), radius, sa, ea, anticlockwise);
3052 }
3053
3054 void QQuickContext2D::arcTo(qreal x1, qreal y1,
3055                                 qreal x2, qreal y2,
3056                                 qreal radius)
3057 {
3058     if (!state.invertibleCTM)
3059         return;
3060
3061     if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2) || !qIsFinite(radius))
3062         return;
3063
3064     QPointF st(x1, y1);
3065     QPointF end(x2, y2);
3066
3067     if (!m_path.elementCount())
3068         m_path.moveTo(st);
3069     else if (st == m_path.currentPosition() || st == end || !radius)
3070         lineTo(x1, y1);
3071     else
3072         addArcTo(st, end, radius);
3073  }
3074
3075 void QQuickContext2D::rect(qreal x, qreal y, qreal w, qreal h)
3076 {
3077     if (!state.invertibleCTM)
3078         return;
3079     if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
3080         return;
3081
3082     if (!w && !h) {
3083         m_path.moveTo(x, y);
3084         return;
3085     }
3086     m_path.addRect(x, y, w, h);
3087 }
3088
3089 void QQuickContext2D::roundedRect(qreal x, qreal y,
3090                                qreal w, qreal h,
3091                                qreal xr, qreal yr)
3092 {
3093     if (!state.invertibleCTM)
3094         return;
3095
3096     if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h) || !qIsFinite(xr) || !qIsFinite(yr))
3097         return;
3098
3099     if (!w && !h) {
3100         m_path.moveTo(x, y);
3101         return;
3102     }
3103     m_path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
3104 }
3105
3106 void QQuickContext2D::ellipse(qreal x, qreal y,
3107                            qreal w, qreal h)
3108 {
3109     if (!state.invertibleCTM)
3110         return;
3111
3112     if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
3113         return;
3114
3115     if (!w && !h) {
3116         m_path.moveTo(x, y);
3117         return;
3118     }
3119
3120     m_path.addEllipse(x, y, w, h);
3121 }
3122
3123 void QQuickContext2D::text(const QString& str, qreal x, qreal y)
3124 {
3125     if (!state.invertibleCTM)
3126         return;
3127
3128     QPainterPath path;
3129     path.addText(x, y, state.font, str);
3130     m_path.addPath(path);
3131 }
3132
3133 void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear, bool antiClockWise)
3134 {
3135     if (!state.invertibleCTM)
3136         return;
3137
3138     if (!qIsFinite(xc) || !qIsFinite(yc) || !qIsFinite(sar) || !qIsFinite(ear) || !qIsFinite(radius))
3139         return;
3140
3141     if (sar == ear)
3142         return;
3143
3144
3145     //### HACK
3146
3147     // In Qt we don't switch the coordinate system for degrees
3148     // and still use the 0,0 as bottom left for degrees so we need
3149     // to switch
3150     sar = -sar;
3151     ear = -ear;
3152     antiClockWise = !antiClockWise;
3153     //end hack
3154
3155     float sa = DEGREES(sar);
3156     float ea = DEGREES(ear);
3157
3158     double span = 0;
3159
3160     double xs     = xc - radius;
3161     double ys     = yc - radius;
3162     double width  = radius*2;
3163     double height = radius*2;
3164     if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
3165         // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
3166         // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
3167         // circumference of this circle.
3168         span = 360;
3169     else {
3170         if (!antiClockWise && (ea < sa)) {
3171             span += 360;
3172         } else if (antiClockWise && (sa < ea)) {
3173             span -= 360;
3174         }
3175         //### this is also due to switched coordinate system
3176         // we would end up with a 0 span instead of 360
3177         if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
3178               qFuzzyCompare(qAbs(span), 360))) {
3179             span   += ea - sa;
3180         }
3181     }
3182
3183     // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
3184     if (!m_path.elementCount())
3185         m_path.arcMoveTo(xs, ys, width, height, sa);
3186     else if (!radius) {
3187         m_path.lineTo(xc, yc);
3188         return;
3189     }
3190
3191     m_path.arcTo(xs, ys, width, height, sa, span);
3192 }
3193
3194 int baseLineOffset(QQuickContext2D::TextBaseLineType value, const QFontMetrics &metrics)
3195 {
3196     int offset = 0;
3197     switch (value) {
3198     case QQuickContext2D::Top:
3199         break;
3200     case QQuickContext2D::Alphabetic:
3201     case QQuickContext2D::Middle:
3202     case QQuickContext2D::Hanging:
3203         offset = metrics.ascent();
3204         break;
3205     case QQuickContext2D::Bottom:
3206         offset = metrics.height();
3207        break;
3208     }
3209     return offset;
3210 }
3211
3212 static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
3213 {
3214     int offset = 0;
3215     if (value == QQuickContext2D::Start)
3216         value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Left : QQuickContext2D::Right;
3217     else if (value == QQuickContext2D::End)
3218         value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Right: QQuickContext2D::Left;
3219     switch (value) {
3220     case QQuickContext2D::Center:
3221         offset = metrics.width(text)/2;
3222         break;
3223     case QQuickContext2D::Right:
3224         offset = metrics.width(text);
3225     case QQuickContext2D::Left:
3226     default:
3227         break;
3228     }
3229     return offset;
3230 }
3231
3232
3233 QImage QQuickContext2D::createImage(const QUrl& url)
3234 {
3235     return m_canvas->loadedImage(url);
3236 }
3237
3238 QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
3239 {
3240     const QFontMetrics metrics(state.font);
3241     int yoffset = baseLineOffset(static_cast<QQuickContext2D::TextBaseLineType>(state.textBaseline), metrics);
3242     int xoffset = textAlignOffset(static_cast<QQuickContext2D::TextAlignType>(state.textAlign), metrics, text);
3243
3244     QPainterPath textPath;
3245
3246     textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
3247     textPath = state.matrix.map(textPath);
3248     return textPath;
3249 }
3250
3251
3252 static inline bool areCollinear(const QPointF& a, const QPointF& b, const QPointF& c)
3253 {
3254     // Solved from comparing the slopes of a to b and b to c: (ay-by)/(ax-bx) == (cy-by)/(cx-bx)
3255     return qFuzzyCompare((c.y() - b.y()) * (a.x() - b.x()), (a.y() - b.y()) * (c.x() - b.x()));
3256 }
3257
3258 static inline bool withinRange(qreal p, qreal a, qreal b)
3259 {
3260     return (p >= a && p <= b) || (p >= b && p <= a);
3261 }
3262
3263 bool QQuickContext2D::isPointInPath(qreal x, qreal y) const
3264 {
3265     if (!state.invertibleCTM)
3266         return false;
3267
3268     if (!m_path.elementCount())
3269         return false;
3270
3271     if (!qIsFinite(x) || !qIsFinite(y))
3272         return false;
3273
3274     QPointF point(x, y);
3275     QTransform ctm = state.matrix;
3276     QPointF p = ctm.inverted().map(point);
3277     if (!qIsFinite(p.x()) || !qIsFinite(p.y()))
3278         return false;
3279
3280     const_cast<QQuickContext2D *>(this)->m_path.setFillRule(state.fillRule);
3281
3282     bool contains = m_path.contains(p);
3283
3284     if (!contains) {
3285         // check whether the point is on the border
3286         QPolygonF border = m_path.toFillPolygon();
3287
3288         QPointF p1 = border.at(0);
3289         QPointF p2;
3290
3291         for (int i = 1; i < border.size(); ++i) {
3292             p2 = border.at(i);
3293             if (areCollinear(p, p1, p2)
3294                     // Once we know that the points are collinear we
3295                     // only need to check one of the coordinates
3296                     && (qAbs(p2.x() - p1.x()) > qAbs(p2.y() - p1.y()) ?
3297                         withinRange(p.x(), p1.x(), p2.x()) :
3298                         withinRange(p.y(), p1.y(), p2.y()))) {
3299                 return true;
3300             }
3301             p1 = p2;
3302         }
3303     }
3304     return contains;
3305 }
3306
3307 QQuickContext2D::QQuickContext2D(QObject *parent)
3308     : QQuickCanvasContext(parent)
3309     , m_buffer(new QQuickContext2DCommandBuffer)
3310     , m_v8engine(0)
3311 {
3312 }
3313
3314 QQuickContext2D::~QQuickContext2D()
3315 {
3316     delete m_buffer;
3317 }
3318
3319 v8::Handle<v8::Object> QQuickContext2D::v8value() const
3320 {
3321     return m_v8value;
3322 }
3323
3324 QStringList QQuickContext2D::contextNames() const
3325 {
3326     return QStringList() << QLatin1String("2d");
3327 }
3328
3329 void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args)
3330 {
3331     Q_UNUSED(args);
3332
3333     m_canvas = canvasItem;
3334     m_renderTarget = canvasItem->renderTarget();
3335
3336     // For the FBO target we only (currently) support Cooperative
3337     if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
3338         canvasItem->setRenderStrategy(QQuickCanvasItem::Cooperative);
3339     }
3340
3341     m_renderStrategy = canvasItem->renderStrategy();
3342
3343     switch (m_renderTarget) {
3344     case QQuickCanvasItem::Image:
3345         m_texture = new QQuickContext2DImageTexture(m_renderStrategy == QQuickCanvasItem::Threaded);
3346         break;
3347     case QQuickCanvasItem::FramebufferObject:
3348         m_texture = new QQuickContext2DFBOTexture;
3349         break;
3350     }
3351
3352     m_texture->setItem(canvasItem);
3353     m_texture->setCanvasWindow(canvasItem->canvasWindow().toRect());
3354     m_texture->setTileSize(canvasItem->tileSize());
3355     m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
3356     m_texture->setSmooth(canvasItem->smooth());
3357
3358     connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
3359
3360     reset();
3361 }
3362
3363 void QQuickContext2D::prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth)
3364 {
3365     m_texture->canvasChanged(canvasSize, tileSize, canvasWindow, dirtyRect, smooth);
3366 }
3367
3368 void QQuickContext2D::flush()
3369 {
3370     if (!m_buffer->isEmpty()) {
3371         QMutexLocker lock(&m_bufferMutex);
3372         m_bufferQueue.enqueue(m_buffer);
3373         m_buffer = new QQuickContext2DCommandBuffer;
3374     } else
3375         return;
3376
3377     switch (m_renderStrategy) {
3378     case QQuickCanvasItem::Immediate:
3379         // Cause the texture to consume paint commands immediately
3380         m_texture->paint();
3381         break;
3382     case QQuickCanvasItem::Threaded:
3383         // wake up thread to consume paint commands
3384         m_texture->paint();
3385         break;
3386     case QQuickCanvasItem::Cooperative:
3387         // NOTE: On SG Thread
3388         m_texture->paint();
3389         break;
3390     }
3391 }
3392
3393 QSGDynamicTexture *QQuickContext2D::texture() const
3394 {
3395     return m_texture;
3396 }
3397
3398 QImage QQuickContext2D::toImage(const QRectF& bounds)
3399 {
3400     switch (m_renderStrategy) {
3401     case QQuickCanvasItem::Immediate:
3402     case QQuickCanvasItem::Threaded:
3403         flush();
3404         break;
3405     case QQuickCanvasItem::Cooperative:
3406         break;
3407     }
3408
3409     return m_texture->toImage(bounds);
3410 }
3411
3412
3413 QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
3414 {
3415     v8::HandleScope handle_scope;
3416     v8::Context::Scope scope(engine->context());
3417
3418     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
3419     ft->InstanceTemplate()->SetHasExternalResource(true);
3420     ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine));
3421     ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine));
3422     ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine));
3423     ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine));
3424     ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine));
3425     ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine));
3426     ft->PrototypeTemplate()->Set(v8::String::New("resetTransform"), V8FUNCTION(ctx2d_resetTransform, engine));
3427     ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine));
3428     ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine));
3429     ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine));
3430     ft->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, engine));
3431     ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine));
3432     ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine));
3433     ft->InstanceTemplate()->SetAccessor(v8::String::New("fillRule"), ctx2d_fillRule, ctx2d_fillRule_set, v8::External::Wrap(engine));
3434     ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine));
3435     ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
3436     ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
3437     ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
3438     ft->PrototypeTemplate()->Set(v8::String::New("createConicalGradient"), V8FUNCTION(ctx2d_createConicalGradient, engine));
3439     ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
3440     ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
3441     ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
3442     ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine));
3443     ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine));
3444     ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine));
3445     ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine));
3446     ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine));
3447     ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine));
3448     ft->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_set, v8::External::Wrap(engine));
3449     ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine));
3450     ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine));
3451     ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine));
3452     ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine));
3453     ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine));
3454     ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine));
3455     ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine));
3456     ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine));
3457     ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine));
3458     ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine));
3459     ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine));
3460     ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine));
3461     ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine));
3462     ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine));
3463     ft->PrototypeTemplate()->Set(v8::String::New("roundedRect"), V8FUNCTION(ctx2d_roundedRect, engine));
3464     ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
3465     ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine));
3466     ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine));
3467     ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine));
3468     ft->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
3469     ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
3470     ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, engine));
3471     ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine));
3472     ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine));
3473     ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine));
3474     ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine));
3475     ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine));
3476     ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine));
3477     ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine));
3478     ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine));
3479     ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine));
3480     ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine));
3481
3482     constructorContext = qPersistentNew(ft->GetFunction());
3483
3484     v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
3485     ftGradient->InstanceTemplate()->SetHasExternalResource(true);
3486     ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
3487     constructorGradient = qPersistentNew(ftGradient->GetFunction());
3488
3489     v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
3490     ftPattern->InstanceTemplate()->SetHasExternalResource(true);
3491     constructorPattern = qPersistentNew(ftPattern->GetFunction());
3492
3493     v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
3494     ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
3495     ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
3496     ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
3497     constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
3498
3499     v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
3500     ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
3501     ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
3502     ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
3503     ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
3504     constructorImageData = qPersistentNew(ftImageData->GetFunction());
3505 }
3506
3507 QQuickContext2DEngineData::~QQuickContext2DEngineData()
3508 {
3509     qPersistentDispose(constructorContext);
3510     qPersistentDispose(constructorGradient);
3511     qPersistentDispose(constructorPattern);
3512     qPersistentDispose(constructorImageData);
3513     qPersistentDispose(constructorPixelArray);
3514 }
3515
3516 void QQuickContext2D::popState()
3517 {
3518     if (m_stateStack.isEmpty())
3519         return;
3520
3521     QQuickContext2D::State newState = m_stateStack.pop();
3522
3523     if (state.matrix != newState.matrix)
3524         buffer()->updateMatrix(newState.matrix);
3525
3526     if (newState.globalAlpha != state.globalAlpha)
3527         buffer()->setGlobalAlpha(newState.globalAlpha);
3528
3529     if (newState.globalCompositeOperation != state.globalCompositeOperation)
3530         buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
3531
3532     if (newState.fillStyle != state.fillStyle)
3533         buffer()->setFillStyle(newState.fillStyle);
3534
3535     if (newState.strokeStyle != state.strokeStyle)
3536         buffer()->setStrokeStyle(newState.strokeStyle);
3537
3538     if (newState.lineWidth != state.lineWidth)
3539         buffer()->setLineWidth(newState.lineWidth);
3540
3541     if (newState.lineCap != state.lineCap)
3542         buffer()->setLineCap(newState.lineCap);
3543
3544     if (newState.lineJoin != state.lineJoin)
3545         buffer()->setLineJoin(newState.lineJoin);
3546
3547     if (newState.miterLimit != state.miterLimit)
3548         buffer()->setMiterLimit(newState.miterLimit);
3549
3550     if (newState.clipPath != state.clipPath) {
3551         buffer()->clip(newState.clipPath);
3552     }
3553
3554     if (newState.shadowBlur != state.shadowBlur)
3555         buffer()->setShadowBlur(newState.shadowBlur);
3556
3557     if (newState.shadowColor != state.shadowColor)
3558         buffer()->setShadowColor(newState.shadowColor);
3559
3560     if (newState.shadowOffsetX != state.shadowOffsetX)
3561         buffer()->setShadowOffsetX(newState.shadowOffsetX);
3562
3563     if (newState.shadowOffsetY != state.shadowOffsetY)
3564         buffer()->setShadowOffsetY(newState.shadowOffsetY);
3565     m_path = state.matrix.map(m_path);
3566     state = newState;
3567     m_path = state.matrix.inverted().map(m_path);
3568 }
3569 void QQuickContext2D::pushState()
3570 {
3571     m_stateStack.push(state);
3572 }
3573
3574 void QQuickContext2D::reset()
3575 {
3576     QQuickContext2D::State newState;
3577     newState.matrix = QTransform();
3578
3579     m_path = QPainterPath();
3580
3581     QPainterPath defaultClipPath;
3582
3583     QRect r(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
3584     r = r.united(m_canvas->canvasWindow().toRect());
3585     defaultClipPath.addRect(r);
3586     newState.clipPath = defaultClipPath;
3587     newState.clipPath.setFillRule(Qt::WindingFill);
3588
3589     newState.strokeStyle = QColor("#000000");
3590     newState.fillStyle = QColor("#000000");
3591     newState.fillPatternRepeatX = false;
3592     newState.fillPatternRepeatY = false;
3593     newState.strokePatternRepeatX = false;
3594     newState.strokePatternRepeatY = false;
3595     newState.invertibleCTM = true;
3596     newState.fillRule = Qt::WindingFill;
3597     newState.globalAlpha = 1.0;
3598     newState.lineWidth = 1;
3599     newState.lineCap = Qt::FlatCap;
3600     newState.lineJoin = Qt::MiterJoin;
3601     newState.miterLimit = 10;
3602     newState.shadowOffsetX = 0;
3603     newState.shadowOffsetY = 0;
3604     newState.shadowBlur = 0;
3605     newState.shadowColor = qRgba(0, 0, 0, 0);
3606     newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
3607     newState.font = QFont(QLatin1String("sans-serif"), 10);
3608     newState.textAlign = QQuickContext2D::Start;
3609     newState.textBaseline = QQuickContext2D::Alphabetic;
3610
3611     m_stateStack.clear();
3612     m_stateStack.push(newState);
3613     popState();
3614     m_buffer->clearRect(0, 0, m_canvas->width(), m_canvas->height());
3615 }
3616
3617 void QQuickContext2D::setV8Engine(QV8Engine *engine)
3618 {
3619     v8::HandleScope handle_scope;
3620     v8::Context::Scope scope(engine->context());
3621
3622     if (m_v8engine != engine) {
3623         m_v8engine = engine;
3624
3625         qPersistentDispose(m_v8value);
3626
3627         if (m_v8engine == 0)
3628             return;
3629
3630         QQuickContext2DEngineData *ed = engineData(engine);
3631         m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
3632         QV8Context2DResource *r = new QV8Context2DResource(engine);
3633         r->context = this;
3634         m_v8value->SetExternalResource(r);
3635     }
3636 }
3637
3638 QQuickContext2DCommandBuffer* QQuickContext2D::nextBuffer()
3639 {
3640     QMutexLocker lock(&m_bufferMutex);
3641     return m_bufferQueue.isEmpty() ? 0 : m_bufferQueue.dequeue();
3642 }
3643
3644 QT_END_NAMESPACE