1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickcontext2d_p.h"
43 #include "qquickcontext2dcommandbuffer_p.h"
44 #include "qquickcanvasitem_p.h"
45 #include <private/qquickcontext2dtexture_p.h>
46 #include <private/qquickitem_p.h>
47 #include <QtQuick/private/qquickshadereffectsource_p.h>
48 #include <QtGui/qopenglframebufferobject.h>
50 #include <QtQuick/private/qsgcontext_p.h>
51 #include <private/qquicksvgparser_p.h>
52 #include <private/qquickpath_p.h>
54 #include <private/qquickimage_p_p.h>
56 #include <QtGui/qguiapplication.h>
58 #include <QtCore/qmath.h>
59 #include <private/qv8engine_p.h>
61 #include <qqmlengine.h>
62 #include <private/qv8domerrors_p.h>
63 #include <QtCore/qnumeric.h>
71 \qmlclass Context2D QQuickContext2D
72 \inqmlmodule QtQuick 2
74 \brief The Context2D API allows you to draw 2d graphic shapes on the \c
77 The Context2D object can be created by \c Canvas item's \c getContext()
83 var ctx = canvas.getContext('2d');
88 The Context2D API implements the same \l
89 {http://www.w3.org/TR/2dcontext}{W3C Canvas 2D Context API standard} with
90 some enhanced features.
92 The Context2D API provides the rendering \b{context} which defines the
93 methods and attributes needed to draw on the \c Canvas item. The following
94 assigns the canvas rendering context to a \c{context} variable:
96 var context = mycanvas.getContext("2d")
99 The Context2D API renders the canvas as a coordinate system whose origin
100 (0,0) is at the top left corner, as shown in the figure below. Coordinates
101 increase along the \c{x} axis from left to right and along the \c{y} axis
102 from top to bottom of the canvas.
103 \image qml-item-canvas-context.gif
108 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
110 static const double Q_PI = 3.14159265358979323846; // pi
112 #define DEGREES(t) ((t) * 180.0 / Q_PI)
114 #define CHECK_CONTEXT(r) if (!r || !r->context || !r->context->bufferValid()) \
115 V8THROW_ERROR("Not a Context2D object");
117 #define CHECK_CONTEXT_SETTER(r) if (!r || !r->context || !r->context->bufferValid()) \
118 V8THROW_ERROR_SETTER("Not a Context2D object");
119 #define qClamp(val, min, max) qMin(qMax(val, min), max)
120 #define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
121 QColor qt_color_from_string(v8::Local<v8::Value> name)
123 v8::String::AsciiValue str(name);
126 int len = str.length();
127 //rgb/hsl color string has at least 7 characters
128 if (!p || len > 255 || len <= 7)
131 bool isRgb(false), isHsl(false), hasAlpha(false);
134 while (isspace(*p)) p++;
135 if (strncmp(p, "rgb", 3) == 0)
137 else if (strncmp(p, "hsl", 3) == 0)
142 p+=3; //skip "rgb" or "hsl"
143 hasAlpha = (*p == 'a') ? true : false;
147 if (hasAlpha) ++p; //skip "a"
149 int rh, gs, bl, alpha = 255;
152 while (isspace(*p)) p++;
153 rh = strtol(p, &p, 10);
155 rh = qRound(rh/100.0 * 255);
158 if (*p++ != ',') return QColor();
161 while (isspace(*p)) p++;
162 gs = strtol(p, &p, 10);
164 gs = qRound(gs/100.0 * 255);
167 if (*p++ != ',') return QColor();
170 while (isspace(*p)) p++;
171 bl = strtol(p, &p, 10);
173 bl = qRound(bl/100.0 * 255);
178 if (*p++!= ',') return QColor();
179 while (isspace(*p)) p++;
181 alpha = qRound(qstrtod(p, const_cast<const char **>(&p), &ok) * 255);
184 if (*p != ')') return QColor();
186 return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)));
188 return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255));
193 QFont qt_font_from_string(const QString& fontString) {
195 // ### this is simplified and incomplete
196 // ### TODO:get code from Qt webkit
197 const QStringList tokens = fontString.split(QLatin1Char(' '));
198 foreach (const QString &token, tokens) {
199 if (token == QLatin1String("italic"))
200 font.setItalic(true);
201 else if (token == QLatin1String("bold"))
203 else if (token.endsWith(QLatin1String("px"))) {
204 QString number = token;
205 number.remove(QLatin1String("px"));
206 //font.setPointSizeF(number.trimmed().toFloat());
207 font.setPixelSize(number.trimmed().toInt());
209 font.setFamily(token);
217 class QQuickContext2DEngineData : public QV8Engine::Deletable
220 QQuickContext2DEngineData(QV8Engine *engine);
221 ~QQuickContext2DEngineData();
223 v8::Persistent<v8::Function> constructorContext;
224 v8::Persistent<v8::Function> constructorGradient;
225 v8::Persistent<v8::Function> constructorPattern;
226 v8::Persistent<v8::Function> constructorPixelArray;
227 v8::Persistent<v8::Function> constructorImageData;
230 V8_DEFINE_EXTENSION(QQuickContext2DEngineData, engineData)
232 class QV8Context2DResource : public QV8ObjectResource
234 V8_RESOURCE_TYPE(Context2DType)
236 QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
237 QQuickContext2D* context;
240 class QV8Context2DStyleResource : public QV8ObjectResource
242 V8_RESOURCE_TYPE(Context2DStyleType)
244 QV8Context2DStyleResource(QV8Engine *e)
245 : QV8ObjectResource(e)
246 , patternRepeatX(false)
247 , patternRepeatY(false)
250 bool patternRepeatX:1;
251 bool patternRepeatY:1;
254 class QV8Context2DPixelArrayResource : public QV8ObjectResource
256 V8_RESOURCE_TYPE(Context2DPixelArrayType)
258 QV8Context2DPixelArrayResource(QV8Engine *e) : QV8ObjectResource(e) {}
263 QImage qt_image_convolute_filter(const QImage& src, const QVector<qreal>& weights, int radius = 0)
265 int sides = radius ? radius : qRound(qSqrt(weights.size()));
266 int half = qFloor(sides/2);
268 QImage dst = QImage(src.size(), src.format());
270 int h = src.height();
271 for (int y = 0; y < dst.height(); ++y) {
272 QRgb *dr = (QRgb*)dst.scanLine(y);
273 for (int x = 0; x < dst.width(); ++x) {
274 unsigned char* dRgb = ((unsigned char*)&dr[x]);
275 unsigned char red=0, green=0, blue=0, alpha=0;
279 for (int cy=0; cy<sides; cy++) {
280 for (int cx=0; cx<sides; cx++) {
281 int scy = sy + cy - half;
282 int scx = sx + cx - half;
283 if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
284 const QRgb *sr = (const QRgb*)(src.constScanLine(scy));
285 const unsigned char* sRgb = ((const unsigned char*)&sr[scx]);
286 qreal wt = radius ? weights[0] : weights[cy*sides+cx];
288 green += sRgb[1] * wt;
289 blue += sRgb[2] * wt;
290 alpha += sRgb[3] * wt;
303 void qt_image_boxblur(QImage& image, int radius, bool quality)
305 int passes = quality? 3: 1;
306 for (int i=0; i < passes; i++) {
307 image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0/(radius * radius * 1.0), radius);
311 static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
313 if (compositeOperator == QLatin1String("source-over")) {
314 return QPainter::CompositionMode_SourceOver;
315 } else if (compositeOperator == QLatin1String("source-out")) {
316 return QPainter::CompositionMode_SourceOut;
317 } else if (compositeOperator == QLatin1String("source-in")) {
318 return QPainter::CompositionMode_SourceIn;
319 } else if (compositeOperator == QLatin1String("source-atop")) {
320 return QPainter::CompositionMode_SourceAtop;
321 } else if (compositeOperator == QLatin1String("destination-atop")) {
322 return QPainter::CompositionMode_DestinationAtop;
323 } else if (compositeOperator == QLatin1String("destination-in")) {
324 return QPainter::CompositionMode_DestinationIn;
325 } else if (compositeOperator == QLatin1String("destination-out")) {
326 return QPainter::CompositionMode_DestinationOut;
327 } else if (compositeOperator == QLatin1String("destination-over")) {
328 return QPainter::CompositionMode_DestinationOver;
329 } else if (compositeOperator == QLatin1String("lighter")) {
330 return QPainter::CompositionMode_Lighten;
331 } else if (compositeOperator == QLatin1String("copy")) {
332 return QPainter::CompositionMode_Source;
333 } else if (compositeOperator == QLatin1String("xor")) {
334 return QPainter::CompositionMode_Xor;
335 } else if (compositeOperator == QLatin1String("qt-clear")) {
336 return QPainter::CompositionMode_Clear;
337 } else if (compositeOperator == QLatin1String("qt-destination")) {
338 return QPainter::CompositionMode_Destination;
339 } else if (compositeOperator == QLatin1String("qt-multiply")) {
340 return QPainter::CompositionMode_Multiply;
341 } else if (compositeOperator == QLatin1String("qt-screen")) {
342 return QPainter::CompositionMode_Screen;
343 } else if (compositeOperator == QLatin1String("qt-overlay")) {
344 return QPainter::CompositionMode_Overlay;
345 } else if (compositeOperator == QLatin1String("qt-darken")) {
346 return QPainter::CompositionMode_Darken;
347 } else if (compositeOperator == QLatin1String("qt-lighten")) {
348 return QPainter::CompositionMode_Lighten;
349 } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
350 return QPainter::CompositionMode_ColorDodge;
351 } else if (compositeOperator == QLatin1String("qt-color-burn")) {
352 return QPainter::CompositionMode_ColorBurn;
353 } else if (compositeOperator == QLatin1String("qt-hard-light")) {
354 return QPainter::CompositionMode_HardLight;
355 } else if (compositeOperator == QLatin1String("qt-soft-light")) {
356 return QPainter::CompositionMode_SoftLight;
357 } else if (compositeOperator == QLatin1String("qt-difference")) {
358 return QPainter::CompositionMode_Difference;
359 } else if (compositeOperator == QLatin1String("qt-exclusion")) {
360 return QPainter::CompositionMode_Exclusion;
362 return QPainter::CompositionMode_SourceOver;
365 static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
368 case QPainter::CompositionMode_SourceOver:
369 return QLatin1String("source-over");
370 case QPainter::CompositionMode_DestinationOver:
371 return QLatin1String("destination-over");
372 case QPainter::CompositionMode_Clear:
373 return QLatin1String("qt-clear");
374 case QPainter::CompositionMode_Source:
375 return QLatin1String("copy");
376 case QPainter::CompositionMode_Destination:
377 return QLatin1String("qt-destination");
378 case QPainter::CompositionMode_SourceIn:
379 return QLatin1String("source-in");
380 case QPainter::CompositionMode_DestinationIn:
381 return QLatin1String("destination-in");
382 case QPainter::CompositionMode_SourceOut:
383 return QLatin1String("source-out");
384 case QPainter::CompositionMode_DestinationOut:
385 return QLatin1String("destination-out");
386 case QPainter::CompositionMode_SourceAtop:
387 return QLatin1String("source-atop");
388 case QPainter::CompositionMode_DestinationAtop:
389 return QLatin1String("destination-atop");
390 case QPainter::CompositionMode_Xor:
391 return QLatin1String("xor");
392 case QPainter::CompositionMode_Plus:
393 return QLatin1String("plus");
394 case QPainter::CompositionMode_Multiply:
395 return QLatin1String("qt-multiply");
396 case QPainter::CompositionMode_Screen:
397 return QLatin1String("qt-screen");
398 case QPainter::CompositionMode_Overlay:
399 return QLatin1String("qt-overlay");
400 case QPainter::CompositionMode_Darken:
401 return QLatin1String("qt-darken");
402 case QPainter::CompositionMode_Lighten:
403 return QLatin1String("lighter");
404 case QPainter::CompositionMode_ColorDodge:
405 return QLatin1String("qt-color-dodge");
406 case QPainter::CompositionMode_ColorBurn:
407 return QLatin1String("qt-color-burn");
408 case QPainter::CompositionMode_HardLight:
409 return QLatin1String("qt-hard-light");
410 case QPainter::CompositionMode_SoftLight:
411 return QLatin1String("qt-soft-light");
412 case QPainter::CompositionMode_Difference:
413 return QLatin1String("qt-difference");
414 case QPainter::CompositionMode_Exclusion:
415 return QLatin1String("qt-exclusion");
423 static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
425 QQuickContext2DEngineData *ed = engineData(engine);
426 v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
427 QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
428 if (image.isNull()) {
429 r->image = QImage(w, h, QImage::Format_ARGB32);
430 r->image.fill(0x00000000);
432 Q_ASSERT(image.width() == w && image.height() == h);
433 r->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
435 v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
436 pixelData->SetExternalResource(r);
438 imageData->SetInternalField(0, pixelData);
442 //static script functions
445 \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
446 Holds the canvas item that the context paints on.
448 This property is read only.
450 static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
452 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
456 QV8Engine *engine = V8ENGINE_ACCESSOR();
458 return engine->newQObject(r->context->canvas());
462 \qmlmethod object QtQuick2::Context2D::restore()
463 Pops the top state on the stack, restoring the context to that state.
465 \sa QtQuick2::Context2D::save()
467 static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
469 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
472 r->context->popState();
477 \qmlmethod object QtQuick2::Context2D::reset()
478 Resets the context state and properties to the default values.
480 static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
482 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
491 \qmlmethod object QtQuick2::Context2D::save()
492 Pushes the current state onto the state stack.
494 Before changing any state attributes, you should save the current state
495 for future reference. The context maintains a stack of drawing states.
496 Each state consists of the current transformation matrix, clipping region,
497 and values of the following attributes:
499 \li\a QtQuick2::Context2D::strokeStyle
500 \li\a QtQuick2::Context2D::fillStyle
501 \li\a QtQuick2::Context2D::fillRule
502 \li\a QtQuick2::Context2D::globalAlpha
503 \li\a QtQuick2::Context2D::lineWidth
504 \li\a QtQuick2::Context2D::lineCap
505 \li\a QtQuick2::Context2D::lineJoin
506 \li\a QtQuick2::Context2D::miterLimit
507 \li\a QtQuick2::Context2D::shadowOffsetX
508 \li\a QtQuick2::Context2D::shadowOffsetY
509 \li\a QtQuick2::Context2D::shadowBlur
510 \li\a QtQuick2::Context2D::shadowColor
511 \li\a QtQuick2::Context2D::globalCompositeOperation
512 \li\a QtQuick2::Context2D::font
513 \li\a QtQuick2::Context2D::textAlign
514 \li\a QtQuick2::Context2D::textBaseline
517 The current path is NOT part of the drawing state. The path can be reset by
518 invoking the \a QtQuick2::Context2D::beginPath() method.
520 static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
522 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
525 r->context->pushState();
532 \qmlmethod object QtQuick2::Context2D::rotate(real angle)
533 Rotate the canvas around the current origin by \c angle in radians and clockwise direction.
535 ctx.rotate(Math.PI/2);
537 \image qml-item-canvas-rotate.png
539 The rotation transformation matrix is as follows:
541 \image qml-item-canvas-math-rotate.png
543 where the \c angle of rotation is in radians.
546 static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
548 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
551 if (args.Length() == 1)
552 r->context->rotate(args[0]->NumberValue());
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)
577 r->context->scale(args[0]->NumberValue(), args[1]->NumberValue());
582 \qmlmethod object QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
583 Changes the transformation matrix to the matrix given by the arguments as described below.
585 Modifying the transformation matrix directly enables you to perform scaling,
586 rotating, and translating transformations in a single step.
588 Each point on the canvas is multiplied by the matrix before anything is
589 drawn. The \l{HTML5 Canvas API} defines the transformation matrix as:
591 \image qml-item-canvas-math.png
594 \li \c{a} is the scale factor in the horizontal (x) direction
595 \image qml-item-canvas-scalex.png
596 \li \c{c} is the skew factor in the x direction
597 \image qml-item-canvas-canvas-skewx.png
598 \li \c{e} is the translation in the x direction
599 \image qml-item-canvas-canvas-translate.png
600 \li \c{b} is the skew factor in the y (vertical) direction
601 \image qml-item-canvas-canvas-skewy.png
602 \li \c{d} is the scale factor in the y direction
603 \image qml-item-canvas-canvas-scaley.png
604 \li \c{f} is the translation in the y direction
605 \image qml-item-canvas-canvas-translatey.png
606 \li the last row remains constant
608 The scale factors and skew factors are multiples; \c{e} and \c{f} are
609 coordinate space units, just like the units in the \a QtQuick2::Context2D::translate(x,y)
612 \sa QtQuick2::Context2D::transform()
614 static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
616 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
620 if (args.Length() == 6)
621 r->context->setTransform( args[0]->NumberValue()
622 , args[1]->NumberValue()
623 , args[2]->NumberValue()
624 , args[3]->NumberValue()
625 , args[4]->NumberValue()
626 , args[5]->NumberValue());
632 \qmlmethod object QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
633 This method is very similar to \a QtQuick2::Context2D::setTransform(), but instead of replacing the old
634 tranform matrix, this method applies the given tranform matrix to the current matrix by mulitplying to it.
636 The \a setTransform(a, b, c, d, e, f) method actually resets the current transform to the identity matrix,
637 and then invokes the transform(a, b, c, d, e, f) method with the same arguments.
639 \sa QtQuick2::Context2D::setTransform()
641 static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
643 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
647 if (args.Length() == 6)
648 r->context->transform( args[0]->NumberValue()
649 , args[1]->NumberValue()
650 , args[2]->NumberValue()
651 , args[3]->NumberValue()
652 , args[4]->NumberValue()
653 , args[5]->NumberValue());
659 \qmlmethod object QtQuick2::Context2D::translate(real x, real y)
660 Translates the origin of the canvas to point (\c x, \c y).
662 \c x is the horizontal distance that the origin is translated, in coordinate space units,
663 \c y is the vertical distance that the origin is translated, in coordinate space units.
664 Translating the origin enables you to draw patterns of different objects on the canvas
665 without having to measure the coordinates manually for each shape.
667 static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
669 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
673 if (args.Length() == 2)
674 r->context->translate(args[0]->NumberValue(), args[1]->NumberValue());
680 \qmlmethod object QtQuick2::Context2D::resetTransform()
681 Reset the transformation matrix to default value.
683 \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform(), QtQuick2::Context2D::reset()
685 static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
687 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
690 r->context->setTransform(1, 0, 0, 1, 0, 0);
697 \qmlmethod object QtQuick2::Context2D::shear(real sh, real sv )
698 Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
700 static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
702 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
705 if (args.Length() == 2)
706 r->context->shear(args[0]->NumberValue(), args[1]->NumberValue());
713 \qmlproperty real QtQuick2::Context2D::globalAlpha
714 Holds the the current alpha value applied to rendering operations.
715 The value must be in the range from 0.0 (fully transparent) to 1.0 (fully opque).
716 The default value is 1.0.
718 static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
720 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
723 return v8::Number::New(r->context->state.globalAlpha);
726 static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
728 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
729 CHECK_CONTEXT_SETTER(r)
731 qreal globalAlpha = value->NumberValue();
733 if (!qIsFinite(globalAlpha))
736 if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
737 r->context->state.globalAlpha = globalAlpha;
738 r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
743 \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
744 Holds the the current the current composition operation, from the list below:
746 \li source-atop - A atop B. Display the source image wherever both images are opaque.
747 Display the destination image wherever the destination image is opaque but the source image is transparent.
748 Display transparency elsewhere.
749 \li source-in - A in B. Display the source image wherever both the source image and destination image are opaque.
750 Display transparency elsewhere.
751 \li source-out - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
752 Display transparency elsewhere.
753 \li source-over - (default) A over B. Display the source image wherever the source image is opaque.
754 Display the destination image elsewhere.
755 \li destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
756 \li destination-in - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
757 \li destination-out - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
758 \li destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
759 \li lighter - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
760 \li copy - A (B is ignored). Display the source image instead of the destination image.
761 \li xor - A xor B. Exclusive OR of the source image and destination image.
764 Additionally, this property also accepts the compositon modes listed in \a {QPainter::CompositionMode}. According to the W3C standard, these
765 extension composition modes are provided as "vendorName-operationName" syntax, for example: \c {QPainter::CompositionMode_Exclusion} is porvided as
768 static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
770 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
774 QV8Engine *engine = V8ENGINE_ACCESSOR();
776 return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
779 static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
781 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
782 CHECK_CONTEXT_SETTER(r)
784 QV8Engine *engine = V8ENGINE_ACCESSOR();
787 QString mode = engine->toString(value);
788 QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
789 if (cm == QPainter::CompositionMode_SourceOver && mode != QStringLiteral("source-over"))
792 if (cm != r->context->state.globalCompositeOperation) {
793 r->context->state.globalCompositeOperation = cm;
794 r->context->buffer()->setGlobalCompositeOperation(cm);
800 \qmlproperty variant QtQuick2::Context2D::fillStyle
801 Holds the current style used for filling shapes.
802 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object. Invalid values are ignored.
803 This property accepts several color syntaxes:
805 \li 'rgb(red, green, blue)' - for example: 'rgb(255, 100, 55)' or 'rgb(100%, 70%, 30%)'
806 \li 'rgba(red, green, blue, alpha)' - for example: 'rgb(255, 100, 55, 1.0)' or 'rgb(100%, 70%, 30%, 0.5)'
807 \li 'hsl(hue, saturation, lightness)'
808 \li 'hsla(hue, saturation, lightness, alpha)'
809 \li '#RRGGBB' - for example: '#00FFCC'
810 \li Qt.rgba(red, green, blue, alpha) - for example: Qt.rgba(0.3, 0.7, 1, 1.0)
812 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
813 best performance, because it's already a valid QColor value, does not need to be parsed everytime.
815 The default value is '#000000'.
816 \sa QtQuick2::Context2D::createLinearGradient
817 \sa QtQuick2::Context2D::createRadialGradient
818 \sa QtQuick2::Context2D::createPattern
819 \sa QtQuick2::Context2D::strokeStyle
821 static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
823 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
826 QV8Engine *engine = V8ENGINE_ACCESSOR();
828 QColor color = r->context->state.fillStyle.color();
829 if (color.isValid()) {
830 if (color.alpha() == 255)
831 return engine->toString(color.name());
832 QString alphaString = QString::number(color.alphaF(), 'f');
833 while (alphaString.endsWith(QLatin1Char('0')))
835 if (alphaString.endsWith(QLatin1Char('.')))
836 alphaString += QLatin1Char('0');
837 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
839 return r->context->m_fillStyle;
842 static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
844 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
845 CHECK_CONTEXT_SETTER(r)
847 QV8Engine *engine = V8ENGINE_ACCESSOR();
849 if (value->IsObject()) {
850 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
851 if (color.isValid()) {
852 r->context->state.fillStyle = color;
853 r->context->buffer()->setFillStyle(color);
854 r->context->m_fillStyle = value;
856 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
857 if (style && style->brush != r->context->state.fillStyle) {
858 r->context->state.fillStyle = style->brush;
859 r->context->buffer()->setFillStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
860 r->context->m_fillStyle = value;
861 r->context->state.fillPatternRepeatX = style->patternRepeatX;
862 r->context->state.fillPatternRepeatY = style->patternRepeatY;
865 } else if (value->IsString()) {
866 QColor color = qt_color_from_string(value);
867 if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
868 r->context->state.fillStyle = QBrush(color);
869 r->context->buffer()->setFillStyle(r->context->state.fillStyle);
870 r->context->m_fillStyle = value;
875 \qmlproperty enumeration QtQuick2::Context2D::fillRule
876 Holds the current fill rule used for filling shapes. The following fill rules supported:
881 Note: Unlike the \a QPainterPath, the Canvas API uses the winding fill as the default fill rule.
882 The fillRule property is part of the context rendering state.
884 \sa QtQuick2::Context2D::fillStyle
886 static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
888 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
890 QV8Engine *engine = V8ENGINE_ACCESSOR();
892 return engine->fromVariant(r->context->state.fillRule);
895 static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
897 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
898 CHECK_CONTEXT_SETTER(r)
900 QV8Engine *engine = V8ENGINE_ACCESSOR();
902 if ((value->IsString() && engine->toString(value) == QStringLiteral("WindingFill"))
903 ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
904 r->context->state.fillRule = Qt::WindingFill;
905 } else if ((value->IsString() && engine->toString(value) == QStringLiteral("OddEvenFill"))
906 ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
907 r->context->state.fillRule = Qt::OddEvenFill;
911 r->context->m_path.setFillRule(r->context->state.fillRule);
914 \qmlproperty variant QtQuick2::Context2D::strokeStyle
915 Holds the current color or style to use for the lines around shapes,
916 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object.
917 Invalid values are ignored.
919 The default value is '#000000'.
921 \sa QtQuick2::Context2D::createLinearGradient
922 \sa QtQuick2::Context2D::createRadialGradient
923 \sa QtQuick2::Context2D::createPattern
924 \sa QtQuick2::Context2D::fillStyle
926 v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
928 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
931 QV8Engine *engine = V8ENGINE_ACCESSOR();
933 QColor color = r->context->state.strokeStyle.color();
934 if (color.isValid()) {
935 if (color.alpha() == 255)
936 return engine->toString(color.name());
937 QString alphaString = QString::number(color.alphaF(), 'f');
938 while (alphaString.endsWith(QLatin1Char('0')))
940 if (alphaString.endsWith(QLatin1Char('.')))
941 alphaString += QLatin1Char('0');
942 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
944 return r->context->m_strokeStyle;
947 static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
949 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
950 CHECK_CONTEXT_SETTER(r)
952 QV8Engine *engine = V8ENGINE_ACCESSOR();
954 if (value->IsObject()) {
955 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
956 if (color.isValid()) {
957 r->context->state.fillStyle = color;
958 r->context->buffer()->setStrokeStyle(color);
959 r->context->m_strokeStyle = value;
961 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
962 if (style && style->brush != r->context->state.strokeStyle) {
963 r->context->state.strokeStyle = style->brush;
964 r->context->buffer()->setStrokeStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
965 r->context->m_strokeStyle = value;
966 r->context->state.strokePatternRepeatX = style->patternRepeatX;
967 r->context->state.strokePatternRepeatY = style->patternRepeatY;
971 } else if (value->IsString()) {
972 QColor color = qt_color_from_string(value);
973 if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
974 r->context->state.strokeStyle = QBrush(color);
975 r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
976 r->context->m_strokeStyle = value;
982 \qmlmethod object QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
983 Returns a CanvasGradient object that represents a linear gradient that transitions the color along a line between
984 the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
986 A gradient is a smooth transition between colors. There are two types of gradients: linear and radial.
987 Gradients must have two or more color stops, representing color shifts positioned from 0 to 1 between
988 to the gradient's starting and end points or circles.
990 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
991 \sa QtQuick2::Context2D::createRadialGradient
992 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
993 \sa QtQuick2::Context2D::createPattern
994 \sa QtQuick2::Context2D::fillStyle
995 \sa QtQuick2::Context2D::strokeStyle
998 static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
1000 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1004 QV8Engine *engine = V8ENGINE();
1006 if (args.Length() == 4) {
1007 QQuickContext2DEngineData *ed = engineData(engine);
1008 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1009 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1010 qreal x0 = args[0]->NumberValue();
1011 qreal y0 = args[1]->NumberValue();
1012 qreal x1 = args[2]->NumberValue();
1013 qreal y1 = args[3]->NumberValue();
1019 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
1021 r->brush = QLinearGradient(x0, y0, x1, y1);
1022 gradient->SetExternalResource(r);
1030 \qmlmethod object QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
1031 Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
1032 origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
1034 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1035 \sa QtQuick2::Context2D::createLinearGradient
1036 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
1037 \sa QtQuick2::Context2D::createPattern
1038 \sa QtQuick2::Context2D::fillStyle
1039 \sa QtQuick2::Context2D::strokeStyle
1042 static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
1044 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1048 QV8Engine *engine = V8ENGINE();
1050 if (args.Length() == 6) {
1051 QQuickContext2DEngineData *ed = engineData(engine);
1052 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1053 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1055 qreal x0 = args[0]->NumberValue();
1056 qreal y0 = args[1]->NumberValue();
1057 qreal r0 = args[2]->NumberValue();
1058 qreal x1 = args[3]->NumberValue();
1059 qreal y1 = args[4]->NumberValue();
1060 qreal r1 = args[5]->NumberValue();
1068 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
1070 if (r0 < 0 || r1 < 0)
1071 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
1074 r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
1075 gradient->SetExternalResource(r);
1083 \qmlmethod object QtQuick2::Context2D::createConicalGradient(real x, real y, real angle)
1084 Returns a CanvasGradient object that represents a conical gradient that interpolate colors counter-clockwise around a center point (\c x, \c y)
1085 with start angle \c angle in units of radians.
1087 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1088 \sa QtQuick2::Context2D::createLinearGradient
1089 \sa QtQuick2::Context2D::ctx2d_createRadialGradient
1090 \sa QtQuick2::Context2D::createPattern
1091 \sa QtQuick2::Context2D::fillStyle
1092 \sa QtQuick2::Context2D::strokeStyle
1095 static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &args)
1097 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1101 QV8Engine *engine = V8ENGINE();
1103 if (args.Length() == 6) {
1104 QQuickContext2DEngineData *ed = engineData(engine);
1105 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1106 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1108 qreal x = args[0]->NumberValue();
1109 qreal y = args[1]->NumberValue();
1110 qreal angle = DEGREES(args[2]->NumberValue());
1111 if (!qIsFinite(x) || !qIsFinite(y))
1112 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
1114 if (!qIsFinite(angle))
1115 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
1117 r->brush = QConicalGradient(x, y, angle);
1118 gradient->SetExternalResource(r);
1125 \qmlmethod variant createPattern(Color color, enumeration patternMode)
1126 This is a overload function.
1127 Returns a CanvasPattern object that uses the given \c color and \c patternMode.
1128 The valid pattern modes are:
1131 \li Qt.Dense1Pattern
1132 \li Qt.Dense2Pattern
1133 \li Qt.Dense3Pattern
1134 \li Qt.Dense4Pattern
1135 \li Qt.Dense5Pattern
1136 \li Qt.Dense6Pattern
1137 \li Qt.Dense7Pattern
1143 \li Qt.DiagCrossPattern
1148 \qmlmethod variant createPattern(Image image, string repetition)
1149 Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
1151 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.
1153 The allowed values for \a repetition are:
1156 \li "repeat" - both directions
1157 \li "repeat-x - horizontal only
1158 \li "repeat-y" - vertical only
1159 \li "no-repeat" - neither
1162 If the repetition argument is empty or null, the value "repeat" is used.
1164 \sa QtQuick2::Context2D::strokeStyle
1165 \sa QtQuick2::Context2D::fillStyle
1167 static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
1169 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1173 QV8Engine *engine = V8ENGINE();
1175 if (args.Length() == 2) {
1176 QQuickContext2DEngineData *ed = engineData(engine);
1177 QV8Context2DStyleResource *styleResouce = new QV8Context2DStyleResource(engine);
1179 QColor color = engine->toVariant(args[0], qMetaTypeId<QColor>()).value<QColor>();
1180 if (color.isValid()) {
1181 int patternMode = args[1]->IntegerValue();
1182 Qt::BrushStyle style = Qt::SolidPattern;
1183 if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
1184 style = static_cast<Qt::BrushStyle>(patternMode);
1186 styleResouce->brush = QBrush(color, style);
1188 QImage patternTexture;
1190 if (args[0]->IsObject()) {
1191 QV8Context2DPixelArrayResource *pixelData = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->Get(v8::String::New("data"))->ToObject());
1193 patternTexture = pixelData->image;
1196 patternTexture = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
1199 if (!patternTexture.isNull()) {
1200 styleResouce->brush.setTextureImage(patternTexture);
1202 QString repetition = engine->toString(args[1]);
1203 if (repetition == QStringLiteral("repeat") || repetition.isEmpty()) {
1204 styleResouce->patternRepeatX = true;
1205 styleResouce->patternRepeatY = true;
1206 } else if (repetition == QStringLiteral("repeat-x")) {
1207 styleResouce->patternRepeatX = true;
1208 } else if (repetition == QStringLiteral("repeat-y")) {
1209 styleResouce->patternRepeatY = true;
1210 } else if (repetition == QStringLiteral("no-repeat")) {
1211 styleResouce->patternRepeatY = false;
1212 styleResouce->patternRepeatY = false;
1214 //TODO: exception: SYNTAX_ERR
1220 v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
1221 pattern->SetExternalResource(styleResouce);
1225 return v8::Undefined();
1230 \qmlproperty string QtQuick2::Context2D::lineCap
1231 Holds the the current line cap style.
1232 The possible line cap styles are:
1234 \li butt - the end of each line has a flat edge perpendicular to the direction of the line, this is the default line cap value.
1235 \li 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.
1236 \li 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.
1238 Other values are ignored.
1240 v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
1242 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1246 QV8Engine *engine = V8ENGINE_ACCESSOR();
1247 switch (r->context->state.lineCap) {
1249 return engine->toString(QLatin1String("round"));
1251 return engine->toString(QLatin1String("butt"));
1253 return engine->toString(QLatin1String("square"));
1257 return engine->toString(QLatin1String("butt"));;
1260 static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1262 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1263 CHECK_CONTEXT_SETTER(r)
1265 QV8Engine *engine = V8ENGINE_ACCESSOR();
1267 QString lineCap = engine->toString(value);
1268 Qt::PenCapStyle cap;
1269 if (lineCap == QLatin1String("round"))
1271 else if (lineCap == QLatin1String("butt"))
1273 else if (lineCap == QLatin1String("square"))
1274 cap = Qt::SquareCap;
1278 if (cap != r->context->state.lineCap) {
1279 r->context->state.lineCap = cap;
1280 r->context->buffer()->setLineCap(cap);
1285 \qmlproperty string QtQuick2::Context2D::lineJoin
1286 Holds the the current line join style. A join exists at any point in a subpath
1287 shared by two consecutive lines. When a subpath is closed, then a join also exists
1288 at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
1290 The possible line join styles are:
1292 \li bevel - this is all that is rendered at joins.
1293 \li 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.
1294 \li 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.
1296 Other values are ignored.
1298 v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
1300 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1304 QV8Engine *engine = V8ENGINE_ACCESSOR();
1305 switch (r->context->state.lineJoin) {
1307 return engine->toString(QLatin1String("round"));
1309 return engine->toString(QLatin1String("bevel"));
1311 return engine->toString(QLatin1String("miter"));
1315 return engine->toString(QLatin1String("miter"));
1318 static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1320 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1321 CHECK_CONTEXT_SETTER(r)
1323 QV8Engine *engine = V8ENGINE_ACCESSOR();
1325 QString lineJoin = engine->toString(value);
1326 Qt::PenJoinStyle join;
1327 if (lineJoin == QLatin1String("round"))
1328 join = Qt::RoundJoin;
1329 else if (lineJoin == QLatin1String("bevel"))
1330 join = Qt::BevelJoin;
1331 else if (lineJoin == QLatin1String("miter"))
1332 join = Qt::SvgMiterJoin;
1336 if (join != r->context->state.lineJoin) {
1337 r->context->state.lineJoin = join;
1338 r->context->buffer()->setLineJoin(join);
1343 \qmlproperty real QtQuick2::Context2D::lineWidth
1344 Holds the the current line width. Values that are not finite values greater than zero are ignored.
1346 v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
1348 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1352 return v8::Number::New(r->context->state.lineWidth);
1355 static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1357 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1358 CHECK_CONTEXT_SETTER(r)
1360 qreal w = value->NumberValue();
1362 if (w > 0 && qIsFinite(w) && w != r->context->state.lineWidth) {
1363 r->context->state.lineWidth = w;
1364 r->context->buffer()->setLineWidth(w);
1369 \qmlproperty real QtQuick2::Context2D::miterLimit
1370 Holds the current miter limit ratio.
1371 The default miter limit value is 10.0.
1373 v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
1375 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1379 return v8::Number::New(r->context->state.miterLimit);
1382 static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1384 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1385 CHECK_CONTEXT_SETTER(r)
1387 qreal ml = value->NumberValue();
1389 if (ml > 0 && qIsFinite(ml) && ml != r->context->state.miterLimit) {
1390 r->context->state.miterLimit = ml;
1391 r->context->buffer()->setMiterLimit(ml);
1397 \qmlproperty real QtQuick2::Context2D::shadowBlur
1398 Holds the current level of blur applied to shadows
1400 v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
1402 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1406 return v8::Number::New(r->context->state.shadowBlur);
1409 static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1411 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1412 CHECK_CONTEXT_SETTER(r)
1413 qreal blur = value->NumberValue();
1415 if (blur > 0 && qIsFinite(blur) && blur != r->context->state.shadowBlur) {
1416 r->context->state.shadowBlur = blur;
1417 r->context->buffer()->setShadowBlur(blur);
1422 \qmlproperty string QtQuick2::Context2D::shadowColor
1423 Holds the current shadow color.
1425 v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
1427 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1431 QV8Engine *engine = V8ENGINE_ACCESSOR();
1433 return engine->toString(r->context->state.shadowColor.name());
1436 static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1438 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1439 CHECK_CONTEXT_SETTER(r)
1441 QColor color = qt_color_from_string(value);
1443 if (color.isValid() && color != r->context->state.shadowColor) {
1444 r->context->state.shadowColor = color;
1445 r->context->buffer()->setShadowColor(color);
1451 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
1452 Holds the current shadow offset in the positive horizontal distance.
1454 \sa QtQuick2::Context2D::shadowOffsetY
1456 v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
1458 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1462 return v8::Number::New(r->context->state.shadowOffsetX);
1465 static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1467 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1468 CHECK_CONTEXT_SETTER(r)
1470 qreal offsetX = value->NumberValue();
1471 if (qIsFinite(offsetX) && offsetX != r->context->state.shadowOffsetX) {
1472 r->context->state.shadowOffsetX = offsetX;
1473 r->context->buffer()->setShadowOffsetX(offsetX);
1477 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
1478 Holds the current shadow offset in the positive vertical distance.
1480 \sa QtQuick2::Context2D::shadowOffsetX
1482 v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
1484 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1488 return v8::Number::New(r->context->state.shadowOffsetY);
1491 static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1493 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1494 CHECK_CONTEXT_SETTER(r)
1496 qreal offsetY = value->NumberValue();
1497 if (qIsFinite(offsetY) && offsetY != r->context->state.shadowOffsetY) {
1498 r->context->state.shadowOffsetY = offsetY;
1499 r->context->buffer()->setShadowOffsetY(offsetY);
1503 v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
1505 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1507 return r->context->m_v8path;
1510 static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1512 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1513 CHECK_CONTEXT_SETTER(r)
1514 QV8Engine *engine = V8ENGINE_ACCESSOR();
1516 r->context->beginPath();
1517 if (value->IsObject()) {
1518 QQuickPath* path = qobject_cast<QQuickPath*>(engine->toQObject(value));
1520 r->context->m_path = path->path();
1522 QString path = engine->toString(value->ToString());
1523 QQuickSvgParser::parsePathDataFast(path, r->context->m_path);
1525 r->context->m_v8path = value;
1530 \qmlmethod object QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
1531 Clears all pixels on the canvas in the given rectangle to transparent black.
1533 static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
1535 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1539 if (args.Length() == 4)
1540 r->context->clearRect(args[0]->NumberValue(),
1541 args[1]->NumberValue(),
1542 args[2]->NumberValue(),
1543 args[3]->NumberValue());
1548 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1549 Paint the specified rectangular area using the fillStyle.
1551 \sa QtQuick2::Context2D::fillStyle
1553 static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
1555 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1558 if (args.Length() == 4)
1559 r->context->fillRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1564 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1565 Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
1566 and (if appropriate) miterLimit attributes.
1568 \sa QtQuick2::Context2D::strokeStyle
1569 \sa QtQuick2::Context2D::lineWidth
1570 \sa QtQuick2::Context2D::lineJoin
1571 \sa QtQuick2::Context2D::miterLimit
1573 static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
1575 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1578 if (args.Length() == 4)
1579 r->context->strokeRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1584 // Complex shapes (paths) API
1586 \qmlmethod object QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
1587 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.
1588 \image qml-item-canvas-arcTo2.png
1589 \sa QtQuick2::Context2D::arcTo,
1590 {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
1592 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
1594 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1597 if (args.Length() >= 5) {
1598 bool antiClockwise = false;
1600 if (args.Length() == 6)
1601 antiClockwise = args[5]->BooleanValue();
1603 qreal radius = args[2]->NumberValue();
1605 if (qIsFinite(radius) && radius < 0)
1606 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1608 r->context->arc(args[0]->NumberValue(),
1609 args[1]->NumberValue(),
1611 args[3]->NumberValue(),
1612 args[4]->NumberValue(),
1620 \qmlmethod object QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
1622 Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
1623 To draw an arc, you begin with the same steps your followed to create a line:
1625 \li Call the context.beginPath() method to set a new path.
1626 \li Call the context.moveTo(\c x, \c y) method to set your starting position on the canvas at the point (\c x,\c y).
1627 \li To draw an arc or circle, call the context.arcTo(\c x1, \c y1, \c x2, \c y2,\c radius) method.
1628 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
1629 it to the previous subpath by a straight line.
1631 \image qml-item-canvas-arcTo.png
1632 Both startAngle and endAngle are measured from the x axis in units of radians.
1634 \image qml-item-canvas-startAngle.png
1635 The anticlockwise has the value TRUE for each arc in the figure above because they are all drawn in the counterclockwise direction.
1636 \sa QtQuick2::Context2D::arc, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d
1637 context standard for arcTo}
1639 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
1641 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1644 if (args.Length() == 5) {
1645 qreal radius = args[4]->NumberValue();
1647 if (qIsFinite(radius) && radius < 0)
1648 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1650 r->context->arcTo(args[0]->NumberValue(),
1651 args[1]->NumberValue(),
1652 args[2]->NumberValue(),
1653 args[3]->NumberValue(),
1661 \qmlmethod object QtQuick2::Context2D::beginPath()
1663 Resets the current path to a new path.
1665 static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
1667 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1671 r->context->beginPath();
1677 \qmlmethod object QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
1679 Adds a cubic Bezier curve between the current position and the given endPoint using the control points specified by (\c cp1x, cp1y),
1680 and (\c cp2x, \c cp2y).
1681 After the curve is added, the current position is updated to be at the end point (\c x, \c y) of the curve.
1682 The following code produces the path shown below:
1684 ctx.strokeStyle = Qt.rgba(0, 0, 0, 1);
1687 ctx.moveTo(20, 0);//start point
1688 ctx.bezierCurveTo(-10, 90, 210, 90, 180, 0);
1691 \image qml-item-canvas-bezierCurveTo.png
1692 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
1693 \sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
1695 static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
1697 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1701 if (args.Length() == 6) {
1702 qreal cp1x = args[0]->NumberValue();
1703 qreal cp1y = args[1]->NumberValue();
1704 qreal cp2x = args[2]->NumberValue();
1705 qreal cp2y = args[3]->NumberValue();
1706 qreal x = args[4]->NumberValue();
1707 qreal y = args[5]->NumberValue();
1709 if (!qIsFinite(cp1x) || !qIsFinite(cp1y) || !qIsFinite(cp2x) || !qIsFinite(cp2y) || !qIsFinite(x) || !qIsFinite(y))
1712 r->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
1719 \qmlmethod object QtQuick2::Context2D::clip()
1721 Creates the clipping region from the current path.
1722 Any parts of the shape outside the clipping path are not displayed.
1723 To create a complex shape using the \a clip() method:
1726 \li Call the \c{context.beginPath()} method to set the clipping path.
1727 \li Define the clipping path by calling any combination of the \c{lineTo},
1728 \c{arcTo}, \c{arc}, \c{moveTo}, etc and \c{closePath} methods.
1729 \li Call the \c{context.clip()} method.
1732 The new shape displays. The following shows how a clipping path can
1733 modify how an image displays:
1735 \image qml-canvas-clip-complex.png
1736 \sa QtQuick2::Context2D::beginPath()
1737 \sa QtQuick2::Context2D::closePath()
1738 \sa QtQuick2::Context2D::stroke()
1739 \sa QtQuick2::Context2D::fill()
1740 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-clip}{W3C 2d context standard for clip}
1742 static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
1744 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1752 \qmlmethod object QtQuick2::Context2D::closePath()
1753 Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting a new path.
1754 The current point of the new path is the previous subpath's first point.
1756 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath}{W3C 2d context standard for closePath}
1758 static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
1760 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1764 r->context->closePath();
1770 \qmlmethod object QtQuick2::Context2D::fill()
1772 Fills the subpaths with the current fill style.
1774 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-fill}{W3C 2d context standard for fill}
1776 \sa QtQuick2::Context2D::fillStyle
1778 static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
1780 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1787 \qmlmethod object QtQuick2::Context2D::lineTo(real x, real y)
1789 Draws a line from the current position to the point (x, y).
1791 static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
1793 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1797 if (args.Length() == 2) {
1798 qreal x = args[0]->NumberValue();
1799 qreal y = args[1]->NumberValue();
1801 if (!qIsFinite(x) || !qIsFinite(y))
1804 r->context->lineTo(x, y);
1811 \qmlmethod object QtQuick2::Context2D::moveTo(real x, real y)
1813 Creates a new subpath with the given point.
1815 static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
1817 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1820 if (args.Length() == 2) {
1821 qreal x = args[0]->NumberValue();
1822 qreal y = args[1]->NumberValue();
1824 if (!qIsFinite(x) || !qIsFinite(y))
1826 r->context->moveTo(x, y);
1832 \qmlmethod object QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
1834 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).
1836 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto}{W3C 2d context standard for for quadraticCurveTo}
1838 static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
1840 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1843 if (args.Length() == 4) {
1844 qreal cpx = args[0]->NumberValue();
1845 qreal cpy = args[1]->NumberValue();
1846 qreal x = args[2]->NumberValue();
1847 qreal y = args[3]->NumberValue();
1849 if (!qIsFinite(cpx) || !qIsFinite(cpy) || !qIsFinite(x) || !qIsFinite(y))
1852 r->context->quadraticCurveTo(cpx, cpy, x, y);
1859 \qmlmethod object QtQuick2::Context2D::rect(real x, real y, real w, real h)
1861 Adds a rectangle at position (\c x, \c y), with the given width \c w and height \c h, as a closed subpath.
1863 static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
1865 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1868 if (args.Length() == 4)
1869 r->context->rect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1874 \qmlmethod object QtQuick2::Context2D::roundedRect(real x, real y, real w, real h, real xRadius, real yRadius)
1876 Adds the given rectangle rect with rounded corners to the path. The \c xRadius and \c yRadius arguments specify the radius of the
1877 ellipses defining the corners of the rounded rectangle.
1879 static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
1881 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1884 if (args.Length() == 6)
1885 r->context->roundedRect(args[0]->NumberValue()
1886 , args[1]->NumberValue()
1887 , args[2]->NumberValue()
1888 , args[3]->NumberValue()
1889 , args[4]->NumberValue()
1890 , args[5]->NumberValue());
1895 \qmlmethod object QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
1897 Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
1898 and adds it to the path as a closed subpath.
1900 The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
1902 static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
1904 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1908 if (args.Length() == 4)
1909 r->context->ellipse(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1915 \qmlmethod object QtQuick2::Context2D::text(string text, real x, real y)
1917 Adds the given \c text to the path as a set of closed subpaths created from the current context font supplied.
1918 The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (\c x, \c y).
1920 static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
1922 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1925 QV8Engine *engine = V8ENGINE();
1926 if (args.Length() == 3) {
1927 qreal x = args[1]->NumberValue();
1928 qreal y = args[2]->NumberValue();
1930 if (!qIsFinite(x) || !qIsFinite(y))
1932 r->context->text(engine->toString(args[0]), x, y);
1938 \qmlmethod object QtQuick2::Context2D::stroke()
1940 Strokes the subpaths with the current stroke style.
1942 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke}{W3C 2d context standard for stroke}
1944 \sa QtQuick2::Context2D::strokeStyle
1946 static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
1948 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1951 r->context->stroke();
1956 \qmlmethod object QtQuick2::Context2D::isPointInPath(real x, real y)
1958 Returns true if the given point is in the current path.
1960 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath}{W3C 2d context standard for isPointInPath}
1962 static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
1964 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1967 bool pointInPath = false;
1968 if (args.Length() == 2)
1969 pointInPath = r->context->isPointInPath(args[0]->NumberValue(), args[1]->NumberValue());
1970 return v8::Boolean::New(pointInPath);
1973 static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
1975 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
1979 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
1981 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
1985 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
1987 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
1992 \qmlproperty string QtQuick2::Context2D::font
1993 Holds the current font settings.
1995 The default font value is "10px sans-serif".
1996 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-font}{w3C 2d context standard for font}
1998 v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
2000 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2003 QV8Engine *engine = V8ENGINE_ACCESSOR();
2005 return engine->toString(r->context->state.font.toString());
2008 static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2010 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2011 CHECK_CONTEXT_SETTER(r)
2013 QV8Engine *engine = V8ENGINE_ACCESSOR();
2014 QString fs = engine->toString(value);
2015 QFont font = qt_font_from_string(fs);
2016 if (font != r->context->state.font) {
2017 r->context->state.font = font;
2022 \qmlproperty string QtQuick2::Context2D::textAlign
2024 Holds the current text alignment settings.
2025 The possible values are:
2033 Other values are ignored. The default value is "start".
2035 v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
2037 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2039 QV8Engine *engine = V8ENGINE_ACCESSOR();
2040 switch (r->context->state.textAlign) {
2041 case QQuickContext2D::Start:
2042 return engine->toString(QLatin1String("start"));
2043 case QQuickContext2D::End:
2044 return engine->toString(QLatin1String("end"));
2045 case QQuickContext2D::Left:
2046 return engine->toString(QLatin1String("left"));
2047 case QQuickContext2D::Right:
2048 return engine->toString(QLatin1String("right"));
2049 case QQuickContext2D::Center:
2050 return engine->toString(QLatin1String("center"));
2054 return engine->toString(QLatin1String("start"));
2057 static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2059 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2060 CHECK_CONTEXT_SETTER(r)
2061 QV8Engine *engine = V8ENGINE_ACCESSOR();
2063 QString textAlign = engine->toString(value);
2065 QQuickContext2D::TextAlignType ta;
2066 if (textAlign == QLatin1String("start"))
2067 ta = QQuickContext2D::Start;
2068 else if (textAlign == QLatin1String("end"))
2069 ta = QQuickContext2D::End;
2070 else if (textAlign == QLatin1String("left"))
2071 ta = QQuickContext2D::Left;
2072 else if (textAlign == QLatin1String("right"))
2073 ta = QQuickContext2D::Right;
2074 else if (textAlign == QLatin1String("center"))
2075 ta = QQuickContext2D::Center;
2079 if (ta != r->context->state.textAlign) {
2080 r->context->state.textAlign = ta;
2085 \qmlproperty string QtQuick2::Context2D::textBaseline
2087 Holds the current baseline alignment settings.
2088 The possible values are:
2097 Other values are ignored. The default value is "alphabetic".
2099 v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
2101 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2104 QV8Engine *engine = V8ENGINE_ACCESSOR();
2105 switch (r->context->state.textBaseline) {
2106 case QQuickContext2D::Alphabetic:
2107 return engine->toString(QLatin1String("alphabetic"));
2108 case QQuickContext2D::Hanging:
2109 return engine->toString(QLatin1String("hanging"));
2110 case QQuickContext2D::Top:
2111 return engine->toString(QLatin1String("top"));
2112 case QQuickContext2D::Bottom:
2113 return engine->toString(QLatin1String("bottom"));
2114 case QQuickContext2D::Middle:
2115 return engine->toString(QLatin1String("middle"));
2119 return engine->toString(QLatin1String("alphabetic"));
2122 static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2124 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2125 CHECK_CONTEXT_SETTER(r)
2126 QV8Engine *engine = V8ENGINE_ACCESSOR();
2127 QString textBaseline = engine->toString(value);
2129 QQuickContext2D::TextBaseLineType tb;
2130 if (textBaseline == QLatin1String("alphabetic"))
2131 tb = QQuickContext2D::Alphabetic;
2132 else if (textBaseline == QLatin1String("hanging"))
2133 tb = QQuickContext2D::Hanging;
2134 else if (textBaseline == QLatin1String("top"))
2135 tb = QQuickContext2D::Top;
2136 else if (textBaseline == QLatin1String("bottom"))
2137 tb = QQuickContext2D::Bottom;
2138 else if (textBaseline == QLatin1String("middle"))
2139 tb = QQuickContext2D::Middle;
2143 if (tb != r->context->state.textBaseline) {
2144 r->context->state.textBaseline = tb;
2149 \qmlmethod object QtQuick2::Context2D::fillText(text, x, y)
2150 Fills the given text at the given position.
2151 \sa QtQuick2::Context2D::font
2152 \sa QtQuick2::Context2D::textAlign
2153 \sa QtQuick2::Context2D::textBaseline
2154 \sa QtQuick2::Context2D::strokeText
2156 static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
2158 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2161 QV8Engine *engine = V8ENGINE();
2162 if (args.Length() == 3) {
2163 qreal x = args[1]->NumberValue();
2164 qreal y = args[2]->NumberValue();
2165 if (!qIsFinite(x) || !qIsFinite(y))
2167 QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
2168 r->context->buffer()->fill(textPath);
2173 \qmlmethod object QtQuick2::Context2D::strokeText(text, x, y)
2174 Strokes the given text at the given position.
2175 \sa QtQuick2::Context2D::font
2176 \sa QtQuick2::Context2D::textAlign
2177 \sa QtQuick2::Context2D::textBaseline
2178 \sa QtQuick2::Context2D::fillText
2180 static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
2182 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2185 QV8Engine *engine = V8ENGINE();
2186 if (args.Length() == 3)
2187 r->context->drawText(engine->toString(args[0]), args[1]->NumberValue(), args[2]->NumberValue(), false);
2191 \qmlclass QtQuick2::TextMetrics
2192 \inqmlmodule QtQuick 2
2194 \brief The Context2D TextMetrics interface.
2195 The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
2196 See {http://www.w3.org/TR/2dcontext/#textmetrics}{W3C 2d context TexMetrics} for more details.
2198 \sa QtQuick2::Context2D::measureText
2199 \sa QtQuick2::TextMetrics::width
2203 \qmlproperty int QtQuick2::TextMetrics::width
2204 Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
2205 This property is read only.
2209 \qmlmethod variant QtQuick2::Context2D::measureText(text)
2210 Returns a TextMetrics object with the metrics of the given text in the current font.
2212 static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
2214 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2217 QV8Engine *engine = V8ENGINE();
2219 if (args.Length() == 1) {
2220 QFontMetrics fm(r->context->state.font);
2221 uint width = fm.width(engine->toString(args[0]));
2222 v8::Local<v8::Object> tm = v8::Object::New();
2223 tm->Set(v8::String::New("width"), v8::Number::New(width));
2226 return v8::Undefined();
2231 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
2232 Draws the given \a image on the canvas at position (\a dx, \a dy).
2234 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2235 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2236 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2237 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2239 \sa QtQuick2::CanvasImageData
2241 \sa QtQuick2::Canvas::loadImage
2242 \sa QtQuick2::Canvas::isImageLoaded
2243 \sa QtQuick2::Canvas::imageLoaded
2245 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2248 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
2249 This is an overloaded function.
2250 Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
2254 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2255 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2256 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2257 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2259 \sa QtQuick2::CanvasImageData
2261 \sa QtQuick2::Canvas::loadImage
2262 \sa QtQuick2::Canvas::isImageLoaded
2263 \sa QtQuick2::Canvas::imageLoaded
2265 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2268 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
2269 This is an overloaded function.
2270 Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
2271 onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
2275 The \a image type can be an Image or Canvas item, an image url or a \a {QtQuick2::CanvasImageData} object.
2276 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2277 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2278 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2280 \sa QtQuick2::CanvasImageData
2282 \sa QtQuick2::Canvas::loadImage
2283 \sa QtQuick2::Canvas::isImageLoaded
2284 \sa QtQuick2::Canvas::imageLoaded
2286 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2288 static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
2290 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2293 QV8Engine *engine = V8ENGINE();
2294 qreal sx, sy, sw, sh, dx, dy, dw, dh;
2299 //FIXME:This function should be moved to QQuickContext2D::drawImage(...)
2300 if (!r->context->state.invertibleCTM)
2304 if (args[0]->IsString()) {
2305 QUrl url(engine->toString(args[0]->ToString()));
2307 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2309 image = r->context->createImage(url);
2310 } else if (args[0]->IsObject()) {
2311 QQuickImage *imageItem = qobject_cast<QQuickImage*>(engine->toQObject(args[0]->ToObject()));
2312 QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(engine->toQObject(args[0]->ToObject()));
2314 QV8Context2DPixelArrayResource *pix = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->GetInternalField(0)->ToObject());
2317 } else if (imageItem) {
2318 image = imageItem->image();
2319 } else if (canvas) {
2320 image = canvas->toImage();
2322 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2325 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2327 if (args.Length() == 3) {
2328 dx = args[1]->NumberValue();
2329 dy = args[2]->NumberValue();
2333 sh = image.height();
2336 } else if (args.Length() == 5) {
2340 sh = image.height();
2341 dx = args[1]->NumberValue();
2342 dy = args[2]->NumberValue();
2343 dw = args[3]->NumberValue();
2344 dh = args[4]->NumberValue();
2345 } else if (args.Length() == 9) {
2346 sx = args[1]->NumberValue();
2347 sy = args[2]->NumberValue();
2348 sw = args[3]->NumberValue();
2349 sh = args[4]->NumberValue();
2350 dx = args[5]->NumberValue();
2351 dy = args[6]->NumberValue();
2352 dw = args[7]->NumberValue();
2353 dh = args[8]->NumberValue();
2368 if (!image.isNull()) {
2369 if (sx < 0 || sy < 0 || sw == 0 || sh == 0
2370 || sx + sw > image.width() || sy + sh > image.height()
2371 || sx + sw < 0 || sy + sh < 0) {
2372 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
2375 r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
2381 // pixel manipulation
2383 \qmlclass QtQuick2::CanvasImageData
2384 The \a QtQuick2::CanvasImageData object holds the image pixel data.
2386 The \a QtQuick2::CanvasImageData object has the actual dimensions of the data stored in
2387 this object and holds the one-dimensional array containing the data in RGBA order,
2388 as integers in the range 0 to 255.
2390 \sa QtQuick2::CanvasImageData::width
2391 \sa QtQuick2::CanvasImageData::height
2392 \sa QtQuick2::CanvasImageData::data
2393 \sa QtQuick2::Context2D::createImageData
2394 \sa QtQuick2::Context2D::getImageData
2395 \sa QtQuick2::Context2D::putImageData
2398 \qmlproperty QtQuick2::CanvasImageData::width
2399 Holds the actual width dimension of the data in the ImageData object, in device pixels.
2401 v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
2403 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2405 return v8::Integer::New(0);
2406 return v8::Integer::New(r->image.width());
2410 \qmlproperty QtQuick2::CanvasImageData::height
2411 Holds the actual height dimension of the data in the ImageData object, in device pixels.
2413 v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
2415 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2417 return v8::Integer::New(0);
2419 return v8::Integer::New(r->image.height());
2423 \qmlproperty QtQuick2::CanvasImageData::data
2424 Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
2426 v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
2428 return args.This()->GetInternalField(0);
2432 \qmlclass QtQuick2::CanvasPixelArray
2433 The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
2434 The CanvasPixelArray can be accessed as normal Javascript array.
2435 \sa QtQuick2::CanvasImageData
2436 \sa {http://www.w3.org/TR/2dcontext/#canvaspixelarray}{W3C 2d context standard for PixelArray}
2440 \qmlproperty QtQuick2::CanvasPixelArray::length
2441 The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
2442 The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
2443 This property is read only.
2445 v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
2447 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2448 if (!r || r->image.isNull()) return v8::Undefined();
2450 return v8::Integer::New(r->image.width() * r->image.height() * 4);
2453 v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
2455 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2457 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
2458 const quint32 w = r->image.width();
2459 const quint32 row = (index / 4) / w;
2460 const quint32 col = (index / 4) % w;
2461 const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
2463 switch (index % 4) {
2465 return v8::Integer::New(qRed(*pixel));
2467 return v8::Integer::New(qGreen(*pixel));
2469 return v8::Integer::New(qBlue(*pixel));
2471 return v8::Integer::New(qAlpha(*pixel));
2474 return v8::Undefined();
2477 v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
2479 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
2481 const int v = value->Uint32Value();
2482 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4) && v > 0 && v <= 255) {
2483 const quint32 w = r->image.width();
2484 const quint32 row = (index / 4) / w;
2485 const quint32 col = (index / 4) % w;
2487 QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
2489 switch (index % 4) {
2491 *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
2494 *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
2497 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
2500 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
2504 return v8::Undefined();
2507 \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
2508 Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
2511 \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
2512 Creates a CanvasImageData object with the same dimensions as the argument.
2515 \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
2516 Creates a CanvasImageData object with the given image loaded from \a imageUrl.
2517 Note:The \a imageUrl must be already loaded before this function call, if not, an empty
2518 CanvasImageData obect will be returned.
2520 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
2522 static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
2524 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2527 QV8Engine *engine = V8ENGINE();
2529 if (args.Length() == 1) {
2530 if (args[0]->IsObject()) {
2531 v8::Local<v8::Object> imgData = args[0]->ToObject();
2532 QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
2534 qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
2535 qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
2536 return qt_create_image_data(w, h, engine, QImage());
2538 } else if (args[0]->IsString()) {
2539 QImage image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2540 return qt_create_image_data(image.width(), image.height(), engine, image);
2542 } else if (args.Length() == 2) {
2543 qreal w = args[0]->NumberValue();
2544 qreal h = args[1]->NumberValue();
2546 if (!qIsFinite(w) || !qIsFinite(h))
2547 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
2550 return qt_create_image_data(w, h, engine, QImage());
2552 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createImageData(): invalid arguments");
2554 return v8::Undefined();
2558 \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
2559 Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
2561 static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
2563 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2566 QV8Engine *engine = V8ENGINE();
2567 if (args.Length() == 4) {
2568 qreal x = args[0]->NumberValue();
2569 qreal y = args[1]->NumberValue();
2570 qreal w = args[2]->NumberValue();
2571 qreal h = args[3]->NumberValue();
2572 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(w))
2573 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
2575 if (w <= 0 || h <= 0)
2576 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
2578 QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
2579 v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
2587 \qmlmethod object QtQuick2::Context2D::putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
2588 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.
2590 static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
2592 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2594 if (args.Length() != 3 && args.Length() != 7)
2595 return v8::Undefined();
2597 if (args[0]->IsNull() || !args[0]->IsObject()) {
2598 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
2600 qreal dx = args[1]->NumberValue();
2601 qreal dy = args[2]->NumberValue();
2602 qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
2604 if (!qIsFinite(dx) || !qIsFinite(dy))
2605 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2607 v8::Local<v8::Object> imageData = args[0]->ToObject();
2608 QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
2610 w = imageData->Get(v8::String::New("width"))->NumberValue();
2611 h = imageData->Get(v8::String::New("height"))->NumberValue();
2613 if (args.Length() == 7) {
2614 dirtyX = args[3]->NumberValue();
2615 dirtyY = args[4]->NumberValue();
2616 dirtyWidth = args[5]->NumberValue();
2617 dirtyHeight = args[6]->NumberValue();
2619 if (!qIsFinite(dirtyX) || !qIsFinite(dirtyY) || !qIsFinite(dirtyWidth) || !qIsFinite(dirtyHeight))
2620 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2623 if (dirtyWidth < 0) {
2624 dirtyX = dirtyX+dirtyWidth;
2625 dirtyWidth = -dirtyWidth;
2628 if (dirtyHeight < 0) {
2629 dirtyY = dirtyY+dirtyHeight;
2630 dirtyHeight = -dirtyHeight;
2634 dirtyWidth = dirtyWidth+dirtyX;
2639 dirtyHeight = dirtyHeight+dirtyY;
2643 if (dirtyX+dirtyWidth > w) {
2644 dirtyWidth = w - dirtyX;
2647 if (dirtyY+dirtyHeight > h) {
2648 dirtyHeight = h - dirtyY;
2651 if (dirtyWidth <=0 || dirtyHeight <= 0)
2660 QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2661 r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
2667 \qmlclass QtQuick2::CanvasGradient
2668 \inqmlmodule QtQuick 2
2670 \brief The Context2D opaque CanvasGradient interface.
2674 \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
2675 Adds a color stop with the given color to the gradient at the given offset.
2676 0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
2680 var gradient = ctx.createLinearGradient(0, 0, 100, 100);
2681 gradient.addColorStop(0.3, Qt.rgba(1, 0, 0, 1));
2682 gradient.addColorStop(0.7, 'rgba(0, 255, 255, 1');
2685 static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
2687 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
2689 V8THROW_ERROR("Not a CanvasGradient object");
2691 QV8Engine *engine = V8ENGINE();
2693 if (args.Length() == 2) {
2695 if (!style->brush.gradient())
2696 V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
2697 QGradient gradient = *(style->brush.gradient());
2698 qreal pos = args[0]->NumberValue();
2701 if (args[1]->IsObject()) {
2702 color = engine->toVariant(args[1], qMetaTypeId<QColor>()).value<QColor>();
2704 color = qt_color_from_string(args[1]);
2706 if (pos < 0.0 || pos > 1.0 || !qIsFinite(pos)) {
2707 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
2710 if (color.isValid()) {
2711 gradient.setColorAt(pos, color);
2713 V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string");
2715 style->brush = gradient;
2721 void QQuickContext2D::scale(qreal x, qreal y)
2723 if (!state.invertibleCTM)
2726 if (!qIsFinite(x) || !qIsFinite(y))
2729 QTransform newTransform = state.matrix;
2730 newTransform.scale(x, y);
2732 if (!newTransform.isInvertible()) {
2733 state.invertibleCTM = false;
2737 state.matrix = newTransform;
2738 buffer()->updateMatrix(state.matrix);
2739 m_path = QTransform().scale(1.0 / x, 1.0 / y).map(m_path);
2742 void QQuickContext2D::rotate(qreal angle)
2744 if (!state.invertibleCTM)
2747 if (!qIsFinite(angle))
2750 QTransform newTransform =state.matrix;
2751 newTransform.rotate(DEGREES(angle));
2753 if (!newTransform.isInvertible()) {
2754 state.invertibleCTM = false;
2758 state.matrix = newTransform;
2759 buffer()->updateMatrix(state.matrix);
2760 m_path = QTransform().rotate(-DEGREES(angle)).map(m_path);
2763 void QQuickContext2D::shear(qreal h, qreal v)
2765 if (!state.invertibleCTM)
2768 if (!qIsFinite(h) || !qIsFinite(v))
2771 QTransform newTransform = state.matrix;
2772 newTransform.shear(h, v);
2774 if (!newTransform.isInvertible()) {
2775 state.invertibleCTM = false;
2779 state.matrix = newTransform;
2780 buffer()->updateMatrix(state.matrix);
2781 m_path = QTransform().shear(-h, -v).map(m_path);
2784 void QQuickContext2D::translate(qreal x, qreal y)
2786 if (!state.invertibleCTM)
2789 if (!qIsFinite(x) || !qIsFinite(y))
2792 QTransform newTransform = state.matrix;
2793 newTransform.translate(x, y);
2795 if (!newTransform.isInvertible()) {
2796 state.invertibleCTM = false;
2800 state.matrix = newTransform;
2801 buffer()->updateMatrix(state.matrix);
2802 m_path = QTransform().translate(-x, -y).map(m_path);
2805 void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
2807 if (!state.invertibleCTM)
2810 if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
2813 QTransform transform(a, b, c, d, e, f);
2814 QTransform newTransform = state.matrix * transform;
2816 if (!newTransform.isInvertible()) {
2817 state.invertibleCTM = false;
2820 state.matrix = newTransform;
2821 buffer()->updateMatrix(state.matrix);
2822 m_path = transform.inverted().map(m_path);
2825 void QQuickContext2D::setTransform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
2827 if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
2830 QTransform ctm = state.matrix;
2831 if (!ctm.isInvertible())
2834 state.matrix = ctm.inverted() * state.matrix;
2835 m_path = ctm.map(m_path);
2836 state.invertibleCTM = true;
2837 transform(a, b, c, d, e, f);
2840 void QQuickContext2D::fill()
2842 if (!state.invertibleCTM)
2845 if (!m_path.elementCount())
2848 m_path.setFillRule(state.fillRule);
2849 buffer()->fill(m_path);
2852 void QQuickContext2D::clip()
2854 if (!state.invertibleCTM)
2857 QPainterPath clipPath = m_path;
2858 clipPath.closeSubpath();
2859 if (!state.clipPath.isEmpty())
2860 state.clipPath = clipPath.intersected(state.clipPath);
2862 state.clipPath = clipPath;
2863 buffer()->clip(state.clipPath);
2866 void QQuickContext2D::stroke()
2868 if (!state.invertibleCTM)
2871 if (!m_path.elementCount())
2874 buffer()->stroke(m_path);
2877 void QQuickContext2D::fillRect(qreal x, qreal y, qreal w, qreal h)
2879 if (!state.invertibleCTM)
2882 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2885 buffer()->fillRect(x, y, w, h);
2888 void QQuickContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
2890 if (!state.invertibleCTM)
2893 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2896 buffer()->strokeRect(x, y, w, h);
2899 void QQuickContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
2901 if (!state.invertibleCTM)
2904 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2907 buffer()->clearRect(x, y, w, h);
2910 void QQuickContext2D::drawText(const QString& text, qreal x, qreal y, bool fill)
2912 if (!state.invertibleCTM)
2915 if (!qIsFinite(x) || !qIsFinite(y))
2918 QPainterPath textPath = createTextGlyphs(x, y, text);
2920 buffer()->fill(textPath);
2922 buffer()->stroke(textPath);
2926 void QQuickContext2D::beginPath()
2928 if (!m_path.elementCount())
2930 m_path = QPainterPath();
2933 void QQuickContext2D::closePath()
2935 if (!m_path.elementCount())
2938 QRectF boundRect = m_path.boundingRect();
2939 if (boundRect.width() || boundRect.height())
2940 m_path.closeSubpath();
2941 //FIXME:QPainterPath set the current point to (0,0) after close subpath
2942 //should be the first point of the previous subpath
2945 void QQuickContext2D::moveTo( qreal x, qreal y)
2947 if (!state.invertibleCTM)
2950 //FIXME: moveTo should not close the previous subpath
2951 m_path.moveTo(QPointF(x, y));
2954 void QQuickContext2D::lineTo( qreal x, qreal y)
2956 if (!state.invertibleCTM)
2961 if (!m_path.elementCount())
2963 else if (m_path.currentPosition() != pt)
2967 void QQuickContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
2970 if (!state.invertibleCTM)
2973 if (!m_path.elementCount())
2974 m_path.moveTo(QPointF(cpx, cpy));
2977 if (m_path.currentPosition() != pt)
2978 m_path.quadTo(QPointF(cpx, cpy), pt);
2981 void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
2982 qreal cp2x, qreal cp2y,
2985 if (!state.invertibleCTM)
2988 if (!m_path.elementCount())
2989 m_path.moveTo(QPointF(cp1x, cp1y));
2992 if (m_path.currentPosition() != pt)
2993 m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y), pt);
2996 void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
2998 QPointF p0(m_path.currentPosition());
3000 QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
3001 QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
3002 float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
3003 float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
3005 double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
3007 // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
3008 // We could have used areCollinear() here, but since we're reusing
3009 // the variables computed above later on we keep this logic.
3010 if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
3015 float tangent = radius / tan(acos(cos_phi) / 2);
3016 float factor_p1p0 = tangent / p1p0_length;
3017 QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
3019 QPointF orth_p1p0(p1p0.y(), -p1p0.x());
3020 float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
3021 float factor_ra = radius / orth_p1p0_length;
3023 // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
3024 double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
3025 if (cos_alpha < 0.f)
3026 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3028 QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
3030 // calculate angles for addArc
3031 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3032 float sa = acos(orth_p1p0.x() / orth_p1p0_length);
3033 if (orth_p1p0.y() < 0.f)
3036 // anticlockwise logic
3037 bool anticlockwise = false;
3039 float factor_p1p2 = tangent / p1p2_length;
3040 QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
3041 QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
3042 float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
3043 float ea = acos(orth_p1p2.x() / orth_p1p2_length);
3044 if (orth_p1p2.y() < 0)
3046 if ((sa > ea) && ((sa - ea) < Q_PI))
3047 anticlockwise = true;
3048 if ((sa < ea) && ((ea - sa) > Q_PI))
3049 anticlockwise = true;
3051 arc(p.x(), p.y(), radius, sa, ea, anticlockwise);
3054 void QQuickContext2D::arcTo(qreal x1, qreal y1,
3058 if (!state.invertibleCTM)
3061 if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2) || !qIsFinite(radius))
3065 QPointF end(x2, y2);
3067 if (!m_path.elementCount())
3069 else if (st == m_path.currentPosition() || st == end || !radius)
3072 addArcTo(st, end, radius);
3075 void QQuickContext2D::rect(qreal x, qreal y, qreal w, qreal h)
3077 if (!state.invertibleCTM)
3079 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
3083 m_path.moveTo(x, y);
3086 m_path.addRect(x, y, w, h);
3089 void QQuickContext2D::roundedRect(qreal x, qreal y,
3093 if (!state.invertibleCTM)
3096 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h) || !qIsFinite(xr) || !qIsFinite(yr))
3100 m_path.moveTo(x, y);
3103 m_path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
3106 void QQuickContext2D::ellipse(qreal x, qreal y,
3109 if (!state.invertibleCTM)
3112 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
3116 m_path.moveTo(x, y);
3120 m_path.addEllipse(x, y, w, h);
3123 void QQuickContext2D::text(const QString& str, qreal x, qreal y)
3125 if (!state.invertibleCTM)
3129 path.addText(x, y, state.font, str);
3130 m_path.addPath(path);
3133 void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear, bool antiClockWise)
3135 if (!state.invertibleCTM)
3138 if (!qIsFinite(xc) || !qIsFinite(yc) || !qIsFinite(sar) || !qIsFinite(ear) || !qIsFinite(radius))
3147 // In Qt we don't switch the coordinate system for degrees
3148 // and still use the 0,0 as bottom left for degrees so we need
3152 antiClockWise = !antiClockWise;
3155 float sa = DEGREES(sar);
3156 float ea = DEGREES(ear);
3160 double xs = xc - radius;
3161 double ys = yc - radius;
3162 double width = radius*2;
3163 double height = radius*2;
3164 if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
3165 // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
3166 // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
3167 // circumference of this circle.
3170 if (!antiClockWise && (ea < sa)) {
3172 } else if (antiClockWise && (sa < ea)) {
3175 //### this is also due to switched coordinate system
3176 // we would end up with a 0 span instead of 360
3177 if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
3178 qFuzzyCompare(qAbs(span), 360))) {
3183 // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
3184 if (!m_path.elementCount())
3185 m_path.arcMoveTo(xs, ys, width, height, sa);
3187 m_path.lineTo(xc, yc);
3191 m_path.arcTo(xs, ys, width, height, sa, span);
3194 int baseLineOffset(QQuickContext2D::TextBaseLineType value, const QFontMetrics &metrics)
3198 case QQuickContext2D::Top:
3200 case QQuickContext2D::Alphabetic:
3201 case QQuickContext2D::Middle:
3202 case QQuickContext2D::Hanging:
3203 offset = metrics.ascent();
3205 case QQuickContext2D::Bottom:
3206 offset = metrics.height();
3212 static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
3215 if (value == QQuickContext2D::Start)
3216 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Left : QQuickContext2D::Right;
3217 else if (value == QQuickContext2D::End)
3218 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Right: QQuickContext2D::Left;
3220 case QQuickContext2D::Center:
3221 offset = metrics.width(text)/2;
3223 case QQuickContext2D::Right:
3224 offset = metrics.width(text);
3225 case QQuickContext2D::Left:
3233 QImage QQuickContext2D::createImage(const QUrl& url)
3235 return m_canvas->loadedImage(url);
3238 QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
3240 const QFontMetrics metrics(state.font);
3241 int yoffset = baseLineOffset(static_cast<QQuickContext2D::TextBaseLineType>(state.textBaseline), metrics);
3242 int xoffset = textAlignOffset(static_cast<QQuickContext2D::TextAlignType>(state.textAlign), metrics, text);
3244 QPainterPath textPath;
3246 textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
3247 textPath = state.matrix.map(textPath);
3252 static inline bool areCollinear(const QPointF& a, const QPointF& b, const QPointF& c)
3254 // Solved from comparing the slopes of a to b and b to c: (ay-by)/(ax-bx) == (cy-by)/(cx-bx)
3255 return qFuzzyCompare((c.y() - b.y()) * (a.x() - b.x()), (a.y() - b.y()) * (c.x() - b.x()));
3258 static inline bool withinRange(qreal p, qreal a, qreal b)
3260 return (p >= a && p <= b) || (p >= b && p <= a);
3263 bool QQuickContext2D::isPointInPath(qreal x, qreal y) const
3265 if (!state.invertibleCTM)
3268 if (!m_path.elementCount())
3271 if (!qIsFinite(x) || !qIsFinite(y))
3274 QPointF point(x, y);
3275 QTransform ctm = state.matrix;
3276 QPointF p = ctm.inverted().map(point);
3277 if (!qIsFinite(p.x()) || !qIsFinite(p.y()))
3280 const_cast<QQuickContext2D *>(this)->m_path.setFillRule(state.fillRule);
3282 bool contains = m_path.contains(p);
3285 // check whether the point is on the border
3286 QPolygonF border = m_path.toFillPolygon();
3288 QPointF p1 = border.at(0);
3291 for (int i = 1; i < border.size(); ++i) {
3293 if (areCollinear(p, p1, p2)
3294 // Once we know that the points are collinear we
3295 // only need to check one of the coordinates
3296 && (qAbs(p2.x() - p1.x()) > qAbs(p2.y() - p1.y()) ?
3297 withinRange(p.x(), p1.x(), p2.x()) :
3298 withinRange(p.y(), p1.y(), p2.y()))) {
3307 QQuickContext2D::QQuickContext2D(QObject *parent)
3308 : QQuickCanvasContext(parent)
3309 , m_buffer(new QQuickContext2DCommandBuffer)
3314 QQuickContext2D::~QQuickContext2D()
3319 v8::Handle<v8::Object> QQuickContext2D::v8value() const
3324 QStringList QQuickContext2D::contextNames() const
3326 return QStringList() << QLatin1String("2d");
3329 void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args)
3333 m_canvas = canvasItem;
3334 m_renderTarget = canvasItem->renderTarget();
3336 // For the FBO target we only (currently) support Cooperative
3337 if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
3338 canvasItem->setRenderStrategy(QQuickCanvasItem::Cooperative);
3341 m_renderStrategy = canvasItem->renderStrategy();
3343 switch (m_renderTarget) {
3344 case QQuickCanvasItem::Image:
3345 m_texture = new QQuickContext2DImageTexture(m_renderStrategy == QQuickCanvasItem::Threaded);
3347 case QQuickCanvasItem::FramebufferObject:
3348 m_texture = new QQuickContext2DFBOTexture;
3352 m_texture->setItem(canvasItem);
3353 m_texture->setCanvasWindow(canvasItem->canvasWindow().toRect());
3354 m_texture->setTileSize(canvasItem->tileSize());
3355 m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
3356 m_texture->setSmooth(canvasItem->smooth());
3358 connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
3363 void QQuickContext2D::prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth)
3365 m_texture->canvasChanged(canvasSize, tileSize, canvasWindow, dirtyRect, smooth);
3368 void QQuickContext2D::flush()
3370 if (!m_buffer->isEmpty()) {
3371 QMutexLocker lock(&m_bufferMutex);
3372 m_bufferQueue.enqueue(m_buffer);
3373 m_buffer = new QQuickContext2DCommandBuffer;
3377 switch (m_renderStrategy) {
3378 case QQuickCanvasItem::Immediate:
3379 // Cause the texture to consume paint commands immediately
3382 case QQuickCanvasItem::Threaded:
3383 // wake up thread to consume paint commands
3386 case QQuickCanvasItem::Cooperative:
3387 // NOTE: On SG Thread
3393 QSGDynamicTexture *QQuickContext2D::texture() const
3398 QImage QQuickContext2D::toImage(const QRectF& bounds)
3400 switch (m_renderStrategy) {
3401 case QQuickCanvasItem::Immediate:
3402 case QQuickCanvasItem::Threaded:
3405 case QQuickCanvasItem::Cooperative:
3409 return m_texture->toImage(bounds);
3413 QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
3415 v8::HandleScope handle_scope;
3416 v8::Context::Scope scope(engine->context());
3418 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
3419 ft->InstanceTemplate()->SetHasExternalResource(true);
3420 ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine));
3421 ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine));
3422 ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine));
3423 ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine));
3424 ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine));
3425 ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine));
3426 ft->PrototypeTemplate()->Set(v8::String::New("resetTransform"), V8FUNCTION(ctx2d_resetTransform, engine));
3427 ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine));
3428 ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine));
3429 ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine));
3430 ft->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, engine));
3431 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine));
3432 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine));
3433 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillRule"), ctx2d_fillRule, ctx2d_fillRule_set, v8::External::Wrap(engine));
3434 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine));
3435 ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
3436 ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
3437 ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
3438 ft->PrototypeTemplate()->Set(v8::String::New("createConicalGradient"), V8FUNCTION(ctx2d_createConicalGradient, engine));
3439 ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
3440 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
3441 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
3442 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine));
3443 ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine));
3444 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine));
3445 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine));
3446 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine));
3447 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine));
3448 ft->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_set, v8::External::Wrap(engine));
3449 ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine));
3450 ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine));
3451 ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine));
3452 ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine));
3453 ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine));
3454 ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine));
3455 ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine));
3456 ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine));
3457 ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine));
3458 ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine));
3459 ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine));
3460 ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine));
3461 ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine));
3462 ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine));
3463 ft->PrototypeTemplate()->Set(v8::String::New("roundedRect"), V8FUNCTION(ctx2d_roundedRect, engine));
3464 ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
3465 ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine));
3466 ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine));
3467 ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine));
3468 ft->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
3469 ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
3470 ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, engine));
3471 ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine));
3472 ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine));
3473 ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine));
3474 ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine));
3475 ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine));
3476 ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine));
3477 ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine));
3478 ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine));
3479 ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine));
3480 ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine));
3482 constructorContext = qPersistentNew(ft->GetFunction());
3484 v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
3485 ftGradient->InstanceTemplate()->SetHasExternalResource(true);
3486 ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
3487 constructorGradient = qPersistentNew(ftGradient->GetFunction());
3489 v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
3490 ftPattern->InstanceTemplate()->SetHasExternalResource(true);
3491 constructorPattern = qPersistentNew(ftPattern->GetFunction());
3493 v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
3494 ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
3495 ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
3496 ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
3497 constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
3499 v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
3500 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
3501 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
3502 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
3503 ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
3504 constructorImageData = qPersistentNew(ftImageData->GetFunction());
3507 QQuickContext2DEngineData::~QQuickContext2DEngineData()
3509 qPersistentDispose(constructorContext);
3510 qPersistentDispose(constructorGradient);
3511 qPersistentDispose(constructorPattern);
3512 qPersistentDispose(constructorImageData);
3513 qPersistentDispose(constructorPixelArray);
3516 void QQuickContext2D::popState()
3518 if (m_stateStack.isEmpty())
3521 QQuickContext2D::State newState = m_stateStack.pop();
3523 if (state.matrix != newState.matrix)
3524 buffer()->updateMatrix(newState.matrix);
3526 if (newState.globalAlpha != state.globalAlpha)
3527 buffer()->setGlobalAlpha(newState.globalAlpha);
3529 if (newState.globalCompositeOperation != state.globalCompositeOperation)
3530 buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
3532 if (newState.fillStyle != state.fillStyle)
3533 buffer()->setFillStyle(newState.fillStyle);
3535 if (newState.strokeStyle != state.strokeStyle)
3536 buffer()->setStrokeStyle(newState.strokeStyle);
3538 if (newState.lineWidth != state.lineWidth)
3539 buffer()->setLineWidth(newState.lineWidth);
3541 if (newState.lineCap != state.lineCap)
3542 buffer()->setLineCap(newState.lineCap);
3544 if (newState.lineJoin != state.lineJoin)
3545 buffer()->setLineJoin(newState.lineJoin);
3547 if (newState.miterLimit != state.miterLimit)
3548 buffer()->setMiterLimit(newState.miterLimit);
3550 if (newState.clipPath != state.clipPath) {
3551 buffer()->clip(newState.clipPath);
3554 if (newState.shadowBlur != state.shadowBlur)
3555 buffer()->setShadowBlur(newState.shadowBlur);
3557 if (newState.shadowColor != state.shadowColor)
3558 buffer()->setShadowColor(newState.shadowColor);
3560 if (newState.shadowOffsetX != state.shadowOffsetX)
3561 buffer()->setShadowOffsetX(newState.shadowOffsetX);
3563 if (newState.shadowOffsetY != state.shadowOffsetY)
3564 buffer()->setShadowOffsetY(newState.shadowOffsetY);
3565 m_path = state.matrix.map(m_path);
3567 m_path = state.matrix.inverted().map(m_path);
3569 void QQuickContext2D::pushState()
3571 m_stateStack.push(state);
3574 void QQuickContext2D::reset()
3576 QQuickContext2D::State newState;
3577 newState.matrix = QTransform();
3579 m_path = QPainterPath();
3581 QPainterPath defaultClipPath;
3583 QRect r(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
3584 r = r.united(m_canvas->canvasWindow().toRect());
3585 defaultClipPath.addRect(r);
3586 newState.clipPath = defaultClipPath;
3587 newState.clipPath.setFillRule(Qt::WindingFill);
3589 newState.strokeStyle = QColor("#000000");
3590 newState.fillStyle = QColor("#000000");
3591 newState.fillPatternRepeatX = false;
3592 newState.fillPatternRepeatY = false;
3593 newState.strokePatternRepeatX = false;
3594 newState.strokePatternRepeatY = false;
3595 newState.invertibleCTM = true;
3596 newState.fillRule = Qt::WindingFill;
3597 newState.globalAlpha = 1.0;
3598 newState.lineWidth = 1;
3599 newState.lineCap = Qt::FlatCap;
3600 newState.lineJoin = Qt::MiterJoin;
3601 newState.miterLimit = 10;
3602 newState.shadowOffsetX = 0;
3603 newState.shadowOffsetY = 0;
3604 newState.shadowBlur = 0;
3605 newState.shadowColor = qRgba(0, 0, 0, 0);
3606 newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
3607 newState.font = QFont(QLatin1String("sans-serif"), 10);
3608 newState.textAlign = QQuickContext2D::Start;
3609 newState.textBaseline = QQuickContext2D::Alphabetic;
3611 m_stateStack.clear();
3612 m_stateStack.push(newState);
3614 m_buffer->clearRect(0, 0, m_canvas->width(), m_canvas->height());
3617 void QQuickContext2D::setV8Engine(QV8Engine *engine)
3619 v8::HandleScope handle_scope;
3620 v8::Context::Scope scope(engine->context());
3622 if (m_v8engine != engine) {
3623 m_v8engine = engine;
3625 qPersistentDispose(m_v8value);
3627 if (m_v8engine == 0)
3630 QQuickContext2DEngineData *ed = engineData(engine);
3631 m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
3632 QV8Context2DResource *r = new QV8Context2DResource(engine);
3634 m_v8value->SetExternalResource(r);
3638 QQuickContext2DCommandBuffer* QQuickContext2D::nextBuffer()
3640 QMutexLocker lock(&m_bufferMutex);
3641 return m_bufferQueue.isEmpty() ? 0 : m_bufferQueue.dequeue();