1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickcontext2d_p.h"
43 #include "qquickcontext2dcommandbuffer_p.h"
44 #include "qquickcanvasitem_p.h"
45 #include <private/qquickitem_p.h>
46 #include <QtQuick/private/qquickshadereffectsource_p.h>
47 #include <QtGui/qopenglframebufferobject.h>
49 #include <QtCore/qdebug.h>
50 #include <QtQuick/private/qsgcontext_p.h>
51 #include <private/qdeclarativesvgparser_p.h>
52 #include <private/qdeclarativepath_p.h>
54 #include <private/qquickimage_p_p.h>
56 #include <QtGui/qguiapplication.h>
57 #include <qdeclarativeinfo.h>
58 #include <QtCore/qmath.h>
59 #include <private/qv8engine_p.h>
61 #include <qdeclarativeengine.h>
62 #include <private/qv8domerrors_p.h>
63 #include <QtCore/qnumeric.h>
67 \qmlclass Context2D QQuickContext2D
68 \inqmlmodule QtQuick 2
70 \brief The Context2D API allows you to draw 2d graphic shapes on the \c Canvas item.
72 The Context2D object can be created by \c Canvas item's \c getContext() method:
77 var ctx = canvas.getContext('2d');
82 The Context2D API implements the same \l {http://www.w3.org/TR/2dcontext}{W3C Canvas 2D Context API standard}
83 with some enhanced features.
85 The Context2D API provides the rendering \bold{context} which defines the methods and attributes needed to draw
86 on the \c Canvas item. The following assigns the canvas rendering context to a \c{context}
89 var context = mycanvas.getContext("2d")
92 The Context2D API renders the canvas as a coordinate system whose origin (0,0) is
93 at the top left corner, as shown in the figure below. Coordinates increase along
94 the \c{x} axis from left to right and along the \c{y} axis from top to bottom of
96 \image qml-item-canvas-context.gif
99 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
101 static const double Q_PI = 3.14159265358979323846; // pi
103 #define DEGREES(t) ((t) * 180.0 / Q_PI)
105 #define CHECK_CONTEXT(r) if (!r || !r->context || !r->context->buffer()) \
106 V8THROW_ERROR("Not a Context2D object");
108 #define CHECK_CONTEXT_SETTER(r) if (!r || !r->context || !r->context->buffer()) \
109 V8THROW_ERROR_SETTER("Not a Context2D object");
110 #define qClamp(val, min, max) qMin(qMax(val, min), max)
111 #define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
112 QColor qt_color_from_string(v8::Local<v8::Value> name)
114 v8::String::AsciiValue str(name);
117 int len = str.length();
118 //rgb/hsl color string has at least 7 characters
119 if (!p || len > 255 || len <= 7)
122 bool isRgb(false), isHsl(false), hasAlpha(false);
125 while (isspace(*p)) p++;
126 if (strncmp(p, "rgb", 3) == 0)
128 else if (strncmp(p, "hsl", 3) == 0)
133 p+=3; //skip "rgb" or "hsl"
134 hasAlpha = (*p == 'a') ? true : false;
138 if (hasAlpha) ++p; //skip "a"
140 int rh, gs, bl, alpha = 255;
143 while (isspace(*p)) p++;
144 rh = strtol(p, &p, 10);
146 rh = qRound(rh/100.0 * 255);
149 if (*p++ != ',') return QColor();
152 while (isspace(*p)) p++;
153 gs = strtol(p, &p, 10);
155 gs = qRound(gs/100.0 * 255);
158 if (*p++ != ',') return QColor();
161 while (isspace(*p)) p++;
162 bl = strtol(p, &p, 10);
164 bl = qRound(bl/100.0 * 255);
169 if (*p++!= ',') return QColor();
170 while (isspace(*p)) p++;
172 alpha = qRound(qstrtod(p, const_cast<const char **>(&p), &ok) * 255);
175 if (*p != ')') return QColor();
177 return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)));
179 return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255));
184 QFont qt_font_from_string(const QString& fontString) {
186 // ### this is simplified and incomplete
187 // ### TODO:get code from Qt webkit
188 QStringList tokens = fontString.split(QLatin1String(" "));
189 foreach (const QString &token, tokens) {
190 if (token == QLatin1String("italic"))
191 font.setItalic(true);
192 else if (token == QLatin1String("bold"))
194 else if (token.endsWith(QLatin1String("px"))) {
195 QString number = token;
196 number.remove(QLatin1String("px"));
197 //font.setPointSizeF(number.trimmed().toFloat());
198 font.setPixelSize(number.trimmed().toInt());
200 font.setFamily(token);
208 class QQuickContext2DEngineData : public QV8Engine::Deletable
211 QQuickContext2DEngineData(QV8Engine *engine);
212 ~QQuickContext2DEngineData();
214 v8::Persistent<v8::Function> constructorContext;
215 v8::Persistent<v8::Function> constructorGradient;
216 v8::Persistent<v8::Function> constructorPattern;
217 v8::Persistent<v8::Function> constructorPixelArray;
218 v8::Persistent<v8::Function> constructorImageData;
221 V8_DEFINE_EXTENSION(QQuickContext2DEngineData, engineData)
223 class QV8Context2DResource : public QV8ObjectResource
225 V8_RESOURCE_TYPE(Context2DType)
227 QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
228 QQuickContext2D* context;
231 class QV8Context2DStyleResource : public QV8ObjectResource
233 V8_RESOURCE_TYPE(Context2DStyleType)
235 QV8Context2DStyleResource(QV8Engine *e)
236 : QV8ObjectResource(e)
237 , patternRepeatX(false)
238 , patternRepeatY(false)
241 bool patternRepeatX:1;
242 bool patternRepeatY:1;
245 class QV8Context2DPixelArrayResource : public QV8ObjectResource
247 V8_RESOURCE_TYPE(Context2DPixelArrayType)
249 QV8Context2DPixelArrayResource(QV8Engine *e) : QV8ObjectResource(e) {}
254 QImage qt_image_convolute_filter(const QImage& src, const QVector<qreal>& weights, int radius = 0)
256 int sides = radius ? radius : qRound(qSqrt(weights.size()));
257 int half = qFloor(sides/2);
259 QImage dst = QImage(src.size(), src.format());
261 int h = src.height();
262 for (int y = 0; y < dst.height(); ++y) {
263 QRgb *dr = (QRgb*)dst.scanLine(y);
264 for (int x = 0; x < dst.width(); ++x) {
265 unsigned char* dRgb = ((unsigned char*)&dr[x]);
266 unsigned char red=0, green=0, blue=0, alpha=0;
270 for (int cy=0; cy<sides; cy++) {
271 for (int cx=0; cx<sides; cx++) {
272 int scy = sy + cy - half;
273 int scx = sx + cx - half;
274 if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
275 const QRgb *sr = (const QRgb*)(src.constScanLine(scy));
276 const unsigned char* sRgb = ((const unsigned char*)&sr[scx]);
277 qreal wt = radius ? weights[0] : weights[cy*sides+cx];
279 green += sRgb[1] * wt;
280 blue += sRgb[2] * wt;
281 alpha += sRgb[3] * wt;
294 void qt_image_boxblur(QImage& image, int radius, bool quality)
296 int passes = quality? 3: 1;
297 for (int i=0; i < passes; i++) {
298 image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0/(radius * radius * 1.0), radius);
302 static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
304 if (compositeOperator == QLatin1String("source-over")) {
305 return QPainter::CompositionMode_SourceOver;
306 } else if (compositeOperator == QLatin1String("source-out")) {
307 return QPainter::CompositionMode_SourceOut;
308 } else if (compositeOperator == QLatin1String("source-in")) {
309 return QPainter::CompositionMode_SourceIn;
310 } else if (compositeOperator == QLatin1String("source-atop")) {
311 return QPainter::CompositionMode_SourceAtop;
312 } else if (compositeOperator == QLatin1String("destination-atop")) {
313 return QPainter::CompositionMode_DestinationAtop;
314 } else if (compositeOperator == QLatin1String("destination-in")) {
315 return QPainter::CompositionMode_DestinationIn;
316 } else if (compositeOperator == QLatin1String("destination-out")) {
317 return QPainter::CompositionMode_DestinationOut;
318 } else if (compositeOperator == QLatin1String("destination-over")) {
319 return QPainter::CompositionMode_DestinationOver;
320 } else if (compositeOperator == QLatin1String("lighter")) {
321 return QPainter::CompositionMode_Lighten;
322 } else if (compositeOperator == QLatin1String("copy")) {
323 return QPainter::CompositionMode_Source;
324 } else if (compositeOperator == QLatin1String("xor")) {
325 return QPainter::CompositionMode_Xor;
326 } else if (compositeOperator == QLatin1String("qt-clear")) {
327 return QPainter::CompositionMode_Clear;
328 } else if (compositeOperator == QLatin1String("qt-destination")) {
329 return QPainter::CompositionMode_Destination;
330 } else if (compositeOperator == QLatin1String("qt-multiply")) {
331 return QPainter::CompositionMode_Multiply;
332 } else if (compositeOperator == QLatin1String("qt-screen")) {
333 return QPainter::CompositionMode_Screen;
334 } else if (compositeOperator == QLatin1String("qt-overlay")) {
335 return QPainter::CompositionMode_Overlay;
336 } else if (compositeOperator == QLatin1String("qt-darken")) {
337 return QPainter::CompositionMode_Darken;
338 } else if (compositeOperator == QLatin1String("qt-lighten")) {
339 return QPainter::CompositionMode_Lighten;
340 } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
341 return QPainter::CompositionMode_ColorDodge;
342 } else if (compositeOperator == QLatin1String("qt-color-burn")) {
343 return QPainter::CompositionMode_ColorBurn;
344 } else if (compositeOperator == QLatin1String("qt-hard-light")) {
345 return QPainter::CompositionMode_HardLight;
346 } else if (compositeOperator == QLatin1String("qt-soft-light")) {
347 return QPainter::CompositionMode_SoftLight;
348 } else if (compositeOperator == QLatin1String("qt-difference")) {
349 return QPainter::CompositionMode_Difference;
350 } else if (compositeOperator == QLatin1String("qt-exclusion")) {
351 return QPainter::CompositionMode_Exclusion;
353 return QPainter::CompositionMode_SourceOver;
356 static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
359 case QPainter::CompositionMode_SourceOver:
360 return QLatin1String("source-over");
361 case QPainter::CompositionMode_DestinationOver:
362 return QLatin1String("destination-over");
363 case QPainter::CompositionMode_Clear:
364 return QLatin1String("qt-clear");
365 case QPainter::CompositionMode_Source:
366 return QLatin1String("copy");
367 case QPainter::CompositionMode_Destination:
368 return QLatin1String("qt-destination");
369 case QPainter::CompositionMode_SourceIn:
370 return QLatin1String("source-in");
371 case QPainter::CompositionMode_DestinationIn:
372 return QLatin1String("destination-in");
373 case QPainter::CompositionMode_SourceOut:
374 return QLatin1String("source-out");
375 case QPainter::CompositionMode_DestinationOut:
376 return QLatin1String("destination-out");
377 case QPainter::CompositionMode_SourceAtop:
378 return QLatin1String("source-atop");
379 case QPainter::CompositionMode_DestinationAtop:
380 return QLatin1String("destination-atop");
381 case QPainter::CompositionMode_Xor:
382 return QLatin1String("xor");
383 case QPainter::CompositionMode_Plus:
384 return QLatin1String("plus");
385 case QPainter::CompositionMode_Multiply:
386 return QLatin1String("qt-multiply");
387 case QPainter::CompositionMode_Screen:
388 return QLatin1String("qt-screen");
389 case QPainter::CompositionMode_Overlay:
390 return QLatin1String("qt-overlay");
391 case QPainter::CompositionMode_Darken:
392 return QLatin1String("qt-darken");
393 case QPainter::CompositionMode_Lighten:
394 return QLatin1String("lighter");
395 case QPainter::CompositionMode_ColorDodge:
396 return QLatin1String("qt-color-dodge");
397 case QPainter::CompositionMode_ColorBurn:
398 return QLatin1String("qt-color-burn");
399 case QPainter::CompositionMode_HardLight:
400 return QLatin1String("qt-hard-light");
401 case QPainter::CompositionMode_SoftLight:
402 return QLatin1String("qt-soft-light");
403 case QPainter::CompositionMode_Difference:
404 return QLatin1String("qt-difference");
405 case QPainter::CompositionMode_Exclusion:
406 return QLatin1String("qt-exclusion");
414 static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
416 QQuickContext2DEngineData *ed = engineData(engine);
417 v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
418 QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
419 if (image.isNull()) {
420 r->image = QImage(w, h, QImage::Format_ARGB32);
421 r->image.fill(0x00000000);
423 Q_ASSERT(image.width() == w && image.height() == h);
424 r->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
426 v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
427 pixelData->SetExternalResource(r);
429 imageData->SetInternalField(0, pixelData);
433 //static script functions
436 \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
437 Holds the canvas item that the context paints on.
439 This property is read only.
441 static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
443 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
447 QV8Engine *engine = V8ENGINE_ACCESSOR();
449 return engine->newQObject(r->context->canvas());
453 \qmlmethod object QtQuick2::Context2D::restore()
454 Pops the top state on the stack, restoring the context to that state.
456 \sa QtQuick2::Context2D::save()
458 static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
460 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
463 r->context->popState();
468 \qmlmethod object QtQuick2::Context2D::reset()
469 Resets the context state and properties to the default values.
471 static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
473 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
477 r->context->m_path = QPainterPath();
478 r->context->m_path.setFillRule(Qt::WindingFill);
484 \qmlmethod object QtQuick2::Context2D::save()
485 Pushes the current state onto the state stack.
487 Before changing any state attributes, you should save the current state
488 for future reference. The context maintains a stack of drawing states.
489 Each state consists of the current transformation matrix, clipping region,
490 and values of the following attributes:
492 \o\a QtQuick2::Context2D::strokeStyle
493 \o\a QtQuick2::Context2D::fillStyle
494 \o\a QtQuick2::Context2D::fillRule
495 \o\a QtQuick2::Context2D::globalAlpha
496 \o\a QtQuick2::Context2D::lineWidth
497 \o\a QtQuick2::Context2D::lineCap
498 \o\a QtQuick2::Context2D::lineJoin
499 \o\a QtQuick2::Context2D::miterLimit
500 \o\a QtQuick2::Context2D::shadowOffsetX
501 \o\a QtQuick2::Context2D::shadowOffsetY
502 \o\a QtQuick2::Context2D::shadowBlur
503 \o\a QtQuick2::Context2D::shadowColor
504 \o\a QtQuick2::Context2D::globalCompositeOperation
505 \o\a QtQuick2::Context2D::font
506 \o\a QtQuick2::Context2D::textAlign
507 \o\a QtQuick2::Context2D::textBaseline
510 The current path is NOT part of the drawing state. The path can be reset by
511 invoking the \a QtQuick2::Context2D::beginPath() method.
513 static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
515 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
518 r->context->pushState();
525 \qmlmethod object QtQuick2::Context2D::rotate(real angle)
526 Rotate the canvas around the current origin by \c angle in radians and clockwise direction.
528 ctx.rotate(Math.PI/2);
530 \image qml-item-canvas-rotate.png
532 The rotation transformation matrix is as follows:
534 \image qml-item-canvas-math-rotate.png
536 where the \c angle of rotation is in radians.
539 static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
541 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
544 if (args.Length() == 1) {
545 qreal angle = args[0]->NumberValue();
546 if (!qIsFinite(angle))
549 r->context->state.matrix.rotate(DEGREES(angle));
550 r->context->buffer()->updateMatrix(r->context->state.matrix);
557 \qmlmethod object QtQuick2::Context2D::scale(real x, real y)
558 Increases or decreases the size of each unit in the canvas grid by multiplying the scale factors
559 to the current tranform matrix.
560 Where \c x is the scale factor in the horizontal direction and \c y is the scale factor in the
562 The following code doubles the horizontal size of an object drawn on the canvas and half its
567 \image qml-item-canvas-scale.png
570 static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
572 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
576 if (args.Length() == 2) {
578 x = args[0]->NumberValue();
579 y = args[1]->NumberValue();
580 if (!qIsFinite(x) || !qIsFinite(y))
583 r->context->state.matrix.scale(x, y);
584 r->context->buffer()->updateMatrix(r->context->state.matrix);
591 \qmlmethod object QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
592 Changes the transformation matrix to the matrix given by the arguments as described below.
594 Modifying the transformation matrix directly enables you to perform scaling,
595 rotating, and translating transformations in a single step.
597 Each point on the canvas is multiplied by the matrix before anything is
598 drawn. The \l{HTML5 Canvas API} defines the transformation matrix as:
600 \image qml-item-canvas-math.png
603 \o \c{a} is the scale factor in the horizontal (x) direction
604 \image qml-item-canvas-scalex.png
605 \o \c{c} is the skew factor in the x direction
606 \image qml-item-canvas-canvas-skewx.png
607 \o \c{e} is the translation in the x direction
608 \image qml-item-canvas-canvas-translate.png
609 \o \c{b} is the skew factor in the y (vertical) direction
610 \image qml-item-canvas-canvas-skewy.png
611 \o \c{d} is the scale factor in the y direction
612 \image qml-item-canvas-canvas-scaley.png
613 \o \c{f} is the translation in the y direction
614 \image qml-item-canvas-canvas-translatey.png
615 \o the last row remains constant
617 The scale factors and skew factors are multiples; \c{e} and \c{f} are
618 coordinate space units, just like the units in the \a QtQuick2::Context2D::translate(x,y)
621 \sa QtQuick2::Context2D::transform()
623 static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
625 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
629 if (args.Length() == 6) {
630 qreal a = args[0]->NumberValue();
631 qreal b = args[1]->NumberValue();
632 qreal c = args[2]->NumberValue();
633 qreal d = args[3]->NumberValue();
634 qreal e = args[4]->NumberValue();
635 qreal f = args[5]->NumberValue();
645 r->context->state.matrix = QTransform(a, b, c, d, e, f);
646 r->context->buffer()->updateMatrix(r->context->state.matrix);
653 \qmlmethod object QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
654 This method is very similar to \a QtQuick2::Context2D::setTransform(), but instead of replacing the old
655 tranform matrix, this method applies the given tranform matrix to the current matrix by mulitplying to it.
657 The \a setTransform(a, b, c, d, e, f) method actually resets the current transform to the identity matrix,
658 and then invokes the transform(a, b, c, d, e, f) method with the same arguments.
660 \sa QtQuick2::Context2D::setTransform()
662 static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
664 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
668 if (args.Length() == 6) {
669 qreal a = args[0]->NumberValue();
670 qreal b = args[1]->NumberValue();
671 qreal c = args[2]->NumberValue();
672 qreal d = args[3]->NumberValue();
673 qreal e = args[4]->NumberValue();
674 qreal f = args[5]->NumberValue();
684 r->context->state.matrix *= QTransform(a, b, c, d, e, f);
685 r->context->buffer()->updateMatrix(r->context->state.matrix);
692 \qmlmethod object QtQuick2::Context2D::translate(real x, real y)
693 Translates the origin of the canvas to point (\c x, \c y).
695 \c x is the horizontal distance that the origin is translated, in coordinate space units,
696 \c y is the vertical distance that the origin is translated, in coordinate space units.
697 Translating the origin enables you to draw patterns of different objects on the canvas
698 without having to measure the coordinates manually for each shape.
700 static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
702 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
706 if (args.Length() == 2) {
707 qreal x = args[0]->NumberValue();
708 qreal y = args[1]->NumberValue();
710 if (!qIsFinite(x) || !qIsFinite(y))
713 r->context->state.matrix.translate(x, y);
714 r->context->buffer()->updateMatrix(r->context->state.matrix);
722 \qmlmethod object QtQuick2::Context2D::resetTransform()
723 Reset the transformation matrix to default value.
725 \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform(), QtQuick2::Context2D::reset()
727 static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
729 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
732 r->context->state.matrix = QTransform();
733 r->context->buffer()->updateMatrix(r->context->state.matrix);
740 \qmlmethod object QtQuick2::Context2D::shear(real sh, real sv )
741 Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
743 static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
745 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
748 if (args.Length() == 2) {
749 qreal sh = args[0]->NumberValue();
750 qreal sv = args[1]->NumberValue();
752 if (!qIsFinite(sh) || !qIsFinite(sv))
755 r->context->state.matrix.shear(sh, sv);
756 r->context->buffer()->updateMatrix(r->context->state.matrix);
763 \qmlproperty real QtQuick2::Context2D::globalAlpha
764 Holds the the current alpha value applied to rendering operations.
765 The value must be in the range from 0.0 (fully transparent) to 1.0 (fully opque).
766 The default value is 1.0.
768 static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
770 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
773 return v8::Number::New(r->context->state.globalAlpha);
776 static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
778 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
779 CHECK_CONTEXT_SETTER(r)
781 qreal globalAlpha = value->NumberValue();
783 if (!qIsFinite(globalAlpha))
786 if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
787 r->context->state.globalAlpha = globalAlpha;
788 r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
793 \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
794 Holds the the current the current composition operation, from the list below:
796 \o source-atop - A atop B. Display the source image wherever both images are opaque.
797 Display the destination image wherever the destination image is opaque but the source image is transparent.
798 Display transparency elsewhere.
799 \o source-in - A in B. Display the source image wherever both the source image and destination image are opaque.
800 Display transparency elsewhere.
801 \o source-out - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
802 Display transparency elsewhere.
803 \o source-over - (default) A over B. Display the source image wherever the source image is opaque.
804 Display the destination image elsewhere.
805 \o destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
806 \o destination-in - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
807 \o destination-out - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
808 \o destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
809 \o lighter - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
810 \o copy - A (B is ignored). Display the source image instead of the destination image.
811 \o xor - A xor B. Exclusive OR of the source image and destination image.
814 Additionally, this property also accepts the compositon modes listed in \a {QPainter::CompositionMode}. According to the W3C standard, these
815 extension composition modes are provided as "vendorName-operationName" syntax, for example: \c {QPainter::CompositionMode_Exclusion} is porvided as
818 static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
820 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
824 QV8Engine *engine = V8ENGINE_ACCESSOR();
826 return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
829 static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
831 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
832 CHECK_CONTEXT_SETTER(r)
834 QV8Engine *engine = V8ENGINE_ACCESSOR();
837 QString mode = engine->toString(value);
838 QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
839 if (cm == QPainter::CompositionMode_SourceOver && mode != QStringLiteral("source-over"))
842 if (cm != r->context->state.globalCompositeOperation) {
843 r->context->state.globalCompositeOperation = cm;
844 r->context->buffer()->setGlobalCompositeOperation(cm);
850 \qmlproperty variant QtQuick2::Context2D::fillStyle
851 Holds the current style used for filling shapes.
852 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object. Invalid values are ignored.
853 This property accepts several color syntaxes:
855 \o 'rgb(red, green, blue)' - for example: 'rgb(255, 100, 55)' or 'rgb(100%, 70%, 30%)'
856 \o 'rgba(red, green, blue, alpha)' - for example: 'rgb(255, 100, 55, 1.0)' or 'rgb(100%, 70%, 30%, 0.5)'
857 \o 'hsl(hue, saturation, lightness)'
858 \o 'hsla(hue, saturation, lightness, alpha)'
859 \o '#RRGGBB' - for example: '#00FFCC'
860 \o Qt.rgba(red, green, blue, alpha) - for example: Qt.rgba(0.3, 0.7, 1, 1.0)
862 If the \a fillStyle or \a strokeStyle is assigned many times in a loop, the last Qt.rgba() syntax should be chosen, as it has the
863 best performance, because it's already a valid QColor value, does not need to be parsed everytime.
865 The default value is '#000000'.
866 \sa QtQuick2::Context2D::createLinearGradient
867 \sa QtQuick2::Context2D::createRadialGradient
868 \sa QtQuick2::Context2D::createPattern
869 \sa QtQuick2::Context2D::strokeStyle
871 static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
873 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
876 QV8Engine *engine = V8ENGINE_ACCESSOR();
878 QColor color = r->context->state.fillStyle.color();
879 if (color.isValid()) {
880 if (color.alpha() == 255)
881 return engine->toString(color.name());
882 QString alphaString = QString::number(color.alphaF(), 'f');
883 while (alphaString.endsWith(QLatin1Char('0')))
885 if (alphaString.endsWith(QLatin1Char('.')))
886 alphaString += QLatin1Char('0');
887 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
889 return r->context->m_fillStyle;
892 static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
894 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
895 CHECK_CONTEXT_SETTER(r)
897 QV8Engine *engine = V8ENGINE_ACCESSOR();
899 if (value->IsObject()) {
900 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
901 if (color.isValid()) {
902 r->context->state.fillStyle = color;
903 r->context->buffer()->setFillStyle(color);
904 r->context->m_fillStyle = value;
906 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
907 if (style && style->brush != r->context->state.fillStyle) {
908 r->context->state.fillStyle = style->brush;
909 r->context->buffer()->setFillStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
910 r->context->m_fillStyle = value;
911 r->context->state.fillPatternRepeatX = style->patternRepeatX;
912 r->context->state.fillPatternRepeatY = style->patternRepeatY;
915 } else if (value->IsString()) {
916 QColor color = qt_color_from_string(value);
917 if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
918 r->context->state.fillStyle = QBrush(color);
919 r->context->buffer()->setFillStyle(r->context->state.fillStyle);
920 r->context->m_fillStyle = value;
925 \qmlproperty enumeration QtQuick2::Context2D::fillRule
926 Holds the current fill rule used for filling shapes. The following fill rules supported:
931 Note: Unlike the \a QPainterPath, the Canvas API uses the winding fill as the default fill rule.
932 The fillRule property is part of the context rendering state.
934 \sa QtQuick2::Context2D::fillStyle
936 static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
938 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
940 QV8Engine *engine = V8ENGINE_ACCESSOR();
942 return engine->fromVariant(r->context->state.fillRule);
945 static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
947 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
948 CHECK_CONTEXT_SETTER(r)
950 QV8Engine *engine = V8ENGINE_ACCESSOR();
952 if ((value->IsString() && engine->toString(value) == QStringLiteral("WindingFill"))
953 ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
954 r->context->state.fillRule = Qt::WindingFill;
955 } else if ((value->IsString() && engine->toString(value) == QStringLiteral("OddEvenFill"))
956 ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
957 r->context->state.fillRule = Qt::OddEvenFill;
961 r->context->m_path.setFillRule(r->context->state.fillRule);
964 \qmlproperty variant QtQuick2::Context2D::strokeStyle
965 Holds the current color or style to use for the lines around shapes,
966 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object.
967 Invalid values are ignored.
969 The default value is '#000000'.
971 \sa QtQuick2::Context2D::createLinearGradient
972 \sa QtQuick2::Context2D::createRadialGradient
973 \sa QtQuick2::Context2D::createPattern
974 \sa QtQuick2::Context2D::fillStyle
976 v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
978 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
981 QV8Engine *engine = V8ENGINE_ACCESSOR();
983 QColor color = r->context->state.strokeStyle.color();
984 if (color.isValid()) {
985 if (color.alpha() == 255)
986 return engine->toString(color.name());
987 QString alphaString = QString::number(color.alphaF(), 'f');
988 while (alphaString.endsWith(QLatin1Char('0')))
990 if (alphaString.endsWith(QLatin1Char('.')))
991 alphaString += QLatin1Char('0');
992 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
994 return r->context->m_strokeStyle;
997 static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
999 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1000 CHECK_CONTEXT_SETTER(r)
1002 QV8Engine *engine = V8ENGINE_ACCESSOR();
1004 if (value->IsObject()) {
1005 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
1006 if (color.isValid()) {
1007 r->context->state.fillStyle = color;
1008 r->context->buffer()->setStrokeStyle(color);
1009 r->context->m_strokeStyle = value;
1011 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
1012 if (style && style->brush != r->context->state.strokeStyle) {
1013 r->context->state.strokeStyle = style->brush;
1014 r->context->buffer()->setStrokeStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
1015 r->context->m_strokeStyle = value;
1016 r->context->state.strokePatternRepeatX = style->patternRepeatX;
1017 r->context->state.strokePatternRepeatY = style->patternRepeatY;
1021 } else if (value->IsString()) {
1022 QColor color = qt_color_from_string(value);
1023 if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
1024 r->context->state.strokeStyle = QBrush(color);
1025 r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
1026 r->context->m_strokeStyle = value;
1032 \qmlmethod object QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
1033 Returns a CanvasGradient object that represents a linear gradient that transitions the color along a line between
1034 the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
1036 A gradient is a smooth transition between colors. There are two types of gradients: linear and radial.
1037 Gradients must have two or more color stops, representing color shifts positioned from 0 to 1 between
1038 to the gradient's starting and end points or circles.
1040 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1041 \sa QtQuick2::Context2D::createRadialGradient
1042 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
1043 \sa QtQuick2::Context2D::createPattern
1044 \sa QtQuick2::Context2D::fillStyle
1045 \sa QtQuick2::Context2D::strokeStyle
1048 static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
1050 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1054 QV8Engine *engine = V8ENGINE();
1056 if (args.Length() == 4) {
1057 QQuickContext2DEngineData *ed = engineData(engine);
1058 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1059 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1060 qreal x0 = args[0]->NumberValue();
1061 qreal y0 = args[1]->NumberValue();
1062 qreal x1 = args[2]->NumberValue();
1063 qreal y1 = args[3]->NumberValue();
1069 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
1071 r->brush = QLinearGradient(x0, y0, x1, y1);
1072 gradient->SetExternalResource(r);
1080 \qmlmethod object QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
1081 Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
1082 origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
1084 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1085 \sa QtQuick2::Context2D::createLinearGradient
1086 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
1087 \sa QtQuick2::Context2D::createPattern
1088 \sa QtQuick2::Context2D::fillStyle
1089 \sa QtQuick2::Context2D::strokeStyle
1092 static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
1094 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1098 QV8Engine *engine = V8ENGINE();
1100 if (args.Length() == 6) {
1101 QQuickContext2DEngineData *ed = engineData(engine);
1102 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1103 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1105 qreal x0 = args[0]->NumberValue();
1106 qreal y0 = args[1]->NumberValue();
1107 qreal r0 = args[2]->NumberValue();
1108 qreal x1 = args[3]->NumberValue();
1109 qreal y1 = args[4]->NumberValue();
1110 qreal r1 = args[5]->NumberValue();
1118 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
1120 if (r0 < 0 || r1 < 0)
1121 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
1124 r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
1125 gradient->SetExternalResource(r);
1133 \qmlmethod object QtQuick2::Context2D::createConicalGradient(real x, real y, real angle)
1134 Returns a CanvasGradient object that represents a conical gradient that interpolate colors counter-clockwise around a center point (\c x, \c y)
1135 with start angle \c angle in units of radians.
1137 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1138 \sa QtQuick2::Context2D::createLinearGradient
1139 \sa QtQuick2::Context2D::ctx2d_createRadialGradient
1140 \sa QtQuick2::Context2D::createPattern
1141 \sa QtQuick2::Context2D::fillStyle
1142 \sa QtQuick2::Context2D::strokeStyle
1145 static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &args)
1147 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1151 QV8Engine *engine = V8ENGINE();
1153 if (args.Length() == 6) {
1154 QQuickContext2DEngineData *ed = engineData(engine);
1155 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1156 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1158 qreal x = args[0]->NumberValue();
1159 qreal y = args[1]->NumberValue();
1160 qreal angle = DEGREES(args[2]->NumberValue());
1161 if (!qIsFinite(x) || !qIsFinite(y))
1162 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
1164 if (!qIsFinite(angle))
1165 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
1167 r->brush = QConicalGradient(x, y, angle);
1168 gradient->SetExternalResource(r);
1175 \qmlmethod variant createPattern(Color color, enumeration patternMode)
1176 This is a overload function.
1177 Returns a CanvasPattern object that uses the given \c color and \c patternMode.
1178 The valid pattern modes are:
1193 \o Qt.DiagCrossPattern
1198 \qmlmethod variant createPattern(Image image, string repetition)
1199 Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
1201 The \a image parameter must be a valid Image item, a valid \a QtQuick2::CanvasImageData object or loaded image url, if there is no image data, throws an INVALID_STATE_ERR exception.
1203 The allowed values for \a repetition are:
1206 \o "repeat" - both directions
1207 \o "repeat-x - horizontal only
1208 \o "repeat-y" - vertical only
1209 \o "no-repeat" - neither
1212 If the repetition argument is empty or null, the value "repeat" is used.
1214 \sa QtQuick2::Context2D::strokeStyle
1215 \sa QtQuick2::Context2D::fillStyle
1217 static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
1219 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1223 QV8Engine *engine = V8ENGINE();
1225 if (args.Length() == 2) {
1226 QQuickContext2DEngineData *ed = engineData(engine);
1227 QV8Context2DStyleResource *styleResouce = new QV8Context2DStyleResource(engine);
1229 QColor color = engine->toVariant(args[0], qMetaTypeId<QColor>()).value<QColor>();
1230 if (color.isValid()) {
1231 int patternMode = args[1]->IntegerValue();
1232 Qt::BrushStyle style = Qt::SolidPattern;
1233 if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
1234 style = static_cast<Qt::BrushStyle>(patternMode);
1236 styleResouce->brush = QBrush(color, style);
1238 QImage patternTexture;
1240 if (args[0]->IsObject()) {
1241 QV8Context2DPixelArrayResource *pixelData = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->Get(v8::String::New("data"))->ToObject());
1243 patternTexture = pixelData->image;
1246 patternTexture = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
1249 if (!patternTexture.isNull()) {
1250 styleResouce->brush.setTextureImage(patternTexture);
1252 QString repetition = engine->toString(args[1]);
1253 if (repetition == QStringLiteral("repeat") || repetition.isEmpty()) {
1254 styleResouce->patternRepeatX = true;
1255 styleResouce->patternRepeatY = true;
1256 } else if (repetition == QStringLiteral("repeat-x")) {
1257 styleResouce->patternRepeatX = true;
1258 } else if (repetition == QStringLiteral("repeat-y")) {
1259 styleResouce->patternRepeatY = true;
1260 } else if (repetition == QStringLiteral("no-repeat")) {
1261 styleResouce->patternRepeatY = false;
1262 styleResouce->patternRepeatY = false;
1264 //TODO: exception: SYNTAX_ERR
1270 v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
1271 pattern->SetExternalResource(styleResouce);
1275 return v8::Undefined();
1280 \qmlproperty string QtQuick2::Context2D::lineCap
1281 Holds the the current line cap style.
1282 The possible line cap styles are:
1284 \o butt - the end of each line has a flat edge perpendicular to the direction of the line, this is the default line cap value.
1285 \o round - a semi-circle with the diameter equal to the width of the line must then be added on to the end of the line.
1286 \o square - a rectangle with the length of the line width and the width of half the line width, placed flat against the edge perpendicular to the direction of the line.
1288 Other values are ignored.
1290 v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
1292 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1296 QV8Engine *engine = V8ENGINE_ACCESSOR();
1297 switch (r->context->state.lineCap) {
1299 return engine->toString(QLatin1String("round"));
1301 return engine->toString(QLatin1String("butt"));
1303 return engine->toString(QLatin1String("square"));
1307 return engine->toString(QLatin1String("butt"));;
1310 static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1312 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1313 CHECK_CONTEXT_SETTER(r)
1315 QV8Engine *engine = V8ENGINE_ACCESSOR();
1317 QString lineCap = engine->toString(value);
1318 Qt::PenCapStyle cap;
1319 if (lineCap == QLatin1String("round"))
1321 else if (lineCap == QLatin1String("butt"))
1323 else if (lineCap == QLatin1String("square"))
1324 cap = Qt::SquareCap;
1328 if (cap != r->context->state.lineCap) {
1329 r->context->state.lineCap = cap;
1330 r->context->buffer()->setLineCap(cap);
1335 \qmlproperty string QtQuick2::Context2D::lineJoin
1336 Holds the the current line join style. A join exists at any point in a subpath
1337 shared by two consecutive lines. When a subpath is closed, then a join also exists
1338 at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
1340 The possible line join styles are:
1342 \o bevel - this is all that is rendered at joins.
1343 \o round - a filled arc connecting the two aforementioned corners of the join, abutting (and not overlapping) the aforementioned triangle, with the diameter equal to the line width and the origin at the point of the join, must be rendered at joins.
1344 \o miter - a second filled triangle must (if it can given the miter length) be rendered at the join, this is the default line join style.
1346 Other values are ignored.
1348 v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
1350 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1354 QV8Engine *engine = V8ENGINE_ACCESSOR();
1355 switch (r->context->state.lineJoin) {
1357 return engine->toString(QLatin1String("round"));
1359 return engine->toString(QLatin1String("bevel"));
1361 return engine->toString(QLatin1String("miter"));
1365 return engine->toString(QLatin1String("miter"));
1368 static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1370 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1371 CHECK_CONTEXT_SETTER(r)
1373 QV8Engine *engine = V8ENGINE_ACCESSOR();
1375 QString lineJoin = engine->toString(value);
1376 Qt::PenJoinStyle join;
1377 if (lineJoin == QLatin1String("round"))
1378 join = Qt::RoundJoin;
1379 else if (lineJoin == QLatin1String("bevel"))
1380 join = Qt::BevelJoin;
1381 else if (lineJoin == QLatin1String("miter"))
1382 join = Qt::MiterJoin;
1386 if (join != r->context->state.lineJoin) {
1387 r->context->state.lineJoin = join;
1388 r->context->buffer()->setLineJoin(join);
1393 \qmlproperty real QtQuick2::Context2D::lineWidth
1394 Holds the the current line width. Values that are not finite values greater than zero are ignored.
1396 v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
1398 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1402 return v8::Number::New(r->context->state.lineWidth);
1405 static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1407 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1408 CHECK_CONTEXT_SETTER(r)
1410 qreal w = value->NumberValue();
1412 if (w > 0 && qIsFinite(w) && w != r->context->state.lineWidth) {
1413 r->context->state.lineWidth = w;
1414 r->context->buffer()->setLineWidth(w);
1419 \qmlproperty real QtQuick2::Context2D::miterLimit
1420 Holds the current miter limit ratio.
1421 The default miter limit value is 10.0.
1423 v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
1425 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1429 return v8::Number::New(r->context->state.miterLimit);
1432 static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1434 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1435 CHECK_CONTEXT_SETTER(r)
1437 qreal ml = value->NumberValue();
1439 if (ml > 0 && qIsFinite(ml) && ml != r->context->state.miterLimit) {
1440 r->context->state.miterLimit = ml;
1441 r->context->buffer()->setMiterLimit(ml);
1447 \qmlproperty real QtQuick2::Context2D::shadowBlur
1448 Holds the current level of blur applied to shadows
1450 v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
1452 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1456 return v8::Number::New(r->context->state.shadowBlur);
1459 static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1461 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1462 CHECK_CONTEXT_SETTER(r)
1463 qreal blur = value->NumberValue();
1465 if (blur > 0 && qIsFinite(blur) && blur != r->context->state.shadowBlur) {
1466 r->context->state.shadowBlur = blur;
1467 r->context->buffer()->setShadowBlur(blur);
1472 \qmlproperty string QtQuick2::Context2D::shadowColor
1473 Holds the current shadow color.
1475 v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
1477 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1481 QV8Engine *engine = V8ENGINE_ACCESSOR();
1483 return engine->toString(r->context->state.shadowColor.name());
1486 static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1488 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1489 CHECK_CONTEXT_SETTER(r)
1491 QColor color = qt_color_from_string(value);
1493 if (color.isValid() && color != r->context->state.shadowColor) {
1494 r->context->state.shadowColor = color;
1495 r->context->buffer()->setShadowColor(color);
1501 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
1502 Holds the current shadow offset in the positive horizontal distance.
1504 \sa QtQuick2::Context2D::shadowOffsetY
1506 v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
1508 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1512 return v8::Number::New(r->context->state.shadowOffsetX);
1515 static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1517 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1518 CHECK_CONTEXT_SETTER(r)
1520 qreal offsetX = value->NumberValue();
1521 if (qIsFinite(offsetX) && offsetX != r->context->state.shadowOffsetX) {
1522 r->context->state.shadowOffsetX = offsetX;
1523 r->context->buffer()->setShadowOffsetX(offsetX);
1527 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
1528 Holds the current shadow offset in the positive vertical distance.
1530 \sa QtQuick2::Context2D::shadowOffsetX
1532 v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
1534 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1538 return v8::Number::New(r->context->state.shadowOffsetY);
1541 static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1543 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1544 CHECK_CONTEXT_SETTER(r)
1546 qreal offsetY = value->NumberValue();
1547 if (qIsFinite(offsetY) && offsetY != r->context->state.shadowOffsetY) {
1548 r->context->state.shadowOffsetY = offsetY;
1549 r->context->buffer()->setShadowOffsetY(offsetY);
1553 v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
1555 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1557 return r->context->m_v8path;
1560 static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1562 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1563 CHECK_CONTEXT_SETTER(r)
1564 QV8Engine *engine = V8ENGINE_ACCESSOR();
1566 r->context->beginPath();
1567 if (value->IsObject()) {
1568 QDeclarativePath* path = qobject_cast<QDeclarativePath*>(engine->toQObject(value));
1570 r->context->m_path = path->path();
1572 QString path = engine->toString(value->ToString());
1573 QDeclarativeSvgParser::parsePathDataFast(path, r->context->m_path);
1575 r->context->m_v8path = value;
1580 \qmlmethod object QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
1581 Clears all pixels on the canvas in the given rectangle to transparent black.
1583 static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
1585 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1589 if (args.Length() == 4) {
1590 qreal x = args[0]->NumberValue();
1591 qreal y = args[1]->NumberValue();
1592 qreal w = args[2]->NumberValue();
1593 qreal h = args[3]->NumberValue();
1595 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
1598 r->context->buffer()->clearRect(x, y, w, h);
1604 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1605 Paint the specified rectangular area using the fillStyle.
1607 \sa QtQuick2::Context2D::fillStyle
1609 static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
1611 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1614 if (args.Length() == 4) {
1615 qreal x = args[0]->NumberValue();
1616 qreal y = args[1]->NumberValue();
1617 qreal w = args[2]->NumberValue();
1618 qreal h = args[3]->NumberValue();
1620 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
1623 r->context->buffer()->fillRect(x, y, w, h);
1630 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1631 Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
1632 and (if appropriate) miterLimit attributes.
1634 \sa QtQuick2::Context2D::strokeStyle
1635 \sa QtQuick2::Context2D::lineWidth
1636 \sa QtQuick2::Context2D::lineJoin
1637 \sa QtQuick2::Context2D::miterLimit
1639 static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
1641 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1645 if (args.Length() == 4) {
1646 qreal x = args[0]->NumberValue();
1647 qreal y = args[1]->NumberValue();
1648 qreal w = args[2]->NumberValue();
1649 qreal h = args[3]->NumberValue();
1651 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
1654 r->context->buffer()->strokeRect(x, y, w, h);
1660 // Complex shapes (paths) API
1662 \qmlmethod object QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
1663 Adds an arc to the current subpath that lies on the circumference of the circle whose center is at the point (\c x,\cy) and whose radius is \c radius.
1664 \image qml-item-canvas-arcTo2.png
1665 \sa QtQuick2::Context2D::arcTo
1666 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
1668 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
1670 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1673 if (args.Length() >= 5) {
1674 bool antiClockwise = false;
1676 if (args.Length() == 6)
1677 antiClockwise = args[5]->BooleanValue();
1679 qreal radius = args[2]->NumberValue();
1680 qreal x = args[0]->NumberValue();
1681 qreal y = args[1]->NumberValue();
1682 qreal sa = args[3]->NumberValue();
1683 qreal ea = args[4]->NumberValue();
1685 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(sa) || !qIsFinite(ea))
1689 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1691 r->context->arc(args[0]->NumberValue(),
1692 args[1]->NumberValue(),
1694 args[3]->NumberValue(),
1695 args[4]->NumberValue(),
1703 \qmlmethod object QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
1705 Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
1706 To draw an arc, you begin with the same steps your followed to create a line:
1708 \o Call the context.beginPath() method to set a new path.
1709 \o Call the context.moveTo(\c x, \c y) method to set your starting position on the canvas at the point (\c x,\c y).
1710 \o To draw an arc or circle, call the context.arcTo(\c x1, \c y1, \c x2, \c y2,\c radius) method.
1711 This adds an arc with starting point (\c x1,\c y1), ending point (\c x2, \c y2), and radius \c radius to the current subpath and connects
1712 it to the previous subpath by a straight line.
1714 \image qml-item-canvas-arcTo.png
1715 Both startAngle and endAngle are measured from the x axis in units of radians.
1717 \image qml-item-canvas-startAngle.png
1718 The anticlockwise has the value TRUE for each arc in the figure above because they are all drawn in the counterclockwise direction.
1719 \sa QtQuick2::Context2D::arc
1720 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d context standard for arcTo}
1722 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
1724 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1729 if (args.Length() == 5) {
1730 qreal x1 = args[0]->NumberValue();
1731 qreal y1 = args[1]->NumberValue();
1732 qreal x2 = args[2]->NumberValue();
1733 qreal y2 = args[3]->NumberValue();
1735 if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
1738 qreal radius = args[4]->NumberValue();
1740 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1741 r->context->arcTo(args[0]->NumberValue(),
1742 args[1]->NumberValue(),
1743 args[2]->NumberValue(),
1744 args[3]->NumberValue(),
1745 args[4]->NumberValue());
1752 \qmlmethod object QtQuick2::Context2D::beginPath()
1754 Resets the current path to a new path.
1756 static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
1758 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1762 r->context->beginPath();
1768 \qmlmethod object QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
1770 Adds a cubic Bezier curve between the current position and the given endPoint using the control points specified by (\c cp1x, cp1y),
1771 and (\c cp2x, \c cp2y).
1772 After the curve is added, the current position is updated to be at the end point (\c x, \c y) of the curve.
1773 The following code produces the path shown below:
1775 ctx.strokeStyle = Qt.rgba(0, 0, 0, 1);
1778 ctx.moveTo(20, 0);//start point
1779 ctx.bezierCurveTo(-10, 90, 210, 90, 180, 0);
1782 \image qml-item-canvas-bezierCurveTo.png
1783 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
1784 \sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
1786 static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
1788 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1792 if (args.Length() == 6) {
1793 qreal cp1x = args[0]->NumberValue();
1794 qreal cp1y = args[1]->NumberValue();
1795 qreal cp2x = args[2]->NumberValue();
1796 qreal cp2y = args[3]->NumberValue();
1797 qreal x = args[4]->NumberValue();
1798 qreal y = args[5]->NumberValue();
1800 if (!qIsFinite(cp1x) || !qIsFinite(cp1y) || !qIsFinite(cp2x) || !qIsFinite(cp2y) || !qIsFinite(x) || !qIsFinite(y))
1803 r->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
1810 \qmlmethod object QtQuick2::Context2D::clip()
1812 Creates the clipping region from the current path.
1813 Any parts of the shape outside the clipping path are not displayed.
1814 To create a complex shape using the \a clip() method:
1817 \o Call the \c{context.beginPath()} method to set the clipping path.
1818 \o Define the clipping path by calling any combination of the \c{lineTo},
1819 \c{arcTo}, \c{arc}, \c{moveTo}, etc and \c{closePath} methods.
1820 \o Call the \c{context.clip()} method.
1823 The new shape displays. The following shows how a clipping path can
1824 modify how an image displays:
1826 \image qml-canvas-clip-complex.png
1827 \sa QtQuick2::Context2D::beginPath()
1828 \sa QtQuick2::Context2D::closePath()
1829 \sa QtQuick2::Context2D::stroke()
1830 \sa QtQuick2::Context2D::fill()
1831 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-clip}{W3C 2d context standard for clip}
1833 static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
1835 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1838 QPainterPath clipPath = r->context->m_path;
1839 clipPath.closeSubpath();
1840 if (!r->context->state.clipPath.isEmpty())
1841 r->context->state.clipPath = clipPath.intersected(r->context->state.clipPath);
1843 r->context->state.clipPath = clipPath;
1844 r->context->buffer()->clip(r->context->state.clipPath);
1850 \qmlmethod object QtQuick2::Context2D::closePath()
1851 Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting a new path.
1852 The current point of the new path is the previous subpath's first point.
1854 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath}{W3C 2d context standard for closePath}
1856 static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
1858 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1862 r->context->closePath();
1868 \qmlmethod object QtQuick2::Context2D::fill()
1870 Fills the subpaths with the current fill style.
1872 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-fill}{W3C 2d context standard for fill}
1874 \sa QtQuick2::Context2D::fillStyle
1876 static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
1878 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1881 r->context->buffer()->fill(r->context->m_path);
1887 \qmlmethod object QtQuick2::Context2D::lineTo(real x, real y)
1889 Draws a line from the current position to the point (x, y).
1891 static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
1893 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1897 if (args.Length() == 2) {
1898 qreal x = args[0]->NumberValue();
1899 qreal y = args[1]->NumberValue();
1901 if (!qIsFinite(x) || !qIsFinite(y))
1904 r->context->lineTo(x, y);
1911 \qmlmethod object QtQuick2::Context2D::moveTo(real x, real y)
1913 Creates a new subpath with the given point.
1915 static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
1917 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1920 if (args.Length() == 2) {
1921 qreal x = args[0]->NumberValue();
1922 qreal y = args[1]->NumberValue();
1924 if (!qIsFinite(x) || !qIsFinite(y))
1926 r->context->moveTo(x, y);
1932 \qmlmethod object QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
1934 Adds a quadratic Bezier curve between the current point and the endpoint (\c x, \c y) with the control point specified by (\c cpx, \c cpy).
1936 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto}{W3C 2d context standard for for quadraticCurveTo}
1938 static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
1940 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1943 if (args.Length() == 4) {
1944 qreal cpx = args[0]->NumberValue();
1945 qreal cpy = args[1]->NumberValue();
1946 qreal x = args[2]->NumberValue();
1947 qreal y = args[3]->NumberValue();
1949 if (!qIsFinite(cpx) || !qIsFinite(cpy) || !qIsFinite(x) || !qIsFinite(y))
1952 r->context->quadraticCurveTo(cpx, cpy, x, y);
1959 \qmlmethod object QtQuick2::Context2D::rect(real x, real y, real w, real h)
1961 Adds a rectangle at position (\c x, \c y), with the given width \c w and height \c h, as a closed subpath.
1963 static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
1965 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1969 if (args.Length() == 4) {
1970 qreal x = args[0]->NumberValue();
1971 qreal y = args[1]->NumberValue();
1972 qreal w = args[2]->NumberValue();
1973 qreal h = args[3]->NumberValue();
1975 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
1978 r->context->rect(x, y, w, h);
1985 \qmlmethod object QtQuick2::Context2D::roundedRect(real x, real y, real w, real h, real xRadius, real yRadius)
1987 Adds the given rectangle rect with rounded corners to the path. The \c xRadius and \c yRadius arguments specify the radius of the
1988 ellipses defining the corners of the rounded rectangle.
1990 static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
1992 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1995 if (args.Length() == 6) {
1996 qreal x = args[0]->NumberValue();
1997 qreal y = args[1]->NumberValue();
1998 qreal w = args[2]->NumberValue();
1999 qreal h = args[3]->NumberValue();
2000 qreal xr = args[4]->NumberValue();
2001 qreal yr = args[5]->NumberValue();
2003 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2006 if (!qIsFinite(xr) || !qIsFinite(yr))
2007 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "roundedRect(): Invalid arguments");
2009 r->context->roundedRect(x, y, w, h, xr, yr);
2016 \qmlmethod object QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
2018 Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
2019 and adds it to the path as a closed subpath.
2021 The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
2023 static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
2025 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2029 if (args.Length() == 4) {
2030 qreal x = args[0]->NumberValue();
2031 qreal y = args[1]->NumberValue();
2032 qreal w = args[2]->NumberValue();
2033 qreal h = args[3]->NumberValue();
2035 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2039 r->context->ellipse(x, y, w, h);
2046 \qmlmethod object QtQuick2::Context2D::text(string text, real x, real y)
2048 Adds the given \c text to the path as a set of closed subpaths created from the current context font supplied.
2049 The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (\c x, \c y).
2051 static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
2053 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2056 QV8Engine *engine = V8ENGINE();
2057 if (args.Length() == 3) {
2058 qreal x = args[1]->NumberValue();
2059 qreal y = args[2]->NumberValue();
2061 if (!qIsFinite(x) || !qIsFinite(y))
2063 r->context->text(engine->toString(args[0]), x, y);
2069 \qmlmethod object QtQuick2::Context2D::stroke()
2071 Strokes the subpaths with the current stroke style.
2073 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke}{W3C 2d context standard for stroke}
2075 \sa QtQuick2::Context2D::strokeStyle
2077 static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
2079 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2083 r->context->buffer()->stroke(r->context->m_path);
2089 \qmlmethod object QtQuick2::Context2D::isPointInPath(real x, real y)
2091 Returns true if the given point is in the current path.
2093 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath}{W3C 2d context standard for isPointInPath}
2095 static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
2097 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2100 bool pointInPath = false;
2101 if (args.Length() == 2) {
2102 qreal x = args[0]->NumberValue();
2103 qreal y = args[1]->NumberValue();
2104 if (!qIsFinite(x) || !qIsFinite(y))
2105 return v8::Boolean::New(false);
2106 pointInPath = r->context->isPointInPath(x, y);
2108 return v8::Boolean::New(pointInPath);
2111 static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
2113 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
2117 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
2119 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
2123 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
2125 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
2130 \qmlproperty string QtQuick2::Context2D::font
2131 Holds the current font settings.
2133 The default font value is "10px sans-serif".
2134 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-font}{w3C 2d context standard for font}
2136 v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
2138 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2141 QV8Engine *engine = V8ENGINE_ACCESSOR();
2143 return engine->toString(r->context->state.font.toString());
2146 static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2148 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2149 CHECK_CONTEXT_SETTER(r)
2151 QV8Engine *engine = V8ENGINE_ACCESSOR();
2152 QString fs = engine->toString(value);
2153 QFont font = qt_font_from_string(fs);
2154 if (font != r->context->state.font) {
2155 r->context->state.font = font;
2160 \qmlproperty string QtQuick2::Context2D::textAlign
2162 Holds the current text alignment settings.
2163 The possible values are:
2171 Other values are ignored. The default value is "start".
2173 v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
2175 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2177 QV8Engine *engine = V8ENGINE_ACCESSOR();
2178 switch (r->context->state.textAlign) {
2179 case QQuickContext2D::Start:
2180 return engine->toString(QLatin1String("start"));
2181 case QQuickContext2D::End:
2182 return engine->toString(QLatin1String("end"));
2183 case QQuickContext2D::Left:
2184 return engine->toString(QLatin1String("left"));
2185 case QQuickContext2D::Right:
2186 return engine->toString(QLatin1String("right"));
2187 case QQuickContext2D::Center:
2188 return engine->toString(QLatin1String("center"));
2192 return engine->toString(QLatin1String("start"));
2195 static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2197 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2198 CHECK_CONTEXT_SETTER(r)
2199 QV8Engine *engine = V8ENGINE_ACCESSOR();
2201 QString textAlign = engine->toString(value);
2203 QQuickContext2D::TextAlignType ta;
2204 if (textAlign == QLatin1String("start"))
2205 ta = QQuickContext2D::Start;
2206 else if (textAlign == QLatin1String("end"))
2207 ta = QQuickContext2D::End;
2208 else if (textAlign == QLatin1String("left"))
2209 ta = QQuickContext2D::Left;
2210 else if (textAlign == QLatin1String("right"))
2211 ta = QQuickContext2D::Right;
2212 else if (textAlign == QLatin1String("center"))
2213 ta = QQuickContext2D::Center;
2217 if (ta != r->context->state.textAlign) {
2218 r->context->state.textAlign = ta;
2223 \qmlproperty string QtQuick2::Context2D::textBaseline
2225 Holds the current baseline alignment settings.
2226 The possible values are:
2235 Other values are ignored. The default value is "alphabetic".
2237 v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
2239 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2242 QV8Engine *engine = V8ENGINE_ACCESSOR();
2243 switch (r->context->state.textBaseline) {
2244 case QQuickContext2D::Alphabetic:
2245 return engine->toString(QLatin1String("alphabetic"));
2246 case QQuickContext2D::Hanging:
2247 return engine->toString(QLatin1String("hanging"));
2248 case QQuickContext2D::Top:
2249 return engine->toString(QLatin1String("top"));
2250 case QQuickContext2D::Bottom:
2251 return engine->toString(QLatin1String("bottom"));
2252 case QQuickContext2D::Middle:
2253 return engine->toString(QLatin1String("middle"));
2257 return engine->toString(QLatin1String("alphabetic"));
2260 static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2262 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2263 CHECK_CONTEXT_SETTER(r)
2264 QV8Engine *engine = V8ENGINE_ACCESSOR();
2265 QString textBaseline = engine->toString(value);
2267 QQuickContext2D::TextBaseLineType tb;
2268 if (textBaseline == QLatin1String("alphabetic"))
2269 tb = QQuickContext2D::Alphabetic;
2270 else if (textBaseline == QLatin1String("hanging"))
2271 tb = QQuickContext2D::Hanging;
2272 else if (textBaseline == QLatin1String("top"))
2273 tb = QQuickContext2D::Top;
2274 else if (textBaseline == QLatin1String("bottom"))
2275 tb = QQuickContext2D::Bottom;
2276 else if (textBaseline == QLatin1String("middle"))
2277 tb = QQuickContext2D::Middle;
2281 if (tb != r->context->state.textBaseline) {
2282 r->context->state.textBaseline = tb;
2287 \qmlmethod object QtQuick2::Context2D::fillText(text, x, y)
2288 Fills the given text at the given position.
2289 \sa QtQuick2::Context2D::font
2290 \sa QtQuick2::Context2D::textAlign
2291 \sa QtQuick2::Context2D::textBaseline
2292 \sa QtQuick2::Context2D::strokeText
2294 static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
2296 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2299 QV8Engine *engine = V8ENGINE();
2300 if (args.Length() == 3) {
2301 qreal x = args[1]->NumberValue();
2302 qreal y = args[2]->NumberValue();
2303 if (!qIsFinite(x) || !qIsFinite(y))
2305 QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
2306 r->context->buffer()->fill(textPath);
2311 \qmlmethod object QtQuick2::Context2D::strokeText(text, x, y)
2312 Strokes the given text at the given position.
2313 \sa QtQuick2::Context2D::font
2314 \sa QtQuick2::Context2D::textAlign
2315 \sa QtQuick2::Context2D::textBaseline
2316 \sa QtQuick2::Context2D::fillText
2318 static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
2320 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2323 QV8Engine *engine = V8ENGINE();
2324 if (args.Length() == 3) {
2325 qreal x = args[1]->NumberValue();
2326 qreal y = args[2]->NumberValue();
2327 if (!qIsFinite(x) || !qIsFinite(y))
2329 QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
2330 r->context->buffer()->stroke(textPath);
2335 \qmlclass QtQuick2::TextMetrics
2336 \inqmlmodule QtQuick 2
2338 \brief The Context2D TextMetrics interface.
2339 The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
2340 See {http://www.w3.org/TR/2dcontext/#textmetrics}{W3C 2d context TexMetrics} for more details.
2342 \sa QtQuick2::Context2D::measureText
2343 \sa QtQuick2::TextMetrics::width
2347 \qmlproperty int QtQuick2::TextMetrics::width
2348 Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
2349 This property is read only.
2353 \qmlmethod variant QtQuick2::Context2D::measureText(text)
2354 Returns a TextMetrics object with the metrics of the given text in the current font.
2356 static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
2358 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2361 QV8Engine *engine = V8ENGINE();
2363 if (args.Length() == 1) {
2364 QFontMetrics fm(r->context->state.font);
2365 uint width = fm.width(engine->toString(args[0]));
2366 v8::Local<v8::Object> tm = v8::Object::New();
2367 tm->Set(v8::String::New("width"), v8::Number::New(width));
2370 return v8::Undefined();
2375 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
2376 Draws the given \a image on the canvas at position (\a dx, \a dy).
2378 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2379 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2380 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2381 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2383 \sa QtQuick2::CanvasImageData
2385 \sa QtQuick2::Canvas::loadImage
2386 \sa QtQuick2::Canvas::isImageLoaded
2387 \sa QtQuick2::Canvas::imageLoaded
2389 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2392 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
2393 This is an overloaded function.
2394 Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
2398 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2399 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2400 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2401 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2403 \sa QtQuick2::CanvasImageData
2405 \sa QtQuick2::Canvas::loadImage
2406 \sa QtQuick2::Canvas::isImageLoaded
2407 \sa QtQuick2::Canvas::imageLoaded
2409 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2412 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
2413 This is an overloaded function.
2414 Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
2415 onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
2419 The \a image type can be an Image or Canvas item, an image url or a \a {QtQuick2::CanvasImageData} object.
2420 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2421 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2422 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
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}
2432 static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
2434 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2437 QV8Engine *engine = V8ENGINE();
2438 qreal sx, sy, sw, sh, dx, dy, dw, dh;
2444 if (args[0]->IsString()) {
2445 QUrl url(engine->toString(args[0]->ToString()));
2447 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2449 image = r->context->createImage(url);
2450 } else if (args[0]->IsObject()) {
2451 QQuickImage *imageItem = qobject_cast<QQuickImage*>(engine->toQObject(args[0]->ToObject()));
2452 QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(engine->toQObject(args[0]->ToObject()));
2454 QV8Context2DPixelArrayResource *pix = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->GetInternalField(0)->ToObject());
2457 } else if (imageItem) {
2458 image = imageItem->image();
2459 } else if (canvas) {
2460 image = canvas->toImage();
2462 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2465 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2467 if (args.Length() == 3) {
2468 dx = args[1]->NumberValue();
2469 dy = args[2]->NumberValue();
2473 sh = image.height();
2476 } else if (args.Length() == 5) {
2480 sh = image.height();
2481 dx = args[1]->NumberValue();
2482 dy = args[2]->NumberValue();
2483 dw = args[3]->NumberValue();
2484 dh = args[4]->NumberValue();
2485 } else if (args.Length() == 9) {
2486 sx = args[1]->NumberValue();
2487 sy = args[2]->NumberValue();
2488 sw = args[3]->NumberValue();
2489 sh = args[4]->NumberValue();
2490 dx = args[5]->NumberValue();
2491 dy = args[6]->NumberValue();
2492 dw = args[7]->NumberValue();
2493 dh = args[8]->NumberValue();
2508 if (!image.isNull()) {
2509 if (sx < 0 || sy < 0 || sw == 0 || sh == 0
2510 || sx + sw > image.width() || sy + sh > image.height()
2511 || sx + sw < 0 || sy + sh < 0) {
2512 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
2515 r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
2521 // pixel manipulation
2523 \qmlclass QtQuick2::CanvasImageData
2524 The \a QtQuick2::CanvasImageData object holds the image pixel data.
2526 The \a QtQuick2::CanvasImageData object has the actual dimensions of the data stored in
2527 this object and holds the one-dimensional array containing the data in RGBA order,
2528 as integers in the range 0 to 255.
2530 \sa QtQuick2::CanvasImageData::width
2531 \sa QtQuick2::CanvasImageData::height
2532 \sa QtQuick2::CanvasImageData::data
2533 \sa QtQuick2::Context2D::createImageData
2534 \sa QtQuick2::Context2D::getImageData
2535 \sa QtQuick2::Context2D::putImageData
2538 \qmlproperty QtQuick2::CanvasImageData::width
2539 Holds the actual width dimension of the data in the ImageData object, in device pixels.
2541 v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
2543 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2545 return v8::Integer::New(0);
2546 return v8::Integer::New(r->image.width());
2550 \qmlproperty QtQuick2::CanvasImageData::height
2551 Holds the actual height dimension of the data in the ImageData object, in device pixels.
2553 v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
2555 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2557 return v8::Integer::New(0);
2559 return v8::Integer::New(r->image.height());
2563 \qmlproperty QtQuick2::CanvasImageData::data
2564 Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
2566 v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
2568 return args.This()->GetInternalField(0);
2572 \qmlmethod void QtQuick2::CanvasImageData::mirrr( bool horizontal = false, bool vertical = true)
2573 Mirrors the image data in place in the \c horizontal and/or the \c vertical direction depending on
2574 whether horizontal and vertical are set to true or false.
2575 The default \c horizontal value is false, the default \c vertical value is true.
2577 static v8::Handle<v8::Value> ctx2d_imageData_mirror(const v8::Arguments &args)
2579 bool horizontal = false, vertical = true;
2580 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2584 return v8::Undefined();
2587 if (args.Length() > 2) {
2589 return v8::Undefined();
2592 if (args.Length() == 1) {
2593 horizontal = args[0]->BooleanValue();
2594 } else if (args.Length() == 2) {
2595 horizontal = args[0]->BooleanValue();
2596 vertical = args[1]->BooleanValue();
2598 r->image = r->image.mirrored(horizontal, vertical);
2603 \qmlmethod void QtQuick2::CanvasImageData::filter(enumeration mode, args)
2604 Filters the image data as defined by one of the following modes:
2606 \o Canvas.Threshold - converts the image to black and white pixels depending
2607 if they are above or below the threshold defined by the level parameter.
2608 The level must be between 0.0 (black) and 1.0(white).
2609 If no level is specified, 0.5 is used.
2610 \o Canvas.Mono - converts the image to the 1-bit per pixel format.
2611 \o Canvas.GrayScale - converts any colors in the image to grayscale equivalents.
2612 \o Canvas.Brightness -increase/decrease a fixed \c adjustment value to each pixel's RGB channel value.
2613 \o Canvas.Invert - sets each pixel to its inverse value.
2614 \o Canvas.Blur - executes a box blur with the pixel \c radius parameter specifying the range of the blurring for each pixel.
2615 the default blur \c radius is 3. This filter also accepts another \c quality parameter, if true, the filter will
2616 execute 3-passes box blur to simulate the Guassian blur. The default \c quality value is false.
2617 \o Canvas.Opaque - sets the alpha channel to entirely opaque.
2618 \o Canvas.Convolute - executes a generic {http://en.wikipedia.org/wiki/Convolution}{Convolution} filter, the second
2619 parameter contains the convoluton matrix data as a number array.
2623 static v8::Handle<v8::Value> ctx2d_imageData_filter(const v8::Arguments &args)
2625 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2629 return v8::Undefined();
2632 if (args.Length() >= 1) {
2633 int filterFlag = args[0]->IntegerValue();
2634 switch (filterFlag) {
2635 case QQuickCanvasItem::Mono :
2637 r->image = r->image.convertToFormat(QImage::Format_Mono).convertToFormat(QImage::Format_ARGB32_Premultiplied);
2640 case QQuickCanvasItem::GrayScale :
2642 for (int y = 0; y < r->image.height(); ++y) {
2643 QRgb *row = (QRgb*)r->image.scanLine(y);
2644 for (int x = 0; x < r->image.width(); ++x) {
2645 unsigned char* rgb = ((unsigned char*)&row[x]);
2646 rgb[0] = rgb[1] = rgb[2] = qGray(rgb[0], rgb[1], rgb[2]);
2651 case QQuickCanvasItem::Threshold :
2653 qreal threshold = 0.5;
2654 if (args.Length() > 1)
2655 threshold = args[1]->NumberValue();
2657 for (int y = 0; y < r->image.height(); ++y) {
2658 QRgb *row = (QRgb*)r->image.scanLine(y);
2659 for (int x = 0; x < r->image.width(); ++x) {
2660 unsigned char* rgb = ((unsigned char*)&row[x]);
2661 unsigned char v = qGray(rgb[0], rgb[1], rgb[2]) >= threshold*255 ? 255 : 0;
2662 rgb[0] = rgb[1] = rgb[2] = v;
2667 case QQuickCanvasItem::Brightness :
2670 if (args.Length() > 1)
2671 adjustment = args[1]->IntegerValue();
2673 for (int y = 0; y < r->image.height(); ++y) {
2674 QRgb *row = (QRgb*)r->image.scanLine(y);
2675 for (int x = 0; x < r->image.width(); ++x) {
2676 ((unsigned char*)&row[x])[0] += adjustment;
2677 ((unsigned char*)&row[x])[1] += adjustment;
2678 ((unsigned char*)&row[x])[2] += adjustment;
2683 case QQuickCanvasItem::Invert :
2685 r->image.invertPixels();
2688 case QQuickCanvasItem::Blur :
2691 bool quality = false;
2693 if (args.Length() > 1)
2694 radius = args[1]->IntegerValue() / 2;
2695 if (args.Length() > 2)
2696 quality = args[2]->BooleanValue();
2698 qt_image_boxblur(r->image, radius, quality);
2701 case QQuickCanvasItem::Opaque :
2703 for (int y = 0; y < r->image.height(); ++y) {
2704 QRgb *row = (QRgb*)r->image.scanLine(y);
2705 for (int x = 0; x < r->image.width(); ++x) {
2706 ((unsigned char*)&row[x])[3] = 255;
2711 case QQuickCanvasItem::Convolute :
2713 if (args.Length() > 1 && args[1]->IsArray()) {
2714 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(args[1]);
2715 QVector<qreal> weights;
2716 for (uint32_t i = 0; i < array->Length(); ++i)
2717 weights.append(array->Get(i)->NumberValue());
2718 r->image = qt_image_convolute_filter(r->image, weights);
2732 \qmlclass QtQuick2::CanvasPixelArray
2733 The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
2734 The CanvasPixelArray can be accessed as normal Javascript array.
2735 \sa QtQuick2::CanvasImageData
2736 \sa {http://www.w3.org/TR/2dcontext/#canvaspixelarray}{W3C 2d context standard for PixelArray}
2740 \qmlproperty QtQuick2::CanvasPixelArray::length
2741 The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
2742 The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
2743 This property is read only.
2745 v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
2747 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2748 if (!r || r->image.isNull()) return v8::Undefined();
2750 return v8::Integer::New(r->image.width() * r->image.height() * 4);
2753 v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
2755 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2757 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
2758 const quint32 w = r->image.width();
2759 const quint32 row = (index / 4) / w;
2760 const quint32 col = (index / 4) % w;
2761 const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
2763 switch (index % 4) {
2765 return v8::Integer::New(qRed(*pixel));
2767 return v8::Integer::New(qGreen(*pixel));
2769 return v8::Integer::New(qBlue(*pixel));
2771 return v8::Integer::New(qAlpha(*pixel));
2774 return v8::Undefined();
2777 v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
2779 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
2781 const int v = value->Uint32Value();
2782 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4) && v > 0 && v <= 255) {
2783 const quint32 w = r->image.width();
2784 const quint32 row = (index / 4) / w;
2785 const quint32 col = (index / 4) % w;
2787 QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
2789 switch (index % 4) {
2791 *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
2794 *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
2797 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
2800 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
2804 return v8::Undefined();
2807 \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
2808 Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
2811 \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
2812 Creates a CanvasImageData object with the same dimensions as the argument.
2815 \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
2816 Creates a CanvasImageData object with the given image loaded from \a imageUrl.
2817 Note:The \a imageUrl must be already loaded before this function call, if not, an empty
2818 CanvasImageData obect will be returned.
2820 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
2822 static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
2824 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2827 QV8Engine *engine = V8ENGINE();
2829 if (args.Length() == 1) {
2830 if (args[0]->IsObject()) {
2831 v8::Local<v8::Object> imgData = args[0]->ToObject();
2832 QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
2834 qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
2835 qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
2836 return qt_create_image_data(w, h, engine, QImage());
2838 } else if (args[0]->IsString()) {
2839 QImage image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2840 return qt_create_image_data(image.width(), image.height(), engine, image);
2842 } else if (args.Length() == 2) {
2843 qreal w = args[0]->NumberValue();
2844 qreal h = args[1]->NumberValue();
2846 if (!qIsFinite(w) || !qIsFinite(h))
2847 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
2850 return qt_create_image_data(w, h, engine, QImage());
2852 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createImageData(): invalid arguments");
2854 return v8::Undefined();
2858 \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
2859 Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
2861 static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
2863 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2866 QV8Engine *engine = V8ENGINE();
2867 if (args.Length() == 4) {
2868 qreal x = args[0]->NumberValue();
2869 qreal y = args[1]->NumberValue();
2870 qreal w = args[2]->NumberValue();
2871 qreal h = args[3]->NumberValue();
2872 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(w))
2873 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
2875 if (w <= 0 || h <= 0)
2876 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
2878 QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
2879 v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
2887 \qmlmethod object QtQuick2::Context2D::putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
2888 Paints the data from the given ImageData object onto the canvas. If a dirty rectangle (\a dirtyX, \a dirtyY, \a dirtyWidth, \a dirtyHeight) is provided, only the pixels from that rectangle are painted.
2890 static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
2892 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2894 if (args.Length() != 3 && args.Length() != 7)
2895 return v8::Undefined();
2897 if (args[0]->IsNull() || !args[0]->IsObject()) {
2898 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
2900 qreal dx = args[1]->NumberValue();
2901 qreal dy = args[2]->NumberValue();
2902 qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
2904 if (!qIsFinite(dx) || !qIsFinite(dy))
2905 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2907 v8::Local<v8::Object> imageData = args[0]->ToObject();
2908 QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
2910 w = imageData->Get(v8::String::New("width"))->NumberValue();
2911 h = imageData->Get(v8::String::New("height"))->NumberValue();
2913 if (args.Length() == 7) {
2914 dirtyX = args[3]->NumberValue();
2915 dirtyY = args[4]->NumberValue();
2916 dirtyWidth = args[5]->NumberValue();
2917 dirtyHeight = args[6]->NumberValue();
2919 if (!qIsFinite(dirtyX) || !qIsFinite(dirtyY) || !qIsFinite(dirtyWidth) || !qIsFinite(dirtyHeight))
2920 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2923 if (dirtyWidth < 0) {
2924 dirtyX = dirtyX+dirtyWidth;
2925 dirtyWidth = -dirtyWidth;
2928 if (dirtyHeight < 0) {
2929 dirtyY = dirtyY+dirtyHeight;
2930 dirtyHeight = -dirtyHeight;
2934 dirtyWidth = dirtyWidth+dirtyX;
2939 dirtyHeight = dirtyHeight+dirtyY;
2943 if (dirtyX+dirtyWidth > w) {
2944 dirtyWidth = w - dirtyX;
2947 if (dirtyY+dirtyHeight > h) {
2948 dirtyHeight = h - dirtyY;
2951 if (dirtyWidth <=0 || dirtyHeight <= 0)
2960 QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2961 r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
2967 \qmlclass QtQuick2::CanvasGradient
2968 \inqmlmodule QtQuick 2
2970 \brief The Context2D opaque CanvasGradient interface.
2974 \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
2975 Adds a color stop with the given color to the gradient at the given offset.
2976 0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
2980 var gradient = ctx.createLinearGradient(0, 0, 100, 100);
2981 gradient.addColorStop(0.3, Qt.rgba(1, 0, 0, 1));
2982 gradient.addColorStop(0.7, 'rgba(0, 255, 255, 1');
2985 static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
2987 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
2989 V8THROW_ERROR("Not a CanvasGradient object");
2991 QV8Engine *engine = V8ENGINE();
2993 if (args.Length() == 2) {
2995 if (!style->brush.gradient())
2996 V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
2997 QGradient gradient = *(style->brush.gradient());
2998 qreal pos = args[0]->NumberValue();
3001 if (args[1]->IsObject()) {
3002 color = engine->toVariant(args[1], qMetaTypeId<QColor>()).value<QColor>();
3004 color = qt_color_from_string(args[1]);
3006 if (pos < 0.0 || pos > 1.0 || !qIsFinite(pos)) {
3007 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
3010 if (color.isValid()) {
3011 gradient.setColorAt(pos, color);
3013 V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string");
3015 style->brush = gradient;
3022 void QQuickContext2D::beginPath()
3024 m_path = QPainterPath();
3025 m_path.setFillRule(state.fillRule);
3028 void QQuickContext2D::closePath()
3030 if (m_path.isEmpty())
3033 QRectF boundRect = m_path.boundingRect();
3034 if (boundRect.width() || boundRect.height())
3035 m_path.closeSubpath();
3036 //FIXME:QPainterPath set the current point to (0,0) after close subpath
3037 //should be the first point of the previous subpath
3040 void QQuickContext2D::moveTo( qreal x, qreal y)
3042 //FIXME: moveTo should not close the previous subpath
3043 m_path.moveTo(state.matrix.map(QPointF(x, y)));
3046 void QQuickContext2D::lineTo( qreal x, qreal y)
3048 m_path.lineTo(state.matrix.map(QPointF(x, y)));
3051 void QQuickContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
3054 m_path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
3055 state.matrix.map(QPointF(x, y)));
3058 void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
3059 qreal cp2x, qreal cp2y,
3062 m_path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
3063 state.matrix.map(QPointF(cp2x, cp2y)),
3064 state.matrix.map(QPointF(x, y)));
3067 void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
3069 QPointF p0(m_path.currentPosition());
3071 QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
3072 QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
3073 float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
3074 float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
3076 double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
3078 // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
3079 // We could have used areCollinear() here, but since we're reusing
3080 // the variables computed above later on we keep this logic.
3081 if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
3086 float tangent = radius / tan(acos(cos_phi) / 2);
3087 float factor_p1p0 = tangent / p1p0_length;
3088 QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
3090 QPointF orth_p1p0(p1p0.y(), -p1p0.x());
3091 float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
3092 float factor_ra = radius / orth_p1p0_length;
3094 // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
3095 double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
3096 if (cos_alpha < 0.f)
3097 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3099 QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
3101 // calculate angles for addArc
3102 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3103 float sa = acos(orth_p1p0.x() / orth_p1p0_length);
3104 if (orth_p1p0.y() < 0.f)
3107 // anticlockwise logic
3108 bool anticlockwise = false;
3110 float factor_p1p2 = tangent / p1p2_length;
3111 QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
3112 QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
3113 float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
3114 float ea = acos(orth_p1p2.x() / orth_p1p2_length);
3115 if (orth_p1p2.y() < 0)
3117 if ((sa > ea) && ((sa - ea) < Q_PI))
3118 anticlockwise = true;
3119 if ((sa < ea) && ((ea - sa) > Q_PI))
3120 anticlockwise = true;
3122 arc(p.x(), p.y(), radius, sa, ea, anticlockwise, false);
3125 void QQuickContext2D::arcTo(qreal x1, qreal y1,
3129 QPointF st = state.matrix.map(QPointF(x1, y1));
3130 QPointF end = state.matrix.map(QPointF(x2, y2));
3132 if (!m_path.elementCount()) {
3134 } else if (st == m_path.currentPosition() || st == end || !radius) {
3137 addArcTo(st, end, radius);
3141 void QQuickContext2D::rect(qreal x, qreal y,
3144 m_path.addPolygon(state.matrix.map(QRectF(x, y, w, h)));
3147 void QQuickContext2D::roundedRect(qreal x, qreal y,
3152 path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
3153 m_path.addPath(state.matrix.map(path));
3156 void QQuickContext2D::ellipse(qreal x, qreal y,
3160 path.addEllipse(x, y, w, h);
3161 m_path.addPath(state.matrix.map(path));
3164 void QQuickContext2D::text(const QString& str, qreal x, qreal y)
3167 path.addText(x, y, state.font, str);
3168 m_path.addPath(state.matrix.map(path));
3171 void QQuickContext2D::arc(qreal xc,
3181 QPointF point = state.matrix.map(QPointF(xc, yc));
3187 // In Qt we don't switch the coordinate system for degrees
3188 // and still use the 0,0 as bottom left for degrees so we need
3192 antiClockWise = !antiClockWise;
3195 float sa = DEGREES(sar);
3196 float ea = DEGREES(ear);
3200 double xs = xc - radius;
3201 double ys = yc - radius;
3202 double width = radius*2;
3203 double height = radius*2;
3204 if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
3205 // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
3206 // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
3207 // circumference of this circle.
3210 if (!antiClockWise && (ea < sa)) {
3212 } else if (antiClockWise && (sa < ea)) {
3215 //### this is also due to switched coordinate system
3216 // we would end up with a 0 span instead of 360
3217 if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
3218 qFuzzyCompare(qAbs(span), 360))) {
3221 if (!m_path.elementCount())
3222 m_path.moveTo(xs, ys);
3227 QPointF currentPos = m_path.currentPosition();
3228 QPointF startPos = QPointF(xc + radius * qCos(sar),
3229 yc - radius * qSin(sar));
3230 if (currentPos != startPos)
3231 m_path.lineTo(startPos);
3234 m_path.arcTo(xs, ys, width, height, sa, span);
3237 int baseLineOffset(QQuickContext2D::TextBaseLineType value, const QFontMetrics &metrics)
3241 case QQuickContext2D::Top:
3243 case QQuickContext2D::Alphabetic:
3244 case QQuickContext2D::Middle:
3245 case QQuickContext2D::Hanging:
3246 offset = metrics.ascent();
3248 case QQuickContext2D::Bottom:
3249 offset = metrics.height();
3255 static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
3258 if (value == QQuickContext2D::Start)
3259 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Left : QQuickContext2D::Right;
3260 else if (value == QQuickContext2D::End)
3261 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Right: QQuickContext2D::Left;
3263 case QQuickContext2D::Center:
3264 offset = metrics.width(text)/2;
3266 case QQuickContext2D::Right:
3267 offset = metrics.width(text);
3268 case QQuickContext2D::Left:
3276 QImage QQuickContext2D::createImage(const QUrl& url)
3278 return m_canvas->loadedImage(url);
3281 QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
3283 const QFontMetrics metrics(state.font);
3284 int yoffset = baseLineOffset(static_cast<QQuickContext2D::TextBaseLineType>(state.textBaseline), metrics);
3285 int xoffset = textAlignOffset(static_cast<QQuickContext2D::TextAlignType>(state.textAlign), metrics, text);
3287 QPainterPath textPath;
3289 textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
3290 textPath = state.matrix.map(textPath);
3295 bool QQuickContext2D::isPointInPath(qreal x, qreal y) const
3297 return m_path.contains(QPointF(x, y));
3300 QQuickContext2D::QQuickContext2D(QQuickCanvasItem* item)
3302 , m_buffer(new QQuickContext2DCommandBuffer)
3308 QQuickContext2D::~QQuickContext2D()
3313 v8::Handle<v8::Object> QQuickContext2D::v8value() const
3318 QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
3320 v8::HandleScope handle_scope;
3321 v8::Context::Scope scope(engine->context());
3323 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
3324 ft->InstanceTemplate()->SetHasExternalResource(true);
3325 ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine));
3326 ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine));
3327 ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine));
3328 ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine));
3329 ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine));
3330 ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine));
3331 ft->PrototypeTemplate()->Set(v8::String::New("resetTransform"), V8FUNCTION(ctx2d_resetTransform, engine));
3332 ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine));
3333 ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine));
3334 ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine));
3335 ft->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, engine));
3336 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine));
3337 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine));
3338 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillRule"), ctx2d_fillRule, ctx2d_fillRule_set, v8::External::Wrap(engine));
3339 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine));
3340 ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
3341 ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
3342 ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
3343 ft->PrototypeTemplate()->Set(v8::String::New("createConicalGradient"), V8FUNCTION(ctx2d_createConicalGradient, engine));
3344 ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
3345 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
3346 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
3347 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine));
3348 ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine));
3349 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine));
3350 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine));
3351 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine));
3352 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine));
3353 ft->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_set, v8::External::Wrap(engine));
3354 ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine));
3355 ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine));
3356 ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine));
3357 ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine));
3358 ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine));
3359 ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine));
3360 ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine));
3361 ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine));
3362 ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine));
3363 ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine));
3364 ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine));
3365 ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine));
3366 ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine));
3367 ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine));
3368 ft->PrototypeTemplate()->Set(v8::String::New("roundedRect"), V8FUNCTION(ctx2d_roundedRect, engine));
3369 ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
3370 ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine));
3371 ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine));
3372 ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine));
3373 ft->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
3374 ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
3375 ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, engine));
3376 ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine));
3377 ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine));
3378 ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine));
3379 ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine));
3380 ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine));
3381 ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine));
3382 ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine));
3383 ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine));
3384 ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine));
3385 ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine));
3387 constructorContext = qPersistentNew(ft->GetFunction());
3389 v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
3390 ftGradient->InstanceTemplate()->SetHasExternalResource(true);
3391 ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
3392 constructorGradient = qPersistentNew(ftGradient->GetFunction());
3394 v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
3395 ftPattern->InstanceTemplate()->SetHasExternalResource(true);
3396 constructorPattern = qPersistentNew(ftPattern->GetFunction());
3398 v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
3399 ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
3400 ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
3401 ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
3402 constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
3404 v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
3405 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
3406 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
3407 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
3408 ftImageData->PrototypeTemplate()->Set(v8::String::New("mirror"), V8FUNCTION(ctx2d_imageData_mirror, engine));
3409 ftImageData->PrototypeTemplate()->Set(v8::String::New("filter"), V8FUNCTION(ctx2d_imageData_filter, engine));
3410 ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
3411 constructorImageData = qPersistentNew(ftImageData->GetFunction());
3414 QQuickContext2DEngineData::~QQuickContext2DEngineData()
3416 qPersistentDispose(constructorContext);
3417 qPersistentDispose(constructorGradient);
3418 qPersistentDispose(constructorPattern);
3419 qPersistentDispose(constructorImageData);
3420 qPersistentDispose(constructorPixelArray);
3423 void QQuickContext2D::popState()
3425 if (m_stateStack.isEmpty())
3428 QQuickContext2D::State newState = m_stateStack.pop();
3430 if (state.matrix != newState.matrix)
3431 buffer()->updateMatrix(newState.matrix);
3433 if (newState.globalAlpha != state.globalAlpha)
3434 buffer()->setGlobalAlpha(newState.globalAlpha);
3436 if (newState.globalCompositeOperation != state.globalCompositeOperation)
3437 buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
3439 if (newState.fillStyle != state.fillStyle)
3440 buffer()->setFillStyle(newState.fillStyle);
3442 if (newState.strokeStyle != state.strokeStyle)
3443 buffer()->setStrokeStyle(newState.strokeStyle);
3445 if (newState.lineWidth != state.lineWidth)
3446 buffer()->setLineWidth(newState.lineWidth);
3448 if (newState.lineCap != state.lineCap)
3449 buffer()->setLineCap(newState.lineCap);
3451 if (newState.lineJoin != state.lineJoin)
3452 buffer()->setLineJoin(newState.lineJoin);
3454 if (newState.miterLimit != state.miterLimit)
3455 buffer()->setMiterLimit(newState.miterLimit);
3457 if (newState.clipPath != state.clipPath) {
3458 buffer()->clip(newState.clipPath);
3461 if (newState.shadowBlur != state.shadowBlur)
3462 buffer()->setShadowBlur(newState.shadowBlur);
3464 if (newState.shadowColor != state.shadowColor)
3465 buffer()->setShadowColor(newState.shadowColor);
3467 if (newState.shadowOffsetX != state.shadowOffsetX)
3468 buffer()->setShadowOffsetX(newState.shadowOffsetX);
3470 if (newState.shadowOffsetY != state.shadowOffsetY)
3471 buffer()->setShadowOffsetY(newState.shadowOffsetY);
3474 void QQuickContext2D::pushState()
3476 m_stateStack.push(state);
3479 void QQuickContext2D::reset()
3481 QQuickContext2D::State newState;
3482 newState.matrix = QTransform();
3484 QPainterPath defaultClipPath;
3486 QRect r(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
3487 r = r.united(m_canvas->canvasWindow().toRect());
3488 defaultClipPath.addRect(r);
3489 newState.clipPath = defaultClipPath;
3490 newState.clipPath.setFillRule(Qt::WindingFill);
3492 newState.strokeStyle = QColor("#000000");
3493 newState.fillStyle = QColor("#000000");
3494 newState.fillPatternRepeatX = false;
3495 newState.fillPatternRepeatY = false;
3496 newState.strokePatternRepeatX = false;
3497 newState.strokePatternRepeatY = false;
3498 newState.fillRule = Qt::WindingFill;
3499 newState.globalAlpha = 1.0;
3500 newState.lineWidth = 1;
3501 newState.lineCap = Qt::FlatCap;
3502 newState.lineJoin = Qt::MiterJoin;
3503 newState.miterLimit = 10;
3504 newState.shadowOffsetX = 0;
3505 newState.shadowOffsetY = 0;
3506 newState.shadowBlur = 0;
3507 newState.shadowColor = qRgba(0, 0, 0, 0);
3508 newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
3509 newState.font = QFont(QLatin1String("sans-serif"), 10);
3510 newState.textAlign = QQuickContext2D::Start;
3511 newState.textBaseline = QQuickContext2D::Alphabetic;
3513 m_stateStack.clear();
3514 m_stateStack.push(newState);
3516 m_buffer->clearRect(0, 0, m_canvas->width(), m_canvas->height());
3519 void QQuickContext2D::setV8Engine(QV8Engine *engine)
3521 v8::HandleScope handle_scope;
3522 v8::Context::Scope scope(engine->context());
3524 if (m_v8engine != engine) {
3525 m_v8engine = engine;
3527 qPersistentDispose(m_v8value);
3529 if (m_v8engine == 0)
3532 QQuickContext2DEngineData *ed = engineData(engine);
3533 m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
3534 QV8Context2DResource *r = new QV8Context2DResource(engine);
3536 m_v8value->SetExternalResource(r);