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