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