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