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