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