1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickcontext2d_p.h"
43 #include "qquickcontext2dcommandbuffer_p.h"
44 #include "qquickcanvasitem_p.h"
45 #include <private/qquickcontext2dtexture_p.h>
46 #include <private/qquickitem_p.h>
47 #include <QtQuick/private/qquickshadereffectsource_p.h>
48 #include <QtGui/qopenglframebufferobject.h>
50 #include <QtCore/qdebug.h>
51 #include <QtQuick/private/qsgcontext_p.h>
52 #include <private/qdeclarativesvgparser_p.h>
53 #include <private/qdeclarativepath_p.h>
55 #include <private/qquickimage_p_p.h>
57 #include <QtGui/qguiapplication.h>
58 #include <qdeclarativeinfo.h>
59 #include <QtCore/qmath.h>
60 #include <private/qv8engine_p.h>
62 #include <qdeclarativeengine.h>
63 #include <private/qv8domerrors_p.h>
64 #include <QtCore/qnumeric.h>
68 \qmlclass Context2D QQuickContext2D
69 \inqmlmodule QtQuick 2
71 \brief The Context2D API allows you to draw 2d graphic shapes on the \c
74 The Context2D object can be created by \c Canvas item's \c getContext()
80 var ctx = canvas.getContext('2d');
85 The Context2D API implements the same \l
86 {http://www.w3.org/TR/2dcontext}{W3C Canvas 2D Context API standard} with
87 some enhanced features.
89 The Context2D API provides the rendering \bold{context} which defines the
90 methods and attributes needed to draw on the \c Canvas item. The following
91 assigns the canvas rendering context to a \c{context} variable:
93 var context = mycanvas.getContext("2d")
96 The Context2D API renders the canvas as a coordinate system whose origin
97 (0,0) is at the top left corner, as shown in the figure below. Coordinates
98 increase along the \c{x} axis from left to right and along the \c{y} axis
99 from top to bottom of the canvas.
100 \image qml-item-canvas-context.gif
103 QLockedCommandBuffer::QLockedCommandBuffer(QQuickContext2DCommandBuffer *b)
106 m_buffer->lockQueue();
109 QLockedCommandBuffer::~QLockedCommandBuffer()
111 m_buffer->unlockQueue();
114 QQuickContext2DCommandBuffer* QLockedCommandBuffer::operator->() const
120 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
122 static const double Q_PI = 3.14159265358979323846; // pi
124 #define DEGREES(t) ((t) * 180.0 / Q_PI)
126 #define CHECK_CONTEXT(r) if (!r || !r->context || !r->context->bufferValid()) \
127 V8THROW_ERROR("Not a Context2D object");
129 #define CHECK_CONTEXT_SETTER(r) if (!r || !r->context || !r->context->bufferValid()) \
130 V8THROW_ERROR_SETTER("Not a Context2D object");
131 #define qClamp(val, min, max) qMin(qMax(val, min), max)
132 #define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
133 QColor qt_color_from_string(v8::Local<v8::Value> name)
135 v8::String::AsciiValue str(name);
138 int len = str.length();
139 //rgb/hsl color string has at least 7 characters
140 if (!p || len > 255 || len <= 7)
143 bool isRgb(false), isHsl(false), hasAlpha(false);
146 while (isspace(*p)) p++;
147 if (strncmp(p, "rgb", 3) == 0)
149 else if (strncmp(p, "hsl", 3) == 0)
154 p+=3; //skip "rgb" or "hsl"
155 hasAlpha = (*p == 'a') ? true : false;
159 if (hasAlpha) ++p; //skip "a"
161 int rh, gs, bl, alpha = 255;
164 while (isspace(*p)) p++;
165 rh = strtol(p, &p, 10);
167 rh = qRound(rh/100.0 * 255);
170 if (*p++ != ',') return QColor();
173 while (isspace(*p)) p++;
174 gs = strtol(p, &p, 10);
176 gs = qRound(gs/100.0 * 255);
179 if (*p++ != ',') return QColor();
182 while (isspace(*p)) p++;
183 bl = strtol(p, &p, 10);
185 bl = qRound(bl/100.0 * 255);
190 if (*p++!= ',') return QColor();
191 while (isspace(*p)) p++;
193 alpha = qRound(qstrtod(p, const_cast<const char **>(&p), &ok) * 255);
196 if (*p != ')') return QColor();
198 return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)));
200 return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255));
205 QFont qt_font_from_string(const QString& fontString) {
207 // ### this is simplified and incomplete
208 // ### TODO:get code from Qt webkit
209 QStringList tokens = fontString.split(QLatin1String(" "));
210 foreach (const QString &token, tokens) {
211 if (token == QLatin1String("italic"))
212 font.setItalic(true);
213 else if (token == QLatin1String("bold"))
215 else if (token.endsWith(QLatin1String("px"))) {
216 QString number = token;
217 number.remove(QLatin1String("px"));
218 //font.setPointSizeF(number.trimmed().toFloat());
219 font.setPixelSize(number.trimmed().toInt());
221 font.setFamily(token);
229 class QQuickContext2DEngineData : public QV8Engine::Deletable
232 QQuickContext2DEngineData(QV8Engine *engine);
233 ~QQuickContext2DEngineData();
235 v8::Persistent<v8::Function> constructorContext;
236 v8::Persistent<v8::Function> constructorGradient;
237 v8::Persistent<v8::Function> constructorPattern;
238 v8::Persistent<v8::Function> constructorPixelArray;
239 v8::Persistent<v8::Function> constructorImageData;
242 V8_DEFINE_EXTENSION(QQuickContext2DEngineData, engineData)
244 class QV8Context2DResource : public QV8ObjectResource
246 V8_RESOURCE_TYPE(Context2DType)
248 QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
249 QQuickContext2D* context;
252 class QV8Context2DStyleResource : public QV8ObjectResource
254 V8_RESOURCE_TYPE(Context2DStyleType)
256 QV8Context2DStyleResource(QV8Engine *e)
257 : QV8ObjectResource(e)
258 , patternRepeatX(false)
259 , patternRepeatY(false)
262 bool patternRepeatX:1;
263 bool patternRepeatY:1;
266 class QV8Context2DPixelArrayResource : public QV8ObjectResource
268 V8_RESOURCE_TYPE(Context2DPixelArrayType)
270 QV8Context2DPixelArrayResource(QV8Engine *e) : QV8ObjectResource(e) {}
275 QImage qt_image_convolute_filter(const QImage& src, const QVector<qreal>& weights, int radius = 0)
277 int sides = radius ? radius : qRound(qSqrt(weights.size()));
278 int half = qFloor(sides/2);
280 QImage dst = QImage(src.size(), src.format());
282 int h = src.height();
283 for (int y = 0; y < dst.height(); ++y) {
284 QRgb *dr = (QRgb*)dst.scanLine(y);
285 for (int x = 0; x < dst.width(); ++x) {
286 unsigned char* dRgb = ((unsigned char*)&dr[x]);
287 unsigned char red=0, green=0, blue=0, alpha=0;
291 for (int cy=0; cy<sides; cy++) {
292 for (int cx=0; cx<sides; cx++) {
293 int scy = sy + cy - half;
294 int scx = sx + cx - half;
295 if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
296 const QRgb *sr = (const QRgb*)(src.constScanLine(scy));
297 const unsigned char* sRgb = ((const unsigned char*)&sr[scx]);
298 qreal wt = radius ? weights[0] : weights[cy*sides+cx];
300 green += sRgb[1] * wt;
301 blue += sRgb[2] * wt;
302 alpha += sRgb[3] * wt;
315 void qt_image_boxblur(QImage& image, int radius, bool quality)
317 int passes = quality? 3: 1;
318 for (int i=0; i < passes; i++) {
319 image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0/(radius * radius * 1.0), radius);
323 static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
325 if (compositeOperator == QLatin1String("source-over")) {
326 return QPainter::CompositionMode_SourceOver;
327 } else if (compositeOperator == QLatin1String("source-out")) {
328 return QPainter::CompositionMode_SourceOut;
329 } else if (compositeOperator == QLatin1String("source-in")) {
330 return QPainter::CompositionMode_SourceIn;
331 } else if (compositeOperator == QLatin1String("source-atop")) {
332 return QPainter::CompositionMode_SourceAtop;
333 } else if (compositeOperator == QLatin1String("destination-atop")) {
334 return QPainter::CompositionMode_DestinationAtop;
335 } else if (compositeOperator == QLatin1String("destination-in")) {
336 return QPainter::CompositionMode_DestinationIn;
337 } else if (compositeOperator == QLatin1String("destination-out")) {
338 return QPainter::CompositionMode_DestinationOut;
339 } else if (compositeOperator == QLatin1String("destination-over")) {
340 return QPainter::CompositionMode_DestinationOver;
341 } else if (compositeOperator == QLatin1String("lighter")) {
342 return QPainter::CompositionMode_Lighten;
343 } else if (compositeOperator == QLatin1String("copy")) {
344 return QPainter::CompositionMode_Source;
345 } else if (compositeOperator == QLatin1String("xor")) {
346 return QPainter::CompositionMode_Xor;
347 } else if (compositeOperator == QLatin1String("qt-clear")) {
348 return QPainter::CompositionMode_Clear;
349 } else if (compositeOperator == QLatin1String("qt-destination")) {
350 return QPainter::CompositionMode_Destination;
351 } else if (compositeOperator == QLatin1String("qt-multiply")) {
352 return QPainter::CompositionMode_Multiply;
353 } else if (compositeOperator == QLatin1String("qt-screen")) {
354 return QPainter::CompositionMode_Screen;
355 } else if (compositeOperator == QLatin1String("qt-overlay")) {
356 return QPainter::CompositionMode_Overlay;
357 } else if (compositeOperator == QLatin1String("qt-darken")) {
358 return QPainter::CompositionMode_Darken;
359 } else if (compositeOperator == QLatin1String("qt-lighten")) {
360 return QPainter::CompositionMode_Lighten;
361 } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
362 return QPainter::CompositionMode_ColorDodge;
363 } else if (compositeOperator == QLatin1String("qt-color-burn")) {
364 return QPainter::CompositionMode_ColorBurn;
365 } else if (compositeOperator == QLatin1String("qt-hard-light")) {
366 return QPainter::CompositionMode_HardLight;
367 } else if (compositeOperator == QLatin1String("qt-soft-light")) {
368 return QPainter::CompositionMode_SoftLight;
369 } else if (compositeOperator == QLatin1String("qt-difference")) {
370 return QPainter::CompositionMode_Difference;
371 } else if (compositeOperator == QLatin1String("qt-exclusion")) {
372 return QPainter::CompositionMode_Exclusion;
374 return QPainter::CompositionMode_SourceOver;
377 static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
380 case QPainter::CompositionMode_SourceOver:
381 return QLatin1String("source-over");
382 case QPainter::CompositionMode_DestinationOver:
383 return QLatin1String("destination-over");
384 case QPainter::CompositionMode_Clear:
385 return QLatin1String("qt-clear");
386 case QPainter::CompositionMode_Source:
387 return QLatin1String("copy");
388 case QPainter::CompositionMode_Destination:
389 return QLatin1String("qt-destination");
390 case QPainter::CompositionMode_SourceIn:
391 return QLatin1String("source-in");
392 case QPainter::CompositionMode_DestinationIn:
393 return QLatin1String("destination-in");
394 case QPainter::CompositionMode_SourceOut:
395 return QLatin1String("source-out");
396 case QPainter::CompositionMode_DestinationOut:
397 return QLatin1String("destination-out");
398 case QPainter::CompositionMode_SourceAtop:
399 return QLatin1String("source-atop");
400 case QPainter::CompositionMode_DestinationAtop:
401 return QLatin1String("destination-atop");
402 case QPainter::CompositionMode_Xor:
403 return QLatin1String("xor");
404 case QPainter::CompositionMode_Plus:
405 return QLatin1String("plus");
406 case QPainter::CompositionMode_Multiply:
407 return QLatin1String("qt-multiply");
408 case QPainter::CompositionMode_Screen:
409 return QLatin1String("qt-screen");
410 case QPainter::CompositionMode_Overlay:
411 return QLatin1String("qt-overlay");
412 case QPainter::CompositionMode_Darken:
413 return QLatin1String("qt-darken");
414 case QPainter::CompositionMode_Lighten:
415 return QLatin1String("lighter");
416 case QPainter::CompositionMode_ColorDodge:
417 return QLatin1String("qt-color-dodge");
418 case QPainter::CompositionMode_ColorBurn:
419 return QLatin1String("qt-color-burn");
420 case QPainter::CompositionMode_HardLight:
421 return QLatin1String("qt-hard-light");
422 case QPainter::CompositionMode_SoftLight:
423 return QLatin1String("qt-soft-light");
424 case QPainter::CompositionMode_Difference:
425 return QLatin1String("qt-difference");
426 case QPainter::CompositionMode_Exclusion:
427 return QLatin1String("qt-exclusion");
435 static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
437 QQuickContext2DEngineData *ed = engineData(engine);
438 v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
439 QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
440 if (image.isNull()) {
441 r->image = QImage(w, h, QImage::Format_ARGB32);
442 r->image.fill(0x00000000);
444 Q_ASSERT(image.width() == w && image.height() == h);
445 r->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
447 v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
448 pixelData->SetExternalResource(r);
450 imageData->SetInternalField(0, pixelData);
454 //static script functions
457 \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
458 Holds the canvas item that the context paints on.
460 This property is read only.
462 static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
464 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
468 QV8Engine *engine = V8ENGINE_ACCESSOR();
470 return engine->newQObject(r->context->canvas());
474 \qmlmethod object QtQuick2::Context2D::restore()
475 Pops the top state on the stack, restoring the context to that state.
477 \sa QtQuick2::Context2D::save()
479 static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
481 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
484 r->context->popState();
489 \qmlmethod object QtQuick2::Context2D::reset()
490 Resets the context state and properties to the default values.
492 static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
494 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
498 r->context->m_path = QPainterPath();
499 r->context->m_path.setFillRule(Qt::WindingFill);
505 \qmlmethod object QtQuick2::Context2D::save()
506 Pushes the current state onto the state stack.
508 Before changing any state attributes, you should save the current state
509 for future reference. The context maintains a stack of drawing states.
510 Each state consists of the current transformation matrix, clipping region,
511 and values of the following attributes:
513 \o\a QtQuick2::Context2D::strokeStyle
514 \o\a QtQuick2::Context2D::fillStyle
515 \o\a QtQuick2::Context2D::fillRule
516 \o\a QtQuick2::Context2D::globalAlpha
517 \o\a QtQuick2::Context2D::lineWidth
518 \o\a QtQuick2::Context2D::lineCap
519 \o\a QtQuick2::Context2D::lineJoin
520 \o\a QtQuick2::Context2D::miterLimit
521 \o\a QtQuick2::Context2D::shadowOffsetX
522 \o\a QtQuick2::Context2D::shadowOffsetY
523 \o\a QtQuick2::Context2D::shadowBlur
524 \o\a QtQuick2::Context2D::shadowColor
525 \o\a QtQuick2::Context2D::globalCompositeOperation
526 \o\a QtQuick2::Context2D::font
527 \o\a QtQuick2::Context2D::textAlign
528 \o\a QtQuick2::Context2D::textBaseline
531 The current path is NOT part of the drawing state. The path can be reset by
532 invoking the \a QtQuick2::Context2D::beginPath() method.
534 static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
536 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
539 r->context->pushState();
546 \qmlmethod object QtQuick2::Context2D::rotate(real angle)
547 Rotate the canvas around the current origin by \c angle in radians and clockwise direction.
549 ctx.rotate(Math.PI/2);
551 \image qml-item-canvas-rotate.png
553 The rotation transformation matrix is as follows:
555 \image qml-item-canvas-math-rotate.png
557 where the \c angle of rotation is in radians.
560 static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
562 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
565 if (args.Length() == 1) {
566 qreal angle = args[0]->NumberValue();
567 if (!qIsFinite(angle))
570 r->context->state.matrix.rotate(DEGREES(angle));
571 r->context->buffer()->updateMatrix(r->context->state.matrix);
578 \qmlmethod object QtQuick2::Context2D::scale(real x, real y)
579 Increases or decreases the size of each unit in the canvas grid by multiplying the scale factors
580 to the current tranform matrix.
581 Where \c x is the scale factor in the horizontal direction and \c y is the scale factor in the
583 The following code doubles the horizontal size of an object drawn on the canvas and half its
588 \image qml-item-canvas-scale.png
591 static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
593 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
597 if (args.Length() == 2) {
599 x = args[0]->NumberValue();
600 y = args[1]->NumberValue();
601 if (!qIsFinite(x) || !qIsFinite(y))
604 r->context->state.matrix.scale(x, y);
605 r->context->buffer()->updateMatrix(r->context->state.matrix);
612 \qmlmethod object QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
613 Changes the transformation matrix to the matrix given by the arguments as described below.
615 Modifying the transformation matrix directly enables you to perform scaling,
616 rotating, and translating transformations in a single step.
618 Each point on the canvas is multiplied by the matrix before anything is
619 drawn. The \l{HTML5 Canvas API} defines the transformation matrix as:
621 \image qml-item-canvas-math.png
624 \o \c{a} is the scale factor in the horizontal (x) direction
625 \image qml-item-canvas-scalex.png
626 \o \c{c} is the skew factor in the x direction
627 \image qml-item-canvas-canvas-skewx.png
628 \o \c{e} is the translation in the x direction
629 \image qml-item-canvas-canvas-translate.png
630 \o \c{b} is the skew factor in the y (vertical) direction
631 \image qml-item-canvas-canvas-skewy.png
632 \o \c{d} is the scale factor in the y direction
633 \image qml-item-canvas-canvas-scaley.png
634 \o \c{f} is the translation in the y direction
635 \image qml-item-canvas-canvas-translatey.png
636 \o the last row remains constant
638 The scale factors and skew factors are multiples; \c{e} and \c{f} are
639 coordinate space units, just like the units in the \a QtQuick2::Context2D::translate(x,y)
642 \sa QtQuick2::Context2D::transform()
644 static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
646 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
650 if (args.Length() == 6) {
651 qreal a = args[0]->NumberValue();
652 qreal b = args[1]->NumberValue();
653 qreal c = args[2]->NumberValue();
654 qreal d = args[3]->NumberValue();
655 qreal e = args[4]->NumberValue();
656 qreal f = args[5]->NumberValue();
666 r->context->state.matrix = QTransform(a, b, c, d, e, f);
667 r->context->buffer()->updateMatrix(r->context->state.matrix);
674 \qmlmethod object QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
675 This method is very similar to \a QtQuick2::Context2D::setTransform(), but instead of replacing the old
676 tranform matrix, this method applies the given tranform matrix to the current matrix by mulitplying to it.
678 The \a setTransform(a, b, c, d, e, f) method actually resets the current transform to the identity matrix,
679 and then invokes the transform(a, b, c, d, e, f) method with the same arguments.
681 \sa QtQuick2::Context2D::setTransform()
683 static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
685 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
689 if (args.Length() == 6) {
690 qreal a = args[0]->NumberValue();
691 qreal b = args[1]->NumberValue();
692 qreal c = args[2]->NumberValue();
693 qreal d = args[3]->NumberValue();
694 qreal e = args[4]->NumberValue();
695 qreal f = args[5]->NumberValue();
705 r->context->state.matrix *= QTransform(a, b, c, d, e, f);
706 r->context->buffer()->updateMatrix(r->context->state.matrix);
713 \qmlmethod object QtQuick2::Context2D::translate(real x, real y)
714 Translates the origin of the canvas to point (\c x, \c y).
716 \c x is the horizontal distance that the origin is translated, in coordinate space units,
717 \c y is the vertical distance that the origin is translated, in coordinate space units.
718 Translating the origin enables you to draw patterns of different objects on the canvas
719 without having to measure the coordinates manually for each shape.
721 static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
723 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
727 if (args.Length() == 2) {
728 qreal x = args[0]->NumberValue();
729 qreal y = args[1]->NumberValue();
731 if (!qIsFinite(x) || !qIsFinite(y))
734 r->context->state.matrix.translate(x, y);
735 r->context->buffer()->updateMatrix(r->context->state.matrix);
743 \qmlmethod object QtQuick2::Context2D::resetTransform()
744 Reset the transformation matrix to default value.
746 \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform(), QtQuick2::Context2D::reset()
748 static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
750 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
753 r->context->state.matrix = QTransform();
754 r->context->buffer()->updateMatrix(r->context->state.matrix);
761 \qmlmethod object QtQuick2::Context2D::shear(real sh, real sv )
762 Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
764 static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
766 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
769 if (args.Length() == 2) {
770 qreal sh = args[0]->NumberValue();
771 qreal sv = args[1]->NumberValue();
773 if (!qIsFinite(sh) || !qIsFinite(sv))
776 r->context->state.matrix.shear(sh, sv);
777 r->context->buffer()->updateMatrix(r->context->state.matrix);
784 \qmlproperty real QtQuick2::Context2D::globalAlpha
785 Holds the the current alpha value applied to rendering operations.
786 The value must be in the range from 0.0 (fully transparent) to 1.0 (fully opque).
787 The default value is 1.0.
789 static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
791 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
794 return v8::Number::New(r->context->state.globalAlpha);
797 static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
799 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
800 CHECK_CONTEXT_SETTER(r)
802 qreal globalAlpha = value->NumberValue();
804 if (!qIsFinite(globalAlpha))
807 if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
808 r->context->state.globalAlpha = globalAlpha;
809 r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
814 \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
815 Holds the the current the current composition operation, from the list below:
817 \o source-atop - A atop B. Display the source image wherever both images are opaque.
818 Display the destination image wherever the destination image is opaque but the source image is transparent.
819 Display transparency elsewhere.
820 \o source-in - A in B. Display the source image wherever both the source image and destination image are opaque.
821 Display transparency elsewhere.
822 \o source-out - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
823 Display transparency elsewhere.
824 \o source-over - (default) A over B. Display the source image wherever the source image is opaque.
825 Display the destination image elsewhere.
826 \o destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
827 \o destination-in - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
828 \o destination-out - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
829 \o destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
830 \o lighter - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
831 \o copy - A (B is ignored). Display the source image instead of the destination image.
832 \o xor - A xor B. Exclusive OR of the source image and destination image.
835 Additionally, this property also accepts the compositon modes listed in \a {QPainter::CompositionMode}. According to the W3C standard, these
836 extension composition modes are provided as "vendorName-operationName" syntax, for example: \c {QPainter::CompositionMode_Exclusion} is porvided as
839 static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
841 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
845 QV8Engine *engine = V8ENGINE_ACCESSOR();
847 return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
850 static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
852 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
853 CHECK_CONTEXT_SETTER(r)
855 QV8Engine *engine = V8ENGINE_ACCESSOR();
858 QString mode = engine->toString(value);
859 QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
860 if (cm == QPainter::CompositionMode_SourceOver && mode != QStringLiteral("source-over"))
863 if (cm != r->context->state.globalCompositeOperation) {
864 r->context->state.globalCompositeOperation = cm;
865 r->context->buffer()->setGlobalCompositeOperation(cm);
871 \qmlproperty variant QtQuick2::Context2D::fillStyle
872 Holds the current style used for filling shapes.
873 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object. Invalid values are ignored.
874 This property accepts several color syntaxes:
876 \o 'rgb(red, green, blue)' - for example: 'rgb(255, 100, 55)' or 'rgb(100%, 70%, 30%)'
877 \o 'rgba(red, green, blue, alpha)' - for example: 'rgb(255, 100, 55, 1.0)' or 'rgb(100%, 70%, 30%, 0.5)'
878 \o 'hsl(hue, saturation, lightness)'
879 \o 'hsla(hue, saturation, lightness, alpha)'
880 \o '#RRGGBB' - for example: '#00FFCC'
881 \o Qt.rgba(red, green, blue, alpha) - for example: Qt.rgba(0.3, 0.7, 1, 1.0)
883 If the \a fillStyle or \a strokeStyle is assigned many times in a loop, the last Qt.rgba() syntax should be chosen, as it has the
884 best performance, because it's already a valid QColor value, does not need to be parsed everytime.
886 The default value is '#000000'.
887 \sa QtQuick2::Context2D::createLinearGradient
888 \sa QtQuick2::Context2D::createRadialGradient
889 \sa QtQuick2::Context2D::createPattern
890 \sa QtQuick2::Context2D::strokeStyle
892 static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
894 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
897 QV8Engine *engine = V8ENGINE_ACCESSOR();
899 QColor color = r->context->state.fillStyle.color();
900 if (color.isValid()) {
901 if (color.alpha() == 255)
902 return engine->toString(color.name());
903 QString alphaString = QString::number(color.alphaF(), 'f');
904 while (alphaString.endsWith(QLatin1Char('0')))
906 if (alphaString.endsWith(QLatin1Char('.')))
907 alphaString += QLatin1Char('0');
908 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
910 return r->context->m_fillStyle;
913 static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
915 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
916 CHECK_CONTEXT_SETTER(r)
918 QV8Engine *engine = V8ENGINE_ACCESSOR();
920 if (value->IsObject()) {
921 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
922 if (color.isValid()) {
923 r->context->state.fillStyle = color;
924 r->context->buffer()->setFillStyle(color);
925 r->context->m_fillStyle = value;
927 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
928 if (style && style->brush != r->context->state.fillStyle) {
929 r->context->state.fillStyle = style->brush;
930 r->context->buffer()->setFillStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
931 r->context->m_fillStyle = value;
932 r->context->state.fillPatternRepeatX = style->patternRepeatX;
933 r->context->state.fillPatternRepeatY = style->patternRepeatY;
936 } else if (value->IsString()) {
937 QColor color = qt_color_from_string(value);
938 if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
939 r->context->state.fillStyle = QBrush(color);
940 r->context->buffer()->setFillStyle(r->context->state.fillStyle);
941 r->context->m_fillStyle = value;
946 \qmlproperty enumeration QtQuick2::Context2D::fillRule
947 Holds the current fill rule used for filling shapes. The following fill rules supported:
952 Note: Unlike the \a QPainterPath, the Canvas API uses the winding fill as the default fill rule.
953 The fillRule property is part of the context rendering state.
955 \sa QtQuick2::Context2D::fillStyle
957 static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
959 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
961 QV8Engine *engine = V8ENGINE_ACCESSOR();
963 return engine->fromVariant(r->context->state.fillRule);
966 static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
968 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
969 CHECK_CONTEXT_SETTER(r)
971 QV8Engine *engine = V8ENGINE_ACCESSOR();
973 if ((value->IsString() && engine->toString(value) == QStringLiteral("WindingFill"))
974 ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
975 r->context->state.fillRule = Qt::WindingFill;
976 } else if ((value->IsString() && engine->toString(value) == QStringLiteral("OddEvenFill"))
977 ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
978 r->context->state.fillRule = Qt::OddEvenFill;
982 r->context->m_path.setFillRule(r->context->state.fillRule);
985 \qmlproperty variant QtQuick2::Context2D::strokeStyle
986 Holds the current color or style to use for the lines around shapes,
987 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object.
988 Invalid values are ignored.
990 The default value is '#000000'.
992 \sa QtQuick2::Context2D::createLinearGradient
993 \sa QtQuick2::Context2D::createRadialGradient
994 \sa QtQuick2::Context2D::createPattern
995 \sa QtQuick2::Context2D::fillStyle
997 v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
999 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1002 QV8Engine *engine = V8ENGINE_ACCESSOR();
1004 QColor color = r->context->state.strokeStyle.color();
1005 if (color.isValid()) {
1006 if (color.alpha() == 255)
1007 return engine->toString(color.name());
1008 QString alphaString = QString::number(color.alphaF(), 'f');
1009 while (alphaString.endsWith(QLatin1Char('0')))
1010 alphaString.chop(1);
1011 if (alphaString.endsWith(QLatin1Char('.')))
1012 alphaString += QLatin1Char('0');
1013 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
1015 return r->context->m_strokeStyle;
1018 static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1020 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1021 CHECK_CONTEXT_SETTER(r)
1023 QV8Engine *engine = V8ENGINE_ACCESSOR();
1025 if (value->IsObject()) {
1026 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
1027 if (color.isValid()) {
1028 r->context->state.fillStyle = color;
1029 r->context->buffer()->setStrokeStyle(color);
1030 r->context->m_strokeStyle = value;
1032 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
1033 if (style && style->brush != r->context->state.strokeStyle) {
1034 r->context->state.strokeStyle = style->brush;
1035 r->context->buffer()->setStrokeStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
1036 r->context->m_strokeStyle = value;
1037 r->context->state.strokePatternRepeatX = style->patternRepeatX;
1038 r->context->state.strokePatternRepeatY = style->patternRepeatY;
1042 } else if (value->IsString()) {
1043 QColor color = qt_color_from_string(value);
1044 if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
1045 r->context->state.strokeStyle = QBrush(color);
1046 r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
1047 r->context->m_strokeStyle = value;
1053 \qmlmethod object QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
1054 Returns a CanvasGradient object that represents a linear gradient that transitions the color along a line between
1055 the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
1057 A gradient is a smooth transition between colors. There are two types of gradients: linear and radial.
1058 Gradients must have two or more color stops, representing color shifts positioned from 0 to 1 between
1059 to the gradient's starting and end points or circles.
1061 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1062 \sa QtQuick2::Context2D::createRadialGradient
1063 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
1064 \sa QtQuick2::Context2D::createPattern
1065 \sa QtQuick2::Context2D::fillStyle
1066 \sa QtQuick2::Context2D::strokeStyle
1069 static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
1071 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1075 QV8Engine *engine = V8ENGINE();
1077 if (args.Length() == 4) {
1078 QQuickContext2DEngineData *ed = engineData(engine);
1079 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1080 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1081 qreal x0 = args[0]->NumberValue();
1082 qreal y0 = args[1]->NumberValue();
1083 qreal x1 = args[2]->NumberValue();
1084 qreal y1 = args[3]->NumberValue();
1090 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
1092 r->brush = QLinearGradient(x0, y0, x1, y1);
1093 gradient->SetExternalResource(r);
1101 \qmlmethod object QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
1102 Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
1103 origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
1105 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1106 \sa QtQuick2::Context2D::createLinearGradient
1107 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
1108 \sa QtQuick2::Context2D::createPattern
1109 \sa QtQuick2::Context2D::fillStyle
1110 \sa QtQuick2::Context2D::strokeStyle
1113 static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
1115 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1119 QV8Engine *engine = V8ENGINE();
1121 if (args.Length() == 6) {
1122 QQuickContext2DEngineData *ed = engineData(engine);
1123 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1124 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1126 qreal x0 = args[0]->NumberValue();
1127 qreal y0 = args[1]->NumberValue();
1128 qreal r0 = args[2]->NumberValue();
1129 qreal x1 = args[3]->NumberValue();
1130 qreal y1 = args[4]->NumberValue();
1131 qreal r1 = args[5]->NumberValue();
1139 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
1141 if (r0 < 0 || r1 < 0)
1142 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
1145 r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
1146 gradient->SetExternalResource(r);
1154 \qmlmethod object QtQuick2::Context2D::createConicalGradient(real x, real y, real angle)
1155 Returns a CanvasGradient object that represents a conical gradient that interpolate colors counter-clockwise around a center point (\c x, \c y)
1156 with start angle \c angle in units of radians.
1158 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1159 \sa QtQuick2::Context2D::createLinearGradient
1160 \sa QtQuick2::Context2D::ctx2d_createRadialGradient
1161 \sa QtQuick2::Context2D::createPattern
1162 \sa QtQuick2::Context2D::fillStyle
1163 \sa QtQuick2::Context2D::strokeStyle
1166 static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &args)
1168 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1172 QV8Engine *engine = V8ENGINE();
1174 if (args.Length() == 6) {
1175 QQuickContext2DEngineData *ed = engineData(engine);
1176 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1177 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1179 qreal x = args[0]->NumberValue();
1180 qreal y = args[1]->NumberValue();
1181 qreal angle = DEGREES(args[2]->NumberValue());
1182 if (!qIsFinite(x) || !qIsFinite(y))
1183 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
1185 if (!qIsFinite(angle))
1186 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
1188 r->brush = QConicalGradient(x, y, angle);
1189 gradient->SetExternalResource(r);
1196 \qmlmethod variant createPattern(Color color, enumeration patternMode)
1197 This is a overload function.
1198 Returns a CanvasPattern object that uses the given \c color and \c patternMode.
1199 The valid pattern modes are:
1214 \o Qt.DiagCrossPattern
1219 \qmlmethod variant createPattern(Image image, string repetition)
1220 Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
1222 The \a image parameter must be a valid Image item, a valid \a QtQuick2::CanvasImageData object or loaded image url, if there is no image data, throws an INVALID_STATE_ERR exception.
1224 The allowed values for \a repetition are:
1227 \o "repeat" - both directions
1228 \o "repeat-x - horizontal only
1229 \o "repeat-y" - vertical only
1230 \o "no-repeat" - neither
1233 If the repetition argument is empty or null, the value "repeat" is used.
1235 \sa QtQuick2::Context2D::strokeStyle
1236 \sa QtQuick2::Context2D::fillStyle
1238 static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
1240 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1244 QV8Engine *engine = V8ENGINE();
1246 if (args.Length() == 2) {
1247 QQuickContext2DEngineData *ed = engineData(engine);
1248 QV8Context2DStyleResource *styleResouce = new QV8Context2DStyleResource(engine);
1250 QColor color = engine->toVariant(args[0], qMetaTypeId<QColor>()).value<QColor>();
1251 if (color.isValid()) {
1252 int patternMode = args[1]->IntegerValue();
1253 Qt::BrushStyle style = Qt::SolidPattern;
1254 if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
1255 style = static_cast<Qt::BrushStyle>(patternMode);
1257 styleResouce->brush = QBrush(color, style);
1259 QImage patternTexture;
1261 if (args[0]->IsObject()) {
1262 QV8Context2DPixelArrayResource *pixelData = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->Get(v8::String::New("data"))->ToObject());
1264 patternTexture = pixelData->image;
1267 patternTexture = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
1270 if (!patternTexture.isNull()) {
1271 styleResouce->brush.setTextureImage(patternTexture);
1273 QString repetition = engine->toString(args[1]);
1274 if (repetition == QStringLiteral("repeat") || repetition.isEmpty()) {
1275 styleResouce->patternRepeatX = true;
1276 styleResouce->patternRepeatY = true;
1277 } else if (repetition == QStringLiteral("repeat-x")) {
1278 styleResouce->patternRepeatX = true;
1279 } else if (repetition == QStringLiteral("repeat-y")) {
1280 styleResouce->patternRepeatY = true;
1281 } else if (repetition == QStringLiteral("no-repeat")) {
1282 styleResouce->patternRepeatY = false;
1283 styleResouce->patternRepeatY = false;
1285 //TODO: exception: SYNTAX_ERR
1291 v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
1292 pattern->SetExternalResource(styleResouce);
1296 return v8::Undefined();
1301 \qmlproperty string QtQuick2::Context2D::lineCap
1302 Holds the the current line cap style.
1303 The possible line cap styles are:
1305 \o butt - the end of each line has a flat edge perpendicular to the direction of the line, this is the default line cap value.
1306 \o round - a semi-circle with the diameter equal to the width of the line must then be added on to the end of the line.
1307 \o square - a rectangle with the length of the line width and the width of half the line width, placed flat against the edge perpendicular to the direction of the line.
1309 Other values are ignored.
1311 v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
1313 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1317 QV8Engine *engine = V8ENGINE_ACCESSOR();
1318 switch (r->context->state.lineCap) {
1320 return engine->toString(QLatin1String("round"));
1322 return engine->toString(QLatin1String("butt"));
1324 return engine->toString(QLatin1String("square"));
1328 return engine->toString(QLatin1String("butt"));;
1331 static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1333 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1334 CHECK_CONTEXT_SETTER(r)
1336 QV8Engine *engine = V8ENGINE_ACCESSOR();
1338 QString lineCap = engine->toString(value);
1339 Qt::PenCapStyle cap;
1340 if (lineCap == QLatin1String("round"))
1342 else if (lineCap == QLatin1String("butt"))
1344 else if (lineCap == QLatin1String("square"))
1345 cap = Qt::SquareCap;
1349 if (cap != r->context->state.lineCap) {
1350 r->context->state.lineCap = cap;
1351 r->context->buffer()->setLineCap(cap);
1356 \qmlproperty string QtQuick2::Context2D::lineJoin
1357 Holds the the current line join style. A join exists at any point in a subpath
1358 shared by two consecutive lines. When a subpath is closed, then a join also exists
1359 at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
1361 The possible line join styles are:
1363 \o bevel - this is all that is rendered at joins.
1364 \o round - a filled arc connecting the two aforementioned corners of the join, abutting (and not overlapping) the aforementioned triangle, with the diameter equal to the line width and the origin at the point of the join, must be rendered at joins.
1365 \o miter - a second filled triangle must (if it can given the miter length) be rendered at the join, this is the default line join style.
1367 Other values are ignored.
1369 v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
1371 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1375 QV8Engine *engine = V8ENGINE_ACCESSOR();
1376 switch (r->context->state.lineJoin) {
1378 return engine->toString(QLatin1String("round"));
1380 return engine->toString(QLatin1String("bevel"));
1382 return engine->toString(QLatin1String("miter"));
1386 return engine->toString(QLatin1String("miter"));
1389 static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1391 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1392 CHECK_CONTEXT_SETTER(r)
1394 QV8Engine *engine = V8ENGINE_ACCESSOR();
1396 QString lineJoin = engine->toString(value);
1397 Qt::PenJoinStyle join;
1398 if (lineJoin == QLatin1String("round"))
1399 join = Qt::RoundJoin;
1400 else if (lineJoin == QLatin1String("bevel"))
1401 join = Qt::BevelJoin;
1402 else if (lineJoin == QLatin1String("miter"))
1403 join = Qt::MiterJoin;
1407 if (join != r->context->state.lineJoin) {
1408 r->context->state.lineJoin = join;
1409 r->context->buffer()->setLineJoin(join);
1414 \qmlproperty real QtQuick2::Context2D::lineWidth
1415 Holds the the current line width. Values that are not finite values greater than zero are ignored.
1417 v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
1419 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1423 return v8::Number::New(r->context->state.lineWidth);
1426 static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1428 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1429 CHECK_CONTEXT_SETTER(r)
1431 qreal w = value->NumberValue();
1433 if (w > 0 && qIsFinite(w) && w != r->context->state.lineWidth) {
1434 r->context->state.lineWidth = w;
1435 r->context->buffer()->setLineWidth(w);
1440 \qmlproperty real QtQuick2::Context2D::miterLimit
1441 Holds the current miter limit ratio.
1442 The default miter limit value is 10.0.
1444 v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
1446 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1450 return v8::Number::New(r->context->state.miterLimit);
1453 static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1455 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1456 CHECK_CONTEXT_SETTER(r)
1458 qreal ml = value->NumberValue();
1460 if (ml > 0 && qIsFinite(ml) && ml != r->context->state.miterLimit) {
1461 r->context->state.miterLimit = ml;
1462 r->context->buffer()->setMiterLimit(ml);
1468 \qmlproperty real QtQuick2::Context2D::shadowBlur
1469 Holds the current level of blur applied to shadows
1471 v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
1473 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1477 return v8::Number::New(r->context->state.shadowBlur);
1480 static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1482 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1483 CHECK_CONTEXT_SETTER(r)
1484 qreal blur = value->NumberValue();
1486 if (blur > 0 && qIsFinite(blur) && blur != r->context->state.shadowBlur) {
1487 r->context->state.shadowBlur = blur;
1488 r->context->buffer()->setShadowBlur(blur);
1493 \qmlproperty string QtQuick2::Context2D::shadowColor
1494 Holds the current shadow color.
1496 v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
1498 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1502 QV8Engine *engine = V8ENGINE_ACCESSOR();
1504 return engine->toString(r->context->state.shadowColor.name());
1507 static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1509 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1510 CHECK_CONTEXT_SETTER(r)
1512 QColor color = qt_color_from_string(value);
1514 if (color.isValid() && color != r->context->state.shadowColor) {
1515 r->context->state.shadowColor = color;
1516 r->context->buffer()->setShadowColor(color);
1522 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
1523 Holds the current shadow offset in the positive horizontal distance.
1525 \sa QtQuick2::Context2D::shadowOffsetY
1527 v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
1529 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1533 return v8::Number::New(r->context->state.shadowOffsetX);
1536 static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1538 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1539 CHECK_CONTEXT_SETTER(r)
1541 qreal offsetX = value->NumberValue();
1542 if (qIsFinite(offsetX) && offsetX != r->context->state.shadowOffsetX) {
1543 r->context->state.shadowOffsetX = offsetX;
1544 r->context->buffer()->setShadowOffsetX(offsetX);
1548 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
1549 Holds the current shadow offset in the positive vertical distance.
1551 \sa QtQuick2::Context2D::shadowOffsetX
1553 v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
1555 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1559 return v8::Number::New(r->context->state.shadowOffsetY);
1562 static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1564 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1565 CHECK_CONTEXT_SETTER(r)
1567 qreal offsetY = value->NumberValue();
1568 if (qIsFinite(offsetY) && offsetY != r->context->state.shadowOffsetY) {
1569 r->context->state.shadowOffsetY = offsetY;
1570 r->context->buffer()->setShadowOffsetY(offsetY);
1574 v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
1576 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1578 return r->context->m_v8path;
1581 static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1583 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1584 CHECK_CONTEXT_SETTER(r)
1585 QV8Engine *engine = V8ENGINE_ACCESSOR();
1587 r->context->beginPath();
1588 if (value->IsObject()) {
1589 QDeclarativePath* path = qobject_cast<QDeclarativePath*>(engine->toQObject(value));
1591 r->context->m_path = path->path();
1593 QString path = engine->toString(value->ToString());
1594 QDeclarativeSvgParser::parsePathDataFast(path, r->context->m_path);
1596 r->context->m_v8path = value;
1601 \qmlmethod object QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
1602 Clears all pixels on the canvas in the given rectangle to transparent black.
1604 static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
1606 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1610 if (args.Length() == 4) {
1611 qreal x = args[0]->NumberValue();
1612 qreal y = args[1]->NumberValue();
1613 qreal w = args[2]->NumberValue();
1614 qreal h = args[3]->NumberValue();
1616 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
1619 r->context->buffer()->clearRect(x, y, w, h);
1625 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1626 Paint the specified rectangular area using the fillStyle.
1628 \sa QtQuick2::Context2D::fillStyle
1630 static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
1632 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1635 if (args.Length() == 4) {
1636 qreal x = args[0]->NumberValue();
1637 qreal y = args[1]->NumberValue();
1638 qreal w = args[2]->NumberValue();
1639 qreal h = args[3]->NumberValue();
1641 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
1644 r->context->buffer()->fillRect(x, y, w, h);
1651 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1652 Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
1653 and (if appropriate) miterLimit attributes.
1655 \sa QtQuick2::Context2D::strokeStyle
1656 \sa QtQuick2::Context2D::lineWidth
1657 \sa QtQuick2::Context2D::lineJoin
1658 \sa QtQuick2::Context2D::miterLimit
1660 static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
1662 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1666 if (args.Length() == 4) {
1667 qreal x = args[0]->NumberValue();
1668 qreal y = args[1]->NumberValue();
1669 qreal w = args[2]->NumberValue();
1670 qreal h = args[3]->NumberValue();
1672 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
1675 r->context->buffer()->strokeRect(x, y, w, h);
1681 // Complex shapes (paths) API
1683 \qmlmethod object QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
1684 Adds an arc to the current subpath that lies on the circumference of the circle whose center is at the point (\c x,\cy) and whose radius is \c radius.
1685 \image qml-item-canvas-arcTo2.png
1686 \sa QtQuick2::Context2D::arcTo
1687 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
1689 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
1691 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1694 if (args.Length() >= 5) {
1695 bool antiClockwise = false;
1697 if (args.Length() == 6)
1698 antiClockwise = args[5]->BooleanValue();
1700 qreal radius = args[2]->NumberValue();
1701 qreal x = args[0]->NumberValue();
1702 qreal y = args[1]->NumberValue();
1703 qreal sa = args[3]->NumberValue();
1704 qreal ea = args[4]->NumberValue();
1706 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(sa) || !qIsFinite(ea))
1710 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1712 r->context->arc(args[0]->NumberValue(),
1713 args[1]->NumberValue(),
1715 args[3]->NumberValue(),
1716 args[4]->NumberValue(),
1724 \qmlmethod object QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
1726 Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
1727 To draw an arc, you begin with the same steps your followed to create a line:
1729 \o Call the context.beginPath() method to set a new path.
1730 \o Call the context.moveTo(\c x, \c y) method to set your starting position on the canvas at the point (\c x,\c y).
1731 \o To draw an arc or circle, call the context.arcTo(\c x1, \c y1, \c x2, \c y2,\c radius) method.
1732 This adds an arc with starting point (\c x1,\c y1), ending point (\c x2, \c y2), and radius \c radius to the current subpath and connects
1733 it to the previous subpath by a straight line.
1735 \image qml-item-canvas-arcTo.png
1736 Both startAngle and endAngle are measured from the x axis in units of radians.
1738 \image qml-item-canvas-startAngle.png
1739 The anticlockwise has the value TRUE for each arc in the figure above because they are all drawn in the counterclockwise direction.
1740 \sa QtQuick2::Context2D::arc
1741 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d context standard for arcTo}
1743 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
1745 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1750 if (args.Length() == 5) {
1751 qreal x1 = args[0]->NumberValue();
1752 qreal y1 = args[1]->NumberValue();
1753 qreal x2 = args[2]->NumberValue();
1754 qreal y2 = args[3]->NumberValue();
1756 if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
1759 qreal radius = args[4]->NumberValue();
1761 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1762 r->context->arcTo(args[0]->NumberValue(),
1763 args[1]->NumberValue(),
1764 args[2]->NumberValue(),
1765 args[3]->NumberValue(),
1766 args[4]->NumberValue());
1773 \qmlmethod object QtQuick2::Context2D::beginPath()
1775 Resets the current path to a new path.
1777 static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
1779 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1783 r->context->beginPath();
1789 \qmlmethod object QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
1791 Adds a cubic Bezier curve between the current position and the given endPoint using the control points specified by (\c cp1x, cp1y),
1792 and (\c cp2x, \c cp2y).
1793 After the curve is added, the current position is updated to be at the end point (\c x, \c y) of the curve.
1794 The following code produces the path shown below:
1796 ctx.strokeStyle = Qt.rgba(0, 0, 0, 1);
1799 ctx.moveTo(20, 0);//start point
1800 ctx.bezierCurveTo(-10, 90, 210, 90, 180, 0);
1803 \image qml-item-canvas-bezierCurveTo.png
1804 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
1805 \sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
1807 static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
1809 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1813 if (args.Length() == 6) {
1814 qreal cp1x = args[0]->NumberValue();
1815 qreal cp1y = args[1]->NumberValue();
1816 qreal cp2x = args[2]->NumberValue();
1817 qreal cp2y = args[3]->NumberValue();
1818 qreal x = args[4]->NumberValue();
1819 qreal y = args[5]->NumberValue();
1821 if (!qIsFinite(cp1x) || !qIsFinite(cp1y) || !qIsFinite(cp2x) || !qIsFinite(cp2y) || !qIsFinite(x) || !qIsFinite(y))
1824 r->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
1831 \qmlmethod object QtQuick2::Context2D::clip()
1833 Creates the clipping region from the current path.
1834 Any parts of the shape outside the clipping path are not displayed.
1835 To create a complex shape using the \a clip() method:
1838 \o Call the \c{context.beginPath()} method to set the clipping path.
1839 \o Define the clipping path by calling any combination of the \c{lineTo},
1840 \c{arcTo}, \c{arc}, \c{moveTo}, etc and \c{closePath} methods.
1841 \o Call the \c{context.clip()} method.
1844 The new shape displays. The following shows how a clipping path can
1845 modify how an image displays:
1847 \image qml-canvas-clip-complex.png
1848 \sa QtQuick2::Context2D::beginPath()
1849 \sa QtQuick2::Context2D::closePath()
1850 \sa QtQuick2::Context2D::stroke()
1851 \sa QtQuick2::Context2D::fill()
1852 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-clip}{W3C 2d context standard for clip}
1854 static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
1856 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1859 QPainterPath clipPath = r->context->m_path;
1860 clipPath.closeSubpath();
1861 if (!r->context->state.clipPath.isEmpty())
1862 r->context->state.clipPath = clipPath.intersected(r->context->state.clipPath);
1864 r->context->state.clipPath = clipPath;
1865 r->context->buffer()->clip(r->context->state.clipPath);
1871 \qmlmethod object QtQuick2::Context2D::closePath()
1872 Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting a new path.
1873 The current point of the new path is the previous subpath's first point.
1875 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath}{W3C 2d context standard for closePath}
1877 static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
1879 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1883 r->context->closePath();
1889 \qmlmethod object QtQuick2::Context2D::fill()
1891 Fills the subpaths with the current fill style.
1893 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-fill}{W3C 2d context standard for fill}
1895 \sa QtQuick2::Context2D::fillStyle
1897 static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
1899 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1902 r->context->buffer()->fill(r->context->m_path);
1908 \qmlmethod object QtQuick2::Context2D::lineTo(real x, real y)
1910 Draws a line from the current position to the point (x, y).
1912 static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
1914 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1918 if (args.Length() == 2) {
1919 qreal x = args[0]->NumberValue();
1920 qreal y = args[1]->NumberValue();
1922 if (!qIsFinite(x) || !qIsFinite(y))
1925 r->context->lineTo(x, y);
1932 \qmlmethod object QtQuick2::Context2D::moveTo(real x, real y)
1934 Creates a new subpath with the given point.
1936 static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
1938 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1941 if (args.Length() == 2) {
1942 qreal x = args[0]->NumberValue();
1943 qreal y = args[1]->NumberValue();
1945 if (!qIsFinite(x) || !qIsFinite(y))
1947 r->context->moveTo(x, y);
1953 \qmlmethod object QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
1955 Adds a quadratic Bezier curve between the current point and the endpoint (\c x, \c y) with the control point specified by (\c cpx, \c cpy).
1957 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto}{W3C 2d context standard for for quadraticCurveTo}
1959 static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
1961 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1964 if (args.Length() == 4) {
1965 qreal cpx = args[0]->NumberValue();
1966 qreal cpy = args[1]->NumberValue();
1967 qreal x = args[2]->NumberValue();
1968 qreal y = args[3]->NumberValue();
1970 if (!qIsFinite(cpx) || !qIsFinite(cpy) || !qIsFinite(x) || !qIsFinite(y))
1973 r->context->quadraticCurveTo(cpx, cpy, x, y);
1980 \qmlmethod object QtQuick2::Context2D::rect(real x, real y, real w, real h)
1982 Adds a rectangle at position (\c x, \c y), with the given width \c w and height \c h, as a closed subpath.
1984 static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
1986 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1990 if (args.Length() == 4) {
1991 qreal x = args[0]->NumberValue();
1992 qreal y = args[1]->NumberValue();
1993 qreal w = args[2]->NumberValue();
1994 qreal h = args[3]->NumberValue();
1996 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
1999 r->context->rect(x, y, w, h);
2006 \qmlmethod object QtQuick2::Context2D::roundedRect(real x, real y, real w, real h, real xRadius, real yRadius)
2008 Adds the given rectangle rect with rounded corners to the path. The \c xRadius and \c yRadius arguments specify the radius of the
2009 ellipses defining the corners of the rounded rectangle.
2011 static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
2013 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2016 if (args.Length() == 6) {
2017 qreal x = args[0]->NumberValue();
2018 qreal y = args[1]->NumberValue();
2019 qreal w = args[2]->NumberValue();
2020 qreal h = args[3]->NumberValue();
2021 qreal xr = args[4]->NumberValue();
2022 qreal yr = args[5]->NumberValue();
2024 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2027 if (!qIsFinite(xr) || !qIsFinite(yr))
2028 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "roundedRect(): Invalid arguments");
2030 r->context->roundedRect(x, y, w, h, xr, yr);
2037 \qmlmethod object QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
2039 Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
2040 and adds it to the path as a closed subpath.
2042 The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
2044 static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
2046 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2050 if (args.Length() == 4) {
2051 qreal x = args[0]->NumberValue();
2052 qreal y = args[1]->NumberValue();
2053 qreal w = args[2]->NumberValue();
2054 qreal h = args[3]->NumberValue();
2056 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2060 r->context->ellipse(x, y, w, h);
2067 \qmlmethod object QtQuick2::Context2D::text(string text, real x, real y)
2069 Adds the given \c text to the path as a set of closed subpaths created from the current context font supplied.
2070 The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (\c x, \c y).
2072 static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
2074 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2077 QV8Engine *engine = V8ENGINE();
2078 if (args.Length() == 3) {
2079 qreal x = args[1]->NumberValue();
2080 qreal y = args[2]->NumberValue();
2082 if (!qIsFinite(x) || !qIsFinite(y))
2084 r->context->text(engine->toString(args[0]), x, y);
2090 \qmlmethod object QtQuick2::Context2D::stroke()
2092 Strokes the subpaths with the current stroke style.
2094 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke}{W3C 2d context standard for stroke}
2096 \sa QtQuick2::Context2D::strokeStyle
2098 static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
2100 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2104 r->context->buffer()->stroke(r->context->m_path);
2110 \qmlmethod object QtQuick2::Context2D::isPointInPath(real x, real y)
2112 Returns true if the given point is in the current path.
2114 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath}{W3C 2d context standard for isPointInPath}
2116 static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
2118 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2121 bool pointInPath = false;
2122 if (args.Length() == 2) {
2123 qreal x = args[0]->NumberValue();
2124 qreal y = args[1]->NumberValue();
2125 if (!qIsFinite(x) || !qIsFinite(y))
2126 return v8::Boolean::New(false);
2127 pointInPath = r->context->isPointInPath(x, y);
2129 return v8::Boolean::New(pointInPath);
2132 static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
2134 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
2138 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
2140 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
2144 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
2146 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
2151 \qmlproperty string QtQuick2::Context2D::font
2152 Holds the current font settings.
2154 The default font value is "10px sans-serif".
2155 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-font}{w3C 2d context standard for font}
2157 v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
2159 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2162 QV8Engine *engine = V8ENGINE_ACCESSOR();
2164 return engine->toString(r->context->state.font.toString());
2167 static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2169 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2170 CHECK_CONTEXT_SETTER(r)
2172 QV8Engine *engine = V8ENGINE_ACCESSOR();
2173 QString fs = engine->toString(value);
2174 QFont font = qt_font_from_string(fs);
2175 if (font != r->context->state.font) {
2176 r->context->state.font = font;
2181 \qmlproperty string QtQuick2::Context2D::textAlign
2183 Holds the current text alignment settings.
2184 The possible values are:
2192 Other values are ignored. The default value is "start".
2194 v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
2196 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2198 QV8Engine *engine = V8ENGINE_ACCESSOR();
2199 switch (r->context->state.textAlign) {
2200 case QQuickContext2D::Start:
2201 return engine->toString(QLatin1String("start"));
2202 case QQuickContext2D::End:
2203 return engine->toString(QLatin1String("end"));
2204 case QQuickContext2D::Left:
2205 return engine->toString(QLatin1String("left"));
2206 case QQuickContext2D::Right:
2207 return engine->toString(QLatin1String("right"));
2208 case QQuickContext2D::Center:
2209 return engine->toString(QLatin1String("center"));
2213 return engine->toString(QLatin1String("start"));
2216 static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2218 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2219 CHECK_CONTEXT_SETTER(r)
2220 QV8Engine *engine = V8ENGINE_ACCESSOR();
2222 QString textAlign = engine->toString(value);
2224 QQuickContext2D::TextAlignType ta;
2225 if (textAlign == QLatin1String("start"))
2226 ta = QQuickContext2D::Start;
2227 else if (textAlign == QLatin1String("end"))
2228 ta = QQuickContext2D::End;
2229 else if (textAlign == QLatin1String("left"))
2230 ta = QQuickContext2D::Left;
2231 else if (textAlign == QLatin1String("right"))
2232 ta = QQuickContext2D::Right;
2233 else if (textAlign == QLatin1String("center"))
2234 ta = QQuickContext2D::Center;
2238 if (ta != r->context->state.textAlign) {
2239 r->context->state.textAlign = ta;
2244 \qmlproperty string QtQuick2::Context2D::textBaseline
2246 Holds the current baseline alignment settings.
2247 The possible values are:
2256 Other values are ignored. The default value is "alphabetic".
2258 v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
2260 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2263 QV8Engine *engine = V8ENGINE_ACCESSOR();
2264 switch (r->context->state.textBaseline) {
2265 case QQuickContext2D::Alphabetic:
2266 return engine->toString(QLatin1String("alphabetic"));
2267 case QQuickContext2D::Hanging:
2268 return engine->toString(QLatin1String("hanging"));
2269 case QQuickContext2D::Top:
2270 return engine->toString(QLatin1String("top"));
2271 case QQuickContext2D::Bottom:
2272 return engine->toString(QLatin1String("bottom"));
2273 case QQuickContext2D::Middle:
2274 return engine->toString(QLatin1String("middle"));
2278 return engine->toString(QLatin1String("alphabetic"));
2281 static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2283 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2284 CHECK_CONTEXT_SETTER(r)
2285 QV8Engine *engine = V8ENGINE_ACCESSOR();
2286 QString textBaseline = engine->toString(value);
2288 QQuickContext2D::TextBaseLineType tb;
2289 if (textBaseline == QLatin1String("alphabetic"))
2290 tb = QQuickContext2D::Alphabetic;
2291 else if (textBaseline == QLatin1String("hanging"))
2292 tb = QQuickContext2D::Hanging;
2293 else if (textBaseline == QLatin1String("top"))
2294 tb = QQuickContext2D::Top;
2295 else if (textBaseline == QLatin1String("bottom"))
2296 tb = QQuickContext2D::Bottom;
2297 else if (textBaseline == QLatin1String("middle"))
2298 tb = QQuickContext2D::Middle;
2302 if (tb != r->context->state.textBaseline) {
2303 r->context->state.textBaseline = tb;
2308 \qmlmethod object QtQuick2::Context2D::fillText(text, x, y)
2309 Fills the given text at the given position.
2310 \sa QtQuick2::Context2D::font
2311 \sa QtQuick2::Context2D::textAlign
2312 \sa QtQuick2::Context2D::textBaseline
2313 \sa QtQuick2::Context2D::strokeText
2315 static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
2317 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2320 QV8Engine *engine = V8ENGINE();
2321 if (args.Length() == 3) {
2322 qreal x = args[1]->NumberValue();
2323 qreal y = args[2]->NumberValue();
2324 if (!qIsFinite(x) || !qIsFinite(y))
2326 QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
2327 r->context->buffer()->fill(textPath);
2332 \qmlmethod object QtQuick2::Context2D::strokeText(text, x, y)
2333 Strokes the given text at the given position.
2334 \sa QtQuick2::Context2D::font
2335 \sa QtQuick2::Context2D::textAlign
2336 \sa QtQuick2::Context2D::textBaseline
2337 \sa QtQuick2::Context2D::fillText
2339 static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
2341 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2344 QV8Engine *engine = V8ENGINE();
2345 if (args.Length() == 3) {
2346 qreal x = args[1]->NumberValue();
2347 qreal y = args[2]->NumberValue();
2348 if (!qIsFinite(x) || !qIsFinite(y))
2350 QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
2351 r->context->buffer()->stroke(textPath);
2356 \qmlclass QtQuick2::TextMetrics
2357 \inqmlmodule QtQuick 2
2359 \brief The Context2D TextMetrics interface.
2360 The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
2361 See {http://www.w3.org/TR/2dcontext/#textmetrics}{W3C 2d context TexMetrics} for more details.
2363 \sa QtQuick2::Context2D::measureText
2364 \sa QtQuick2::TextMetrics::width
2368 \qmlproperty int QtQuick2::TextMetrics::width
2369 Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
2370 This property is read only.
2374 \qmlmethod variant QtQuick2::Context2D::measureText(text)
2375 Returns a TextMetrics object with the metrics of the given text in the current font.
2377 static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
2379 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2382 QV8Engine *engine = V8ENGINE();
2384 if (args.Length() == 1) {
2385 QFontMetrics fm(r->context->state.font);
2386 uint width = fm.width(engine->toString(args[0]));
2387 v8::Local<v8::Object> tm = v8::Object::New();
2388 tm->Set(v8::String::New("width"), v8::Number::New(width));
2391 return v8::Undefined();
2396 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
2397 Draws the given \a image on the canvas at position (\a dx, \a dy).
2399 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2400 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2401 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2402 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2404 \sa QtQuick2::CanvasImageData
2406 \sa QtQuick2::Canvas::loadImage
2407 \sa QtQuick2::Canvas::isImageLoaded
2408 \sa QtQuick2::Canvas::imageLoaded
2410 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2413 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
2414 This is an overloaded function.
2415 Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
2419 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2420 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2421 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2422 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2424 \sa QtQuick2::CanvasImageData
2426 \sa QtQuick2::Canvas::loadImage
2427 \sa QtQuick2::Canvas::isImageLoaded
2428 \sa QtQuick2::Canvas::imageLoaded
2430 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2433 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
2434 This is an overloaded function.
2435 Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
2436 onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
2440 The \a image type can be an Image or Canvas item, an image url or a \a {QtQuick2::CanvasImageData} object.
2441 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2442 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2443 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2445 \sa QtQuick2::CanvasImageData
2447 \sa QtQuick2::Canvas::loadImage
2448 \sa QtQuick2::Canvas::isImageLoaded
2449 \sa QtQuick2::Canvas::imageLoaded
2451 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2453 static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
2455 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2458 QV8Engine *engine = V8ENGINE();
2459 qreal sx, sy, sw, sh, dx, dy, dw, dh;
2465 if (args[0]->IsString()) {
2466 QUrl url(engine->toString(args[0]->ToString()));
2468 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2470 image = r->context->createImage(url);
2471 } else if (args[0]->IsObject()) {
2472 QQuickImage *imageItem = qobject_cast<QQuickImage*>(engine->toQObject(args[0]->ToObject()));
2473 QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(engine->toQObject(args[0]->ToObject()));
2475 QV8Context2DPixelArrayResource *pix = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->GetInternalField(0)->ToObject());
2478 } else if (imageItem) {
2479 image = imageItem->image();
2480 } else if (canvas) {
2481 image = canvas->toImage();
2483 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2486 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2488 if (args.Length() == 3) {
2489 dx = args[1]->NumberValue();
2490 dy = args[2]->NumberValue();
2494 sh = image.height();
2497 } else if (args.Length() == 5) {
2501 sh = image.height();
2502 dx = args[1]->NumberValue();
2503 dy = args[2]->NumberValue();
2504 dw = args[3]->NumberValue();
2505 dh = args[4]->NumberValue();
2506 } else if (args.Length() == 9) {
2507 sx = args[1]->NumberValue();
2508 sy = args[2]->NumberValue();
2509 sw = args[3]->NumberValue();
2510 sh = args[4]->NumberValue();
2511 dx = args[5]->NumberValue();
2512 dy = args[6]->NumberValue();
2513 dw = args[7]->NumberValue();
2514 dh = args[8]->NumberValue();
2529 if (!image.isNull()) {
2530 if (sx < 0 || sy < 0 || sw == 0 || sh == 0
2531 || sx + sw > image.width() || sy + sh > image.height()
2532 || sx + sw < 0 || sy + sh < 0) {
2533 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
2536 r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
2542 // pixel manipulation
2544 \qmlclass QtQuick2::CanvasImageData
2545 The \a QtQuick2::CanvasImageData object holds the image pixel data.
2547 The \a QtQuick2::CanvasImageData object has the actual dimensions of the data stored in
2548 this object and holds the one-dimensional array containing the data in RGBA order,
2549 as integers in the range 0 to 255.
2551 \sa QtQuick2::CanvasImageData::width
2552 \sa QtQuick2::CanvasImageData::height
2553 \sa QtQuick2::CanvasImageData::data
2554 \sa QtQuick2::Context2D::createImageData
2555 \sa QtQuick2::Context2D::getImageData
2556 \sa QtQuick2::Context2D::putImageData
2559 \qmlproperty QtQuick2::CanvasImageData::width
2560 Holds the actual width dimension of the data in the ImageData object, in device pixels.
2562 v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
2564 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2566 return v8::Integer::New(0);
2567 return v8::Integer::New(r->image.width());
2571 \qmlproperty QtQuick2::CanvasImageData::height
2572 Holds the actual height dimension of the data in the ImageData object, in device pixels.
2574 v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
2576 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2578 return v8::Integer::New(0);
2580 return v8::Integer::New(r->image.height());
2584 \qmlproperty QtQuick2::CanvasImageData::data
2585 Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
2587 v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
2589 return args.This()->GetInternalField(0);
2593 \qmlclass QtQuick2::CanvasPixelArray
2594 The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
2595 The CanvasPixelArray can be accessed as normal Javascript array.
2596 \sa QtQuick2::CanvasImageData
2597 \sa {http://www.w3.org/TR/2dcontext/#canvaspixelarray}{W3C 2d context standard for PixelArray}
2601 \qmlproperty QtQuick2::CanvasPixelArray::length
2602 The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
2603 The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
2604 This property is read only.
2606 v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
2608 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2609 if (!r || r->image.isNull()) return v8::Undefined();
2611 return v8::Integer::New(r->image.width() * r->image.height() * 4);
2614 v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
2616 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2618 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
2619 const quint32 w = r->image.width();
2620 const quint32 row = (index / 4) / w;
2621 const quint32 col = (index / 4) % w;
2622 const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
2624 switch (index % 4) {
2626 return v8::Integer::New(qRed(*pixel));
2628 return v8::Integer::New(qGreen(*pixel));
2630 return v8::Integer::New(qBlue(*pixel));
2632 return v8::Integer::New(qAlpha(*pixel));
2635 return v8::Undefined();
2638 v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
2640 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
2642 const int v = value->Uint32Value();
2643 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4) && v > 0 && v <= 255) {
2644 const quint32 w = r->image.width();
2645 const quint32 row = (index / 4) / w;
2646 const quint32 col = (index / 4) % w;
2648 QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
2650 switch (index % 4) {
2652 *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
2655 *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
2658 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
2661 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
2665 return v8::Undefined();
2668 \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
2669 Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
2672 \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
2673 Creates a CanvasImageData object with the same dimensions as the argument.
2676 \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
2677 Creates a CanvasImageData object with the given image loaded from \a imageUrl.
2678 Note:The \a imageUrl must be already loaded before this function call, if not, an empty
2679 CanvasImageData obect will be returned.
2681 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
2683 static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
2685 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2688 QV8Engine *engine = V8ENGINE();
2690 if (args.Length() == 1) {
2691 if (args[0]->IsObject()) {
2692 v8::Local<v8::Object> imgData = args[0]->ToObject();
2693 QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
2695 qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
2696 qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
2697 return qt_create_image_data(w, h, engine, QImage());
2699 } else if (args[0]->IsString()) {
2700 QImage image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2701 return qt_create_image_data(image.width(), image.height(), engine, image);
2703 } else if (args.Length() == 2) {
2704 qreal w = args[0]->NumberValue();
2705 qreal h = args[1]->NumberValue();
2707 if (!qIsFinite(w) || !qIsFinite(h))
2708 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
2711 return qt_create_image_data(w, h, engine, QImage());
2713 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createImageData(): invalid arguments");
2715 return v8::Undefined();
2719 \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
2720 Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
2722 static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
2724 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2727 QV8Engine *engine = V8ENGINE();
2728 if (args.Length() == 4) {
2729 qreal x = args[0]->NumberValue();
2730 qreal y = args[1]->NumberValue();
2731 qreal w = args[2]->NumberValue();
2732 qreal h = args[3]->NumberValue();
2733 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(w))
2734 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
2736 if (w <= 0 || h <= 0)
2737 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
2739 QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
2740 v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
2748 \qmlmethod object QtQuick2::Context2D::putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
2749 Paints the data from the given ImageData object onto the canvas. If a dirty rectangle (\a dirtyX, \a dirtyY, \a dirtyWidth, \a dirtyHeight) is provided, only the pixels from that rectangle are painted.
2751 static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
2753 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2755 if (args.Length() != 3 && args.Length() != 7)
2756 return v8::Undefined();
2758 if (args[0]->IsNull() || !args[0]->IsObject()) {
2759 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
2761 qreal dx = args[1]->NumberValue();
2762 qreal dy = args[2]->NumberValue();
2763 qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
2765 if (!qIsFinite(dx) || !qIsFinite(dy))
2766 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2768 v8::Local<v8::Object> imageData = args[0]->ToObject();
2769 QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
2771 w = imageData->Get(v8::String::New("width"))->NumberValue();
2772 h = imageData->Get(v8::String::New("height"))->NumberValue();
2774 if (args.Length() == 7) {
2775 dirtyX = args[3]->NumberValue();
2776 dirtyY = args[4]->NumberValue();
2777 dirtyWidth = args[5]->NumberValue();
2778 dirtyHeight = args[6]->NumberValue();
2780 if (!qIsFinite(dirtyX) || !qIsFinite(dirtyY) || !qIsFinite(dirtyWidth) || !qIsFinite(dirtyHeight))
2781 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2784 if (dirtyWidth < 0) {
2785 dirtyX = dirtyX+dirtyWidth;
2786 dirtyWidth = -dirtyWidth;
2789 if (dirtyHeight < 0) {
2790 dirtyY = dirtyY+dirtyHeight;
2791 dirtyHeight = -dirtyHeight;
2795 dirtyWidth = dirtyWidth+dirtyX;
2800 dirtyHeight = dirtyHeight+dirtyY;
2804 if (dirtyX+dirtyWidth > w) {
2805 dirtyWidth = w - dirtyX;
2808 if (dirtyY+dirtyHeight > h) {
2809 dirtyHeight = h - dirtyY;
2812 if (dirtyWidth <=0 || dirtyHeight <= 0)
2821 QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2822 r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
2828 \qmlclass QtQuick2::CanvasGradient
2829 \inqmlmodule QtQuick 2
2831 \brief The Context2D opaque CanvasGradient interface.
2835 \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
2836 Adds a color stop with the given color to the gradient at the given offset.
2837 0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
2841 var gradient = ctx.createLinearGradient(0, 0, 100, 100);
2842 gradient.addColorStop(0.3, Qt.rgba(1, 0, 0, 1));
2843 gradient.addColorStop(0.7, 'rgba(0, 255, 255, 1');
2846 static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
2848 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
2850 V8THROW_ERROR("Not a CanvasGradient object");
2852 QV8Engine *engine = V8ENGINE();
2854 if (args.Length() == 2) {
2856 if (!style->brush.gradient())
2857 V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
2858 QGradient gradient = *(style->brush.gradient());
2859 qreal pos = args[0]->NumberValue();
2862 if (args[1]->IsObject()) {
2863 color = engine->toVariant(args[1], qMetaTypeId<QColor>()).value<QColor>();
2865 color = qt_color_from_string(args[1]);
2867 if (pos < 0.0 || pos > 1.0 || !qIsFinite(pos)) {
2868 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
2871 if (color.isValid()) {
2872 gradient.setColorAt(pos, color);
2874 V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string");
2876 style->brush = gradient;
2883 void QQuickContext2D::beginPath()
2885 m_path = QPainterPath();
2886 m_path.setFillRule(state.fillRule);
2889 void QQuickContext2D::closePath()
2891 if (m_path.isEmpty())
2894 QRectF boundRect = m_path.boundingRect();
2895 if (boundRect.width() || boundRect.height())
2896 m_path.closeSubpath();
2897 //FIXME:QPainterPath set the current point to (0,0) after close subpath
2898 //should be the first point of the previous subpath
2901 void QQuickContext2D::moveTo( qreal x, qreal y)
2903 //FIXME: moveTo should not close the previous subpath
2904 m_path.moveTo(state.matrix.map(QPointF(x, y)));
2907 void QQuickContext2D::lineTo( qreal x, qreal y)
2909 m_path.lineTo(state.matrix.map(QPointF(x, y)));
2912 void QQuickContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
2915 m_path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
2916 state.matrix.map(QPointF(x, y)));
2919 void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
2920 qreal cp2x, qreal cp2y,
2923 m_path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
2924 state.matrix.map(QPointF(cp2x, cp2y)),
2925 state.matrix.map(QPointF(x, y)));
2928 void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
2930 QPointF p0(m_path.currentPosition());
2932 QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
2933 QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
2934 float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
2935 float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
2937 double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
2939 // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
2940 // We could have used areCollinear() here, but since we're reusing
2941 // the variables computed above later on we keep this logic.
2942 if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
2947 float tangent = radius / tan(acos(cos_phi) / 2);
2948 float factor_p1p0 = tangent / p1p0_length;
2949 QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
2951 QPointF orth_p1p0(p1p0.y(), -p1p0.x());
2952 float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
2953 float factor_ra = radius / orth_p1p0_length;
2955 // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
2956 double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
2957 if (cos_alpha < 0.f)
2958 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
2960 QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
2962 // calculate angles for addArc
2963 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
2964 float sa = acos(orth_p1p0.x() / orth_p1p0_length);
2965 if (orth_p1p0.y() < 0.f)
2968 // anticlockwise logic
2969 bool anticlockwise = false;
2971 float factor_p1p2 = tangent / p1p2_length;
2972 QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
2973 QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
2974 float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
2975 float ea = acos(orth_p1p2.x() / orth_p1p2_length);
2976 if (orth_p1p2.y() < 0)
2978 if ((sa > ea) && ((sa - ea) < Q_PI))
2979 anticlockwise = true;
2980 if ((sa < ea) && ((ea - sa) > Q_PI))
2981 anticlockwise = true;
2983 arc(p.x(), p.y(), radius, sa, ea, anticlockwise, false);
2986 void QQuickContext2D::arcTo(qreal x1, qreal y1,
2990 QPointF st = state.matrix.map(QPointF(x1, y1));
2991 QPointF end = state.matrix.map(QPointF(x2, y2));
2993 if (!m_path.elementCount()) {
2995 } else if (st == m_path.currentPosition() || st == end || !radius) {
2998 addArcTo(st, end, radius);
3002 void QQuickContext2D::rect(qreal x, qreal y,
3005 m_path.addPolygon(state.matrix.map(QRectF(x, y, w, h)));
3008 void QQuickContext2D::roundedRect(qreal x, qreal y,
3013 path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
3014 m_path.addPath(state.matrix.map(path));
3017 void QQuickContext2D::ellipse(qreal x, qreal y,
3021 path.addEllipse(x, y, w, h);
3022 m_path.addPath(state.matrix.map(path));
3025 void QQuickContext2D::text(const QString& str, qreal x, qreal y)
3028 path.addText(x, y, state.font, str);
3029 m_path.addPath(state.matrix.map(path));
3032 void QQuickContext2D::arc(qreal xc,
3042 QPointF point = state.matrix.map(QPointF(xc, yc));
3048 // In Qt we don't switch the coordinate system for degrees
3049 // and still use the 0,0 as bottom left for degrees so we need
3053 antiClockWise = !antiClockWise;
3056 float sa = DEGREES(sar);
3057 float ea = DEGREES(ear);
3061 double xs = xc - radius;
3062 double ys = yc - radius;
3063 double width = radius*2;
3064 double height = radius*2;
3065 if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
3066 // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
3067 // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
3068 // circumference of this circle.
3071 if (!antiClockWise && (ea < sa)) {
3073 } else if (antiClockWise && (sa < ea)) {
3076 //### this is also due to switched coordinate system
3077 // we would end up with a 0 span instead of 360
3078 if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
3079 qFuzzyCompare(qAbs(span), 360))) {
3082 if (!m_path.elementCount())
3083 m_path.moveTo(xs, ys);
3088 QPointF currentPos = m_path.currentPosition();
3089 QPointF startPos = QPointF(xc + radius * qCos(sar),
3090 yc - radius * qSin(sar));
3091 if (currentPos != startPos)
3092 m_path.lineTo(startPos);
3095 m_path.arcTo(xs, ys, width, height, sa, span);
3098 int baseLineOffset(QQuickContext2D::TextBaseLineType value, const QFontMetrics &metrics)
3102 case QQuickContext2D::Top:
3104 case QQuickContext2D::Alphabetic:
3105 case QQuickContext2D::Middle:
3106 case QQuickContext2D::Hanging:
3107 offset = metrics.ascent();
3109 case QQuickContext2D::Bottom:
3110 offset = metrics.height();
3116 static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
3119 if (value == QQuickContext2D::Start)
3120 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Left : QQuickContext2D::Right;
3121 else if (value == QQuickContext2D::End)
3122 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Right: QQuickContext2D::Left;
3124 case QQuickContext2D::Center:
3125 offset = metrics.width(text)/2;
3127 case QQuickContext2D::Right:
3128 offset = metrics.width(text);
3129 case QQuickContext2D::Left:
3137 QImage QQuickContext2D::createImage(const QUrl& url)
3139 return m_canvas->loadedImage(url);
3142 QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
3144 const QFontMetrics metrics(state.font);
3145 int yoffset = baseLineOffset(static_cast<QQuickContext2D::TextBaseLineType>(state.textBaseline), metrics);
3146 int xoffset = textAlignOffset(static_cast<QQuickContext2D::TextAlignType>(state.textAlign), metrics, text);
3148 QPainterPath textPath;
3150 textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
3151 textPath = state.matrix.map(textPath);
3156 bool QQuickContext2D::isPointInPath(qreal x, qreal y) const
3158 return m_path.contains(QPointF(x, y));
3161 QQuickContext2D::QQuickContext2D(QObject *parent)
3162 : QQuickCanvasContext(parent)
3163 , m_buffer(new QQuickContext2DCommandBuffer)
3168 QQuickContext2D::~QQuickContext2D()
3173 v8::Handle<v8::Object> QQuickContext2D::v8value() const
3178 QStringList QQuickContext2D::contextNames() const
3180 return QStringList() << QLatin1String("2d");
3183 void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args)
3187 m_canvas = canvasItem;
3188 m_renderTarget = canvasItem->renderTarget();
3190 // For the FBO target we only (currently) support Cooperative
3191 if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
3192 canvasItem->setRenderStrategy(QQuickCanvasItem::Cooperative);
3195 m_renderStrategy = canvasItem->renderStrategy();
3197 switch (m_renderTarget) {
3198 case QQuickCanvasItem::Image:
3199 m_texture = new QQuickContext2DImageTexture(m_renderStrategy == QQuickCanvasItem::Threaded); // ?? || Coop
3201 case QQuickCanvasItem::FramebufferObject:
3202 m_texture = new QQuickContext2DFBOTexture;
3206 m_texture->setItem(canvasItem);
3207 m_texture->setCanvasWindow(canvasItem->canvasWindow().toRect());
3208 m_texture->setTileSize(canvasItem->tileSize());
3209 m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
3210 m_texture->setSmooth(canvasItem->smooth());
3212 connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
3217 void QQuickContext2D::prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth)
3219 m_texture->canvasChanged(canvasSize, tileSize, canvasWindow, dirtyRect, smooth);
3222 void QQuickContext2D::flush()
3224 switch (m_renderStrategy) {
3225 case QQuickCanvasItem::Immediate:
3226 // Cause the texture to consume paint commands immediately
3229 case QQuickCanvasItem::Threaded:
3230 // wake up thread to consume paint commands
3233 case QQuickCanvasItem::Cooperative:
3234 // Add to the update list in SG
3235 m_canvas->update(); // FIXME
3240 // On SG render thread
3241 void QQuickContext2D::sync()
3243 if (m_renderStrategy == QQuickCanvasItem::Cooperative)
3247 QSGDynamicTexture *QQuickContext2D::texture() const
3252 QImage QQuickContext2D::toImage(const QRectF& bounds)
3254 return m_texture->toImage(bounds);
3258 QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
3260 v8::HandleScope handle_scope;
3261 v8::Context::Scope scope(engine->context());
3263 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
3264 ft->InstanceTemplate()->SetHasExternalResource(true);
3265 ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine));
3266 ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine));
3267 ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine));
3268 ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine));
3269 ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine));
3270 ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine));
3271 ft->PrototypeTemplate()->Set(v8::String::New("resetTransform"), V8FUNCTION(ctx2d_resetTransform, engine));
3272 ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine));
3273 ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine));
3274 ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine));
3275 ft->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, engine));
3276 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine));
3277 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine));
3278 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillRule"), ctx2d_fillRule, ctx2d_fillRule_set, v8::External::Wrap(engine));
3279 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine));
3280 ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
3281 ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
3282 ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
3283 ft->PrototypeTemplate()->Set(v8::String::New("createConicalGradient"), V8FUNCTION(ctx2d_createConicalGradient, engine));
3284 ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
3285 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
3286 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
3287 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine));
3288 ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine));
3289 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine));
3290 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine));
3291 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine));
3292 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine));
3293 ft->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_set, v8::External::Wrap(engine));
3294 ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine));
3295 ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine));
3296 ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine));
3297 ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine));
3298 ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine));
3299 ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine));
3300 ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine));
3301 ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine));
3302 ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine));
3303 ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine));
3304 ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine));
3305 ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine));
3306 ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine));
3307 ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine));
3308 ft->PrototypeTemplate()->Set(v8::String::New("roundedRect"), V8FUNCTION(ctx2d_roundedRect, engine));
3309 ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
3310 ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine));
3311 ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine));
3312 ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine));
3313 ft->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
3314 ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
3315 ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, engine));
3316 ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine));
3317 ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine));
3318 ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine));
3319 ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine));
3320 ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine));
3321 ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine));
3322 ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine));
3323 ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine));
3324 ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine));
3325 ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine));
3327 constructorContext = qPersistentNew(ft->GetFunction());
3329 v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
3330 ftGradient->InstanceTemplate()->SetHasExternalResource(true);
3331 ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
3332 constructorGradient = qPersistentNew(ftGradient->GetFunction());
3334 v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
3335 ftPattern->InstanceTemplate()->SetHasExternalResource(true);
3336 constructorPattern = qPersistentNew(ftPattern->GetFunction());
3338 v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
3339 ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
3340 ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
3341 ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
3342 constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
3344 v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
3345 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
3346 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
3347 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
3348 ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
3349 constructorImageData = qPersistentNew(ftImageData->GetFunction());
3352 QQuickContext2DEngineData::~QQuickContext2DEngineData()
3354 qPersistentDispose(constructorContext);
3355 qPersistentDispose(constructorGradient);
3356 qPersistentDispose(constructorPattern);
3357 qPersistentDispose(constructorImageData);
3358 qPersistentDispose(constructorPixelArray);
3361 void QQuickContext2D::popState()
3363 if (m_stateStack.isEmpty())
3366 QQuickContext2D::State newState = m_stateStack.pop();
3368 if (state.matrix != newState.matrix)
3369 buffer()->updateMatrix(newState.matrix);
3371 if (newState.globalAlpha != state.globalAlpha)
3372 buffer()->setGlobalAlpha(newState.globalAlpha);
3374 if (newState.globalCompositeOperation != state.globalCompositeOperation)
3375 buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
3377 if (newState.fillStyle != state.fillStyle)
3378 buffer()->setFillStyle(newState.fillStyle);
3380 if (newState.strokeStyle != state.strokeStyle)
3381 buffer()->setStrokeStyle(newState.strokeStyle);
3383 if (newState.lineWidth != state.lineWidth)
3384 buffer()->setLineWidth(newState.lineWidth);
3386 if (newState.lineCap != state.lineCap)
3387 buffer()->setLineCap(newState.lineCap);
3389 if (newState.lineJoin != state.lineJoin)
3390 buffer()->setLineJoin(newState.lineJoin);
3392 if (newState.miterLimit != state.miterLimit)
3393 buffer()->setMiterLimit(newState.miterLimit);
3395 if (newState.clipPath != state.clipPath) {
3396 buffer()->clip(newState.clipPath);
3399 if (newState.shadowBlur != state.shadowBlur)
3400 buffer()->setShadowBlur(newState.shadowBlur);
3402 if (newState.shadowColor != state.shadowColor)
3403 buffer()->setShadowColor(newState.shadowColor);
3405 if (newState.shadowOffsetX != state.shadowOffsetX)
3406 buffer()->setShadowOffsetX(newState.shadowOffsetX);
3408 if (newState.shadowOffsetY != state.shadowOffsetY)
3409 buffer()->setShadowOffsetY(newState.shadowOffsetY);
3412 void QQuickContext2D::pushState()
3414 m_stateStack.push(state);
3417 void QQuickContext2D::reset()
3419 QQuickContext2D::State newState;
3420 newState.matrix = QTransform();
3422 QPainterPath defaultClipPath;
3424 QRect r(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
3425 r = r.united(m_canvas->canvasWindow().toRect());
3426 defaultClipPath.addRect(r);
3427 newState.clipPath = defaultClipPath;
3428 newState.clipPath.setFillRule(Qt::WindingFill);
3430 newState.strokeStyle = QColor("#000000");
3431 newState.fillStyle = QColor("#000000");
3432 newState.fillPatternRepeatX = false;
3433 newState.fillPatternRepeatY = false;
3434 newState.strokePatternRepeatX = false;
3435 newState.strokePatternRepeatY = false;
3436 newState.fillRule = Qt::WindingFill;
3437 newState.globalAlpha = 1.0;
3438 newState.lineWidth = 1;
3439 newState.lineCap = Qt::FlatCap;
3440 newState.lineJoin = Qt::MiterJoin;
3441 newState.miterLimit = 10;
3442 newState.shadowOffsetX = 0;
3443 newState.shadowOffsetY = 0;
3444 newState.shadowBlur = 0;
3445 newState.shadowColor = qRgba(0, 0, 0, 0);
3446 newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
3447 newState.font = QFont(QLatin1String("sans-serif"), 10);
3448 newState.textAlign = QQuickContext2D::Start;
3449 newState.textBaseline = QQuickContext2D::Alphabetic;
3451 m_stateStack.clear();
3452 m_stateStack.push(newState);
3454 m_buffer->clearRect(0, 0, m_canvas->width(), m_canvas->height());
3457 void QQuickContext2D::setV8Engine(QV8Engine *engine)
3459 v8::HandleScope handle_scope;
3460 v8::Context::Scope scope(engine->context());
3462 if (m_v8engine != engine) {
3463 m_v8engine = engine;
3465 qPersistentDispose(m_v8value);
3467 if (m_v8engine == 0)
3470 QQuickContext2DEngineData *ed = engineData(engine);
3471 m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
3472 QV8Context2DResource *r = new QV8Context2DResource(engine);
3474 m_v8value->SetExternalResource(r);