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>
64 #include <private/qquickwindow_p.h>
65 #include <private/qquickwindowmanager_p.h>
66 #include <QtGui/private/qguiapplication_p.h>
67 #include <qpa/qplatformintegration.h>
76 \instantiates QQuickContext2D
77 \inqmlmodule QtQuick 2
78 \ingroup qtquick-canvas
80 \brief Provides 2D context for shapes on a Canvas item
82 The Context2D object can be created by \c Canvas item's \c getContext()
88 var ctx = canvas.getContext('2d');
93 The Context2D API implements the same \l
94 {http://www.w3.org/TR/2dcontext}{W3C Canvas 2D Context API standard} with
95 some enhanced features.
97 The Context2D API provides the rendering \b{context} which defines the
98 methods and attributes needed to draw on the \c Canvas item. The following
99 assigns the canvas rendering context to a \c{context} variable:
101 var context = mycanvas.getContext("2d")
104 The Context2D API renders the canvas as a coordinate system whose origin
105 (0,0) is at the top left corner, as shown in the figure below. Coordinates
106 increase along the \c{x} axis from left to right and along the \c{y} axis
107 from top to bottom of the canvas.
108 \image qml-item-canvas-context.gif
113 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
115 static const double Q_PI = 3.14159265358979323846; // pi
117 #define DEGREES(t) ((t) * 180.0 / Q_PI)
119 #define CHECK_CONTEXT(r) if (!r || !r->context || !r->context->bufferValid()) \
120 V8THROW_ERROR("Not a Context2D object");
122 #define CHECK_CONTEXT_SETTER(r) if (!r || !r->context || !r->context->bufferValid()) \
123 V8THROW_ERROR_SETTER("Not a Context2D object");
124 #define qClamp(val, min, max) qMin(qMax(val, min), max)
125 #define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
126 QColor qt_color_from_string(v8::Local<v8::Value> name)
128 v8::String::AsciiValue str(name);
131 int len = str.length();
132 //rgb/hsl color string has at least 7 characters
133 if (!p || len > 255 || len <= 7)
136 bool isRgb(false), isHsl(false), hasAlpha(false);
139 while (isspace(*p)) p++;
140 if (strncmp(p, "rgb", 3) == 0)
142 else if (strncmp(p, "hsl", 3) == 0)
147 p+=3; //skip "rgb" or "hsl"
148 hasAlpha = (*p == 'a') ? true : false;
152 if (hasAlpha) ++p; //skip "a"
154 int rh, gs, bl, alpha = 255;
157 while (isspace(*p)) p++;
158 rh = strtol(p, &p, 10);
160 rh = qRound(rh/100.0 * 255);
163 if (*p++ != ',') return QColor();
166 while (isspace(*p)) p++;
167 gs = strtol(p, &p, 10);
169 gs = qRound(gs/100.0 * 255);
172 if (*p++ != ',') return QColor();
175 while (isspace(*p)) p++;
176 bl = strtol(p, &p, 10);
178 bl = qRound(bl/100.0 * 255);
183 if (*p++!= ',') return QColor();
184 while (isspace(*p)) p++;
186 alpha = qRound(qstrtod(p, const_cast<const char **>(&p), &ok) * 255);
189 if (*p != ')') return QColor();
191 return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)));
193 return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255));
198 QFont qt_font_from_string(const QString& fontString) {
200 // ### this is simplified and incomplete
201 // ### TODO:get code from Qt webkit
202 const QStringList tokens = fontString.split(QLatin1Char(' '));
203 foreach (const QString &token, tokens) {
204 if (token == QLatin1String("italic"))
205 font.setItalic(true);
206 else if (token == QLatin1String("bold"))
208 else if (token.endsWith(QLatin1String("px"))) {
209 QString number = token;
210 number.remove(QLatin1String("px"));
211 //font.setPointSizeF(number.trimmed().toFloat());
212 font.setPixelSize(number.trimmed().toInt());
214 font.setFamily(token);
222 class QQuickContext2DEngineData : public QV8Engine::Deletable
225 QQuickContext2DEngineData(QV8Engine *engine);
226 ~QQuickContext2DEngineData();
228 v8::Persistent<v8::Function> constructorContext;
229 v8::Persistent<v8::Function> constructorGradient;
230 v8::Persistent<v8::Function> constructorPattern;
231 v8::Persistent<v8::Function> constructorPixelArray;
232 v8::Persistent<v8::Function> constructorImageData;
235 V8_DEFINE_EXTENSION(QQuickContext2DEngineData, engineData)
237 class QV8Context2DResource : public QV8ObjectResource
239 V8_RESOURCE_TYPE(Context2DType)
241 QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e), context(0) {}
242 QQuickContext2D* context;
245 class QV8Context2DStyleResource : public QV8ObjectResource
247 V8_RESOURCE_TYPE(Context2DStyleType)
249 QV8Context2DStyleResource(QV8Engine *e)
250 : QV8ObjectResource(e)
251 , patternRepeatX(false)
252 , patternRepeatY(false)
255 bool patternRepeatX:1;
256 bool patternRepeatY:1;
259 class QV8Context2DPixelArrayResource : public QV8ObjectResource
261 V8_RESOURCE_TYPE(Context2DPixelArrayType)
263 QV8Context2DPixelArrayResource(QV8Engine *e) : QV8ObjectResource(e) {}
268 QImage qt_image_convolute_filter(const QImage& src, const QVector<qreal>& weights, int radius = 0)
270 int sides = radius ? radius : qRound(qSqrt(weights.size()));
271 int half = qFloor(sides/2);
273 QImage dst = QImage(src.size(), src.format());
275 int h = src.height();
276 for (int y = 0; y < dst.height(); ++y) {
277 QRgb *dr = (QRgb*)dst.scanLine(y);
278 for (int x = 0; x < dst.width(); ++x) {
279 unsigned char* dRgb = ((unsigned char*)&dr[x]);
280 unsigned char red=0, green=0, blue=0, alpha=0;
284 for (int cy=0; cy<sides; cy++) {
285 for (int cx=0; cx<sides; cx++) {
286 int scy = sy + cy - half;
287 int scx = sx + cx - half;
288 if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
289 const QRgb *sr = (const QRgb*)(src.constScanLine(scy));
290 const unsigned char* sRgb = ((const unsigned char*)&sr[scx]);
291 qreal wt = radius ? weights[0] : weights[cy*sides+cx];
293 green += sRgb[1] * wt;
294 blue += sRgb[2] * wt;
295 alpha += sRgb[3] * wt;
308 void qt_image_boxblur(QImage& image, int radius, bool quality)
310 int passes = quality? 3: 1;
311 for (int i=0; i < passes; i++) {
312 image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0/(radius * radius * 1.0), radius);
316 static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
318 if (compositeOperator == QLatin1String("source-over")) {
319 return QPainter::CompositionMode_SourceOver;
320 } else if (compositeOperator == QLatin1String("source-out")) {
321 return QPainter::CompositionMode_SourceOut;
322 } else if (compositeOperator == QLatin1String("source-in")) {
323 return QPainter::CompositionMode_SourceIn;
324 } else if (compositeOperator == QLatin1String("source-atop")) {
325 return QPainter::CompositionMode_SourceAtop;
326 } else if (compositeOperator == QLatin1String("destination-atop")) {
327 return QPainter::CompositionMode_DestinationAtop;
328 } else if (compositeOperator == QLatin1String("destination-in")) {
329 return QPainter::CompositionMode_DestinationIn;
330 } else if (compositeOperator == QLatin1String("destination-out")) {
331 return QPainter::CompositionMode_DestinationOut;
332 } else if (compositeOperator == QLatin1String("destination-over")) {
333 return QPainter::CompositionMode_DestinationOver;
334 } else if (compositeOperator == QLatin1String("lighter")) {
335 return QPainter::CompositionMode_Lighten;
336 } else if (compositeOperator == QLatin1String("copy")) {
337 return QPainter::CompositionMode_Source;
338 } else if (compositeOperator == QLatin1String("xor")) {
339 return QPainter::CompositionMode_Xor;
340 } else if (compositeOperator == QLatin1String("qt-clear")) {
341 return QPainter::CompositionMode_Clear;
342 } else if (compositeOperator == QLatin1String("qt-destination")) {
343 return QPainter::CompositionMode_Destination;
344 } else if (compositeOperator == QLatin1String("qt-multiply")) {
345 return QPainter::CompositionMode_Multiply;
346 } else if (compositeOperator == QLatin1String("qt-screen")) {
347 return QPainter::CompositionMode_Screen;
348 } else if (compositeOperator == QLatin1String("qt-overlay")) {
349 return QPainter::CompositionMode_Overlay;
350 } else if (compositeOperator == QLatin1String("qt-darken")) {
351 return QPainter::CompositionMode_Darken;
352 } else if (compositeOperator == QLatin1String("qt-lighten")) {
353 return QPainter::CompositionMode_Lighten;
354 } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
355 return QPainter::CompositionMode_ColorDodge;
356 } else if (compositeOperator == QLatin1String("qt-color-burn")) {
357 return QPainter::CompositionMode_ColorBurn;
358 } else if (compositeOperator == QLatin1String("qt-hard-light")) {
359 return QPainter::CompositionMode_HardLight;
360 } else if (compositeOperator == QLatin1String("qt-soft-light")) {
361 return QPainter::CompositionMode_SoftLight;
362 } else if (compositeOperator == QLatin1String("qt-difference")) {
363 return QPainter::CompositionMode_Difference;
364 } else if (compositeOperator == QLatin1String("qt-exclusion")) {
365 return QPainter::CompositionMode_Exclusion;
367 return QPainter::CompositionMode_SourceOver;
370 static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
373 case QPainter::CompositionMode_SourceOver:
374 return QLatin1String("source-over");
375 case QPainter::CompositionMode_DestinationOver:
376 return QLatin1String("destination-over");
377 case QPainter::CompositionMode_Clear:
378 return QLatin1String("qt-clear");
379 case QPainter::CompositionMode_Source:
380 return QLatin1String("copy");
381 case QPainter::CompositionMode_Destination:
382 return QLatin1String("qt-destination");
383 case QPainter::CompositionMode_SourceIn:
384 return QLatin1String("source-in");
385 case QPainter::CompositionMode_DestinationIn:
386 return QLatin1String("destination-in");
387 case QPainter::CompositionMode_SourceOut:
388 return QLatin1String("source-out");
389 case QPainter::CompositionMode_DestinationOut:
390 return QLatin1String("destination-out");
391 case QPainter::CompositionMode_SourceAtop:
392 return QLatin1String("source-atop");
393 case QPainter::CompositionMode_DestinationAtop:
394 return QLatin1String("destination-atop");
395 case QPainter::CompositionMode_Xor:
396 return QLatin1String("xor");
397 case QPainter::CompositionMode_Plus:
398 return QLatin1String("plus");
399 case QPainter::CompositionMode_Multiply:
400 return QLatin1String("qt-multiply");
401 case QPainter::CompositionMode_Screen:
402 return QLatin1String("qt-screen");
403 case QPainter::CompositionMode_Overlay:
404 return QLatin1String("qt-overlay");
405 case QPainter::CompositionMode_Darken:
406 return QLatin1String("qt-darken");
407 case QPainter::CompositionMode_Lighten:
408 return QLatin1String("lighter");
409 case QPainter::CompositionMode_ColorDodge:
410 return QLatin1String("qt-color-dodge");
411 case QPainter::CompositionMode_ColorBurn:
412 return QLatin1String("qt-color-burn");
413 case QPainter::CompositionMode_HardLight:
414 return QLatin1String("qt-hard-light");
415 case QPainter::CompositionMode_SoftLight:
416 return QLatin1String("qt-soft-light");
417 case QPainter::CompositionMode_Difference:
418 return QLatin1String("qt-difference");
419 case QPainter::CompositionMode_Exclusion:
420 return QLatin1String("qt-exclusion");
428 static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
430 QQuickContext2DEngineData *ed = engineData(engine);
431 v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
432 QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
433 if (image.isNull()) {
434 r->image = QImage(w, h, QImage::Format_ARGB32);
435 r->image.fill(0x00000000);
437 Q_ASSERT(image.width() == w && image.height() == h);
438 r->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
440 v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
441 pixelData->SetExternalResource(r);
443 imageData->SetInternalField(0, pixelData);
447 //static script functions
450 \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
451 Holds the canvas item that the context paints on.
453 This property is read only.
455 static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
457 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
461 QV8Engine *engine = V8ENGINE_ACCESSOR();
463 return engine->newQObject(r->context->canvas());
467 \qmlmethod object QtQuick2::Context2D::restore()
468 Pops the top state on the stack, restoring the context to that state.
470 \sa QtQuick2::Context2D::save()
472 static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
474 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
477 r->context->popState();
482 \qmlmethod object QtQuick2::Context2D::reset()
483 Resets the context state and properties to the default values.
485 static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
487 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
496 \qmlmethod object QtQuick2::Context2D::save()
497 Pushes the current state onto the state stack.
499 Before changing any state attributes, you should save the current state
500 for future reference. The context maintains a stack of drawing states.
501 Each state consists of the current transformation matrix, clipping region,
502 and values of the following attributes:
504 \li\a QtQuick2::Context2D::strokeStyle
505 \li\a QtQuick2::Context2D::fillStyle
506 \li\a QtQuick2::Context2D::fillRule
507 \li\a QtQuick2::Context2D::globalAlpha
508 \li\a QtQuick2::Context2D::lineWidth
509 \li\a QtQuick2::Context2D::lineCap
510 \li\a QtQuick2::Context2D::lineJoin
511 \li\a QtQuick2::Context2D::miterLimit
512 \li\a QtQuick2::Context2D::shadowOffsetX
513 \li\a QtQuick2::Context2D::shadowOffsetY
514 \li\a QtQuick2::Context2D::shadowBlur
515 \li\a QtQuick2::Context2D::shadowColor
516 \li\a QtQuick2::Context2D::globalCompositeOperation
517 \li\a QtQuick2::Context2D::font
518 \li\a QtQuick2::Context2D::textAlign
519 \li\a QtQuick2::Context2D::textBaseline
522 The current path is NOT part of the drawing state. The path can be reset by
523 invoking the \a QtQuick2::Context2D::beginPath() method.
525 static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
527 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
530 r->context->pushState();
537 \qmlmethod object QtQuick2::Context2D::rotate(real angle)
538 Rotate the canvas around the current origin by \c angle in radians and clockwise direction.
540 ctx.rotate(Math.PI/2);
542 \image qml-item-canvas-rotate.png
544 The rotation transformation matrix is as follows:
546 \image qml-item-canvas-math-rotate.png
548 where the \c angle of rotation is in radians.
551 static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
553 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
556 if (args.Length() == 1)
557 r->context->rotate(args[0]->NumberValue());
562 \qmlmethod object QtQuick2::Context2D::scale(real x, real y)
563 Increases or decreases the size of each unit in the canvas grid by multiplying the scale factors
564 to the current tranform matrix.
565 Where \c x is the scale factor in the horizontal direction and \c y is the scale factor in the
567 The following code doubles the horizontal size of an object drawn on the canvas and half its
572 \image qml-item-canvas-scale.png
575 static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
577 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
581 if (args.Length() == 2)
582 r->context->scale(args[0]->NumberValue(), args[1]->NumberValue());
587 \qmlmethod object QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
588 Changes the transformation matrix to the matrix given by the arguments as described below.
590 Modifying the transformation matrix directly enables you to perform scaling,
591 rotating, and translating transformations in a single step.
593 Each point on the canvas is multiplied by the matrix before anything is
594 drawn. The \l{HTML5 Canvas API} defines the transformation matrix as:
596 \image qml-item-canvas-math.png
599 \li \c{a} is the scale factor in the horizontal (x) direction
600 \image qml-item-canvas-scalex.png
601 \li \c{c} is the skew factor in the x direction
602 \image qml-item-canvas-canvas-skewx.png
603 \li \c{e} is the translation in the x direction
604 \image qml-item-canvas-canvas-translate.png
605 \li \c{b} is the skew factor in the y (vertical) direction
606 \image qml-item-canvas-canvas-skewy.png
607 \li \c{d} is the scale factor in the y direction
608 \image qml-item-canvas-canvas-scaley.png
609 \li \c{f} is the translation in the y direction
610 \image qml-item-canvas-canvas-translatey.png
611 \li the last row remains constant
613 The scale factors and skew factors are multiples; \c{e} and \c{f} are
614 coordinate space units, just like the units in the \a QtQuick2::Context2D::translate(x,y)
617 \sa QtQuick2::Context2D::transform()
619 static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
621 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
625 if (args.Length() == 6)
626 r->context->setTransform( args[0]->NumberValue()
627 , args[1]->NumberValue()
628 , args[2]->NumberValue()
629 , args[3]->NumberValue()
630 , args[4]->NumberValue()
631 , args[5]->NumberValue());
637 \qmlmethod object QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
638 This method is very similar to \a QtQuick2::Context2D::setTransform(), but instead of replacing the old
639 tranform matrix, this method applies the given tranform matrix to the current matrix by mulitplying to it.
641 The \a setTransform(a, b, c, d, e, f) method actually resets the current transform to the identity matrix,
642 and then invokes the transform(a, b, c, d, e, f) method with the same arguments.
644 \sa QtQuick2::Context2D::setTransform()
646 static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
648 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
652 if (args.Length() == 6)
653 r->context->transform( args[0]->NumberValue()
654 , args[1]->NumberValue()
655 , args[2]->NumberValue()
656 , args[3]->NumberValue()
657 , args[4]->NumberValue()
658 , args[5]->NumberValue());
664 \qmlmethod object QtQuick2::Context2D::translate(real x, real y)
665 Translates the origin of the canvas to point (\c x, \c y).
667 \c x is the horizontal distance that the origin is translated, in coordinate space units,
668 \c y is the vertical distance that the origin is translated, in coordinate space units.
669 Translating the origin enables you to draw patterns of different objects on the canvas
670 without having to measure the coordinates manually for each shape.
672 static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
674 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
678 if (args.Length() == 2)
679 r->context->translate(args[0]->NumberValue(), args[1]->NumberValue());
685 \qmlmethod object QtQuick2::Context2D::resetTransform()
686 Reset the transformation matrix to default value.
688 \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform(), QtQuick2::Context2D::reset()
690 static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
692 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
695 r->context->setTransform(1, 0, 0, 1, 0, 0);
702 \qmlmethod object QtQuick2::Context2D::shear(real sh, real sv )
703 Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
705 static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
707 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
710 if (args.Length() == 2)
711 r->context->shear(args[0]->NumberValue(), args[1]->NumberValue());
718 \qmlproperty real QtQuick2::Context2D::globalAlpha
719 Holds the the current alpha value applied to rendering operations.
720 The value must be in the range from 0.0 (fully transparent) to 1.0 (fully opque).
721 The default value is 1.0.
723 static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
725 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
728 return v8::Number::New(r->context->state.globalAlpha);
731 static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
733 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
734 CHECK_CONTEXT_SETTER(r)
736 qreal globalAlpha = value->NumberValue();
738 if (!qIsFinite(globalAlpha))
741 if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
742 r->context->state.globalAlpha = globalAlpha;
743 r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
748 \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
749 Holds the the current the current composition operation, from the list below:
751 \li source-atop - A atop B. Display the source image wherever both images are opaque.
752 Display the destination image wherever the destination image is opaque but the source image is transparent.
753 Display transparency elsewhere.
754 \li source-in - A in B. Display the source image wherever both the source image and destination image are opaque.
755 Display transparency elsewhere.
756 \li source-out - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
757 Display transparency elsewhere.
758 \li source-over - (default) A over B. Display the source image wherever the source image is opaque.
759 Display the destination image elsewhere.
760 \li destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
761 \li destination-in - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
762 \li destination-out - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
763 \li destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
764 \li lighter - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
765 \li copy - A (B is ignored). Display the source image instead of the destination image.
766 \li xor - A xor B. Exclusive OR of the source image and destination image.
769 Additionally, this property also accepts the compositon modes listed in \a {QPainter::CompositionMode}. According to the W3C standard, these
770 extension composition modes are provided as "vendorName-operationName" syntax, for example: \c {QPainter::CompositionMode_Exclusion} is porvided as
773 static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
775 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
779 QV8Engine *engine = V8ENGINE_ACCESSOR();
781 return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
784 static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
786 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
787 CHECK_CONTEXT_SETTER(r)
789 QV8Engine *engine = V8ENGINE_ACCESSOR();
792 QString mode = engine->toString(value);
793 QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
794 if (cm == QPainter::CompositionMode_SourceOver && mode != QStringLiteral("source-over"))
797 if (cm != r->context->state.globalCompositeOperation) {
798 r->context->state.globalCompositeOperation = cm;
799 r->context->buffer()->setGlobalCompositeOperation(cm);
805 \qmlproperty variant QtQuick2::Context2D::fillStyle
806 Holds the current style used for filling shapes.
807 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object. Invalid values are ignored.
808 This property accepts several color syntaxes:
810 \li 'rgb(red, green, blue)' - for example: 'rgb(255, 100, 55)' or 'rgb(100%, 70%, 30%)'
811 \li 'rgba(red, green, blue, alpha)' - for example: 'rgb(255, 100, 55, 1.0)' or 'rgb(100%, 70%, 30%, 0.5)'
812 \li 'hsl(hue, saturation, lightness)'
813 \li 'hsla(hue, saturation, lightness, alpha)'
814 \li '#RRGGBB' - for example: '#00FFCC'
815 \li Qt.rgba(red, green, blue, alpha) - for example: Qt.rgba(0.3, 0.7, 1, 1.0)
817 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
818 best performance, because it's already a valid QColor value, does not need to be parsed everytime.
820 The default value is '#000000'.
821 \sa QtQuick2::Context2D::createLinearGradient
822 \sa QtQuick2::Context2D::createRadialGradient
823 \sa QtQuick2::Context2D::createPattern
824 \sa QtQuick2::Context2D::strokeStyle
826 static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
828 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
831 QV8Engine *engine = V8ENGINE_ACCESSOR();
833 QColor color = r->context->state.fillStyle.color();
834 if (color.isValid()) {
835 if (color.alpha() == 255)
836 return engine->toString(color.name());
837 QString alphaString = QString::number(color.alphaF(), 'f');
838 while (alphaString.endsWith(QLatin1Char('0')))
840 if (alphaString.endsWith(QLatin1Char('.')))
841 alphaString += QLatin1Char('0');
842 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
844 return r->context->m_fillStyle;
847 static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
849 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
850 CHECK_CONTEXT_SETTER(r)
852 QV8Engine *engine = V8ENGINE_ACCESSOR();
854 if (value->IsObject()) {
855 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
856 if (color.isValid()) {
857 r->context->state.fillStyle = color;
858 r->context->buffer()->setFillStyle(color);
859 r->context->m_fillStyle = value;
861 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
862 if (style && style->brush != r->context->state.fillStyle) {
863 r->context->state.fillStyle = style->brush;
864 r->context->buffer()->setFillStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
865 r->context->m_fillStyle = value;
866 r->context->state.fillPatternRepeatX = style->patternRepeatX;
867 r->context->state.fillPatternRepeatY = style->patternRepeatY;
870 } else if (value->IsString()) {
871 QColor color = qt_color_from_string(value);
872 if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
873 r->context->state.fillStyle = QBrush(color);
874 r->context->buffer()->setFillStyle(r->context->state.fillStyle);
875 r->context->m_fillStyle = value;
880 \qmlproperty enumeration QtQuick2::Context2D::fillRule
881 Holds the current fill rule used for filling shapes. The following fill rules supported:
886 Note: Unlike the \a QPainterPath, the Canvas API uses the winding fill as the default fill rule.
887 The fillRule property is part of the context rendering state.
889 \sa QtQuick2::Context2D::fillStyle
891 static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
893 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
895 QV8Engine *engine = V8ENGINE_ACCESSOR();
897 return engine->fromVariant(r->context->state.fillRule);
900 static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
902 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
903 CHECK_CONTEXT_SETTER(r)
905 QV8Engine *engine = V8ENGINE_ACCESSOR();
907 if ((value->IsString() && engine->toString(value) == QStringLiteral("WindingFill"))
908 ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
909 r->context->state.fillRule = Qt::WindingFill;
910 } else if ((value->IsString() && engine->toString(value) == QStringLiteral("OddEvenFill"))
911 ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
912 r->context->state.fillRule = Qt::OddEvenFill;
916 r->context->m_path.setFillRule(r->context->state.fillRule);
919 \qmlproperty variant QtQuick2::Context2D::strokeStyle
920 Holds the current color or style to use for the lines around shapes,
921 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object.
922 Invalid values are ignored.
924 The default value is '#000000'.
926 \sa QtQuick2::Context2D::createLinearGradient
927 \sa QtQuick2::Context2D::createRadialGradient
928 \sa QtQuick2::Context2D::createPattern
929 \sa QtQuick2::Context2D::fillStyle
931 v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
933 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
936 QV8Engine *engine = V8ENGINE_ACCESSOR();
938 QColor color = r->context->state.strokeStyle.color();
939 if (color.isValid()) {
940 if (color.alpha() == 255)
941 return engine->toString(color.name());
942 QString alphaString = QString::number(color.alphaF(), 'f');
943 while (alphaString.endsWith(QLatin1Char('0')))
945 if (alphaString.endsWith(QLatin1Char('.')))
946 alphaString += QLatin1Char('0');
947 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
949 return r->context->m_strokeStyle;
952 static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
954 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
955 CHECK_CONTEXT_SETTER(r)
957 QV8Engine *engine = V8ENGINE_ACCESSOR();
959 if (value->IsObject()) {
960 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
961 if (color.isValid()) {
962 r->context->state.fillStyle = color;
963 r->context->buffer()->setStrokeStyle(color);
964 r->context->m_strokeStyle = value;
966 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
967 if (style && style->brush != r->context->state.strokeStyle) {
968 r->context->state.strokeStyle = style->brush;
969 r->context->buffer()->setStrokeStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
970 r->context->m_strokeStyle = value;
971 r->context->state.strokePatternRepeatX = style->patternRepeatX;
972 r->context->state.strokePatternRepeatY = style->patternRepeatY;
976 } else if (value->IsString()) {
977 QColor color = qt_color_from_string(value);
978 if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
979 r->context->state.strokeStyle = QBrush(color);
980 r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
981 r->context->m_strokeStyle = value;
987 \qmlmethod object QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
988 Returns a CanvasGradient object that represents a linear gradient that transitions the color along a line between
989 the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
991 A gradient is a smooth transition between colors. There are two types of gradients: linear and radial.
992 Gradients must have two or more color stops, representing color shifts positioned from 0 to 1 between
993 to the gradient's starting and end points or circles.
995 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
996 \sa QtQuick2::Context2D::createRadialGradient
997 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
998 \sa QtQuick2::Context2D::createPattern
999 \sa QtQuick2::Context2D::fillStyle
1000 \sa QtQuick2::Context2D::strokeStyle
1003 static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
1005 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1009 QV8Engine *engine = V8ENGINE();
1011 if (args.Length() == 4) {
1012 QQuickContext2DEngineData *ed = engineData(engine);
1013 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1014 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1015 qreal x0 = args[0]->NumberValue();
1016 qreal y0 = args[1]->NumberValue();
1017 qreal x1 = args[2]->NumberValue();
1018 qreal y1 = args[3]->NumberValue();
1023 || !qIsFinite(y1)) {
1025 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
1028 r->brush = QLinearGradient(x0, y0, x1, y1);
1029 gradient->SetExternalResource(r);
1037 \qmlmethod object QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
1038 Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
1039 origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
1041 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1042 \sa QtQuick2::Context2D::createLinearGradient
1043 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
1044 \sa QtQuick2::Context2D::createPattern
1045 \sa QtQuick2::Context2D::fillStyle
1046 \sa QtQuick2::Context2D::strokeStyle
1049 static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
1051 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1055 QV8Engine *engine = V8ENGINE();
1057 if (args.Length() == 6) {
1058 QQuickContext2DEngineData *ed = engineData(engine);
1059 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1060 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1062 qreal x0 = args[0]->NumberValue();
1063 qreal y0 = args[1]->NumberValue();
1064 qreal r0 = args[2]->NumberValue();
1065 qreal x1 = args[3]->NumberValue();
1066 qreal y1 = args[4]->NumberValue();
1067 qreal r1 = args[5]->NumberValue();
1074 || !qIsFinite(y1)) {
1076 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
1079 if (r0 < 0 || r1 < 0)
1080 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
1083 r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
1084 gradient->SetExternalResource(r);
1092 \qmlmethod object QtQuick2::Context2D::createConicalGradient(real x, real y, real angle)
1093 Returns a CanvasGradient object that represents a conical gradient that interpolate colors counter-clockwise around a center point (\c x, \c y)
1094 with start angle \c angle in units of radians.
1096 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1097 \sa QtQuick2::Context2D::createLinearGradient
1098 \sa QtQuick2::Context2D::ctx2d_createRadialGradient
1099 \sa QtQuick2::Context2D::createPattern
1100 \sa QtQuick2::Context2D::fillStyle
1101 \sa QtQuick2::Context2D::strokeStyle
1104 static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &args)
1106 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1110 QV8Engine *engine = V8ENGINE();
1112 if (args.Length() == 6) {
1113 QQuickContext2DEngineData *ed = engineData(engine);
1114 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1115 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1117 qreal x = args[0]->NumberValue();
1118 qreal y = args[1]->NumberValue();
1119 qreal angle = DEGREES(args[2]->NumberValue());
1120 if (!qIsFinite(x) || !qIsFinite(y)) {
1122 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
1125 if (!qIsFinite(angle)) {
1127 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
1130 r->brush = QConicalGradient(x, y, angle);
1131 gradient->SetExternalResource(r);
1138 \qmlmethod variant createPattern(Color color, enumeration patternMode)
1139 This is a overload function.
1140 Returns a CanvasPattern object that uses the given \c color and \c patternMode.
1141 The valid pattern modes are:
1144 \li Qt.Dense1Pattern
1145 \li Qt.Dense2Pattern
1146 \li Qt.Dense3Pattern
1147 \li Qt.Dense4Pattern
1148 \li Qt.Dense5Pattern
1149 \li Qt.Dense6Pattern
1150 \li Qt.Dense7Pattern
1156 \li Qt.DiagCrossPattern
1161 \qmlmethod variant createPattern(Image image, string repetition)
1162 Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
1164 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.
1166 The allowed values for \a repetition are:
1169 \li "repeat" - both directions
1170 \li "repeat-x - horizontal only
1171 \li "repeat-y" - vertical only
1172 \li "no-repeat" - neither
1175 If the repetition argument is empty or null, the value "repeat" is used.
1177 \sa QtQuick2::Context2D::strokeStyle
1178 \sa QtQuick2::Context2D::fillStyle
1180 static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
1182 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1186 QV8Engine *engine = V8ENGINE();
1188 if (args.Length() == 2) {
1189 QQuickContext2DEngineData *ed = engineData(engine);
1190 QV8Context2DStyleResource *styleResouce = new QV8Context2DStyleResource(engine);
1192 QColor color = engine->toVariant(args[0], qMetaTypeId<QColor>()).value<QColor>();
1193 if (color.isValid()) {
1194 int patternMode = args[1]->IntegerValue();
1195 Qt::BrushStyle style = Qt::SolidPattern;
1196 if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
1197 style = static_cast<Qt::BrushStyle>(patternMode);
1199 styleResouce->brush = QBrush(color, style);
1201 QImage patternTexture;
1203 if (args[0]->IsObject()) {
1204 QV8Context2DPixelArrayResource *pixelData = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->Get(v8::String::New("data"))->ToObject());
1206 patternTexture = pixelData->image;
1209 patternTexture = r->context->createPixmap(QUrl(engine->toString(args[0]->ToString())))->image();
1212 if (!patternTexture.isNull()) {
1213 styleResouce->brush.setTextureImage(patternTexture);
1215 QString repetition = engine->toString(args[1]);
1216 if (repetition == QStringLiteral("repeat") || repetition.isEmpty()) {
1217 styleResouce->patternRepeatX = true;
1218 styleResouce->patternRepeatY = true;
1219 } else if (repetition == QStringLiteral("repeat-x")) {
1220 styleResouce->patternRepeatX = true;
1221 } else if (repetition == QStringLiteral("repeat-y")) {
1222 styleResouce->patternRepeatY = true;
1223 } else if (repetition == QStringLiteral("no-repeat")) {
1224 styleResouce->patternRepeatY = false;
1225 styleResouce->patternRepeatY = false;
1227 //TODO: exception: SYNTAX_ERR
1233 v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
1234 pattern->SetExternalResource(styleResouce);
1238 return v8::Undefined();
1243 \qmlproperty string QtQuick2::Context2D::lineCap
1244 Holds the the current line cap style.
1245 The possible line cap styles are:
1247 \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.
1248 \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.
1249 \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.
1251 Other values are ignored.
1253 v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
1255 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1259 QV8Engine *engine = V8ENGINE_ACCESSOR();
1260 switch (r->context->state.lineCap) {
1262 return engine->toString(QLatin1String("round"));
1264 return engine->toString(QLatin1String("butt"));
1266 return engine->toString(QLatin1String("square"));
1270 return engine->toString(QLatin1String("butt"));;
1273 static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1275 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1276 CHECK_CONTEXT_SETTER(r)
1278 QV8Engine *engine = V8ENGINE_ACCESSOR();
1280 QString lineCap = engine->toString(value);
1281 Qt::PenCapStyle cap;
1282 if (lineCap == QLatin1String("round"))
1284 else if (lineCap == QLatin1String("butt"))
1286 else if (lineCap == QLatin1String("square"))
1287 cap = Qt::SquareCap;
1291 if (cap != r->context->state.lineCap) {
1292 r->context->state.lineCap = cap;
1293 r->context->buffer()->setLineCap(cap);
1298 \qmlproperty string QtQuick2::Context2D::lineJoin
1299 Holds the the current line join style. A join exists at any point in a subpath
1300 shared by two consecutive lines. When a subpath is closed, then a join also exists
1301 at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
1303 The possible line join styles are:
1305 \li bevel - this is all that is rendered at joins.
1306 \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.
1307 \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.
1309 Other values are ignored.
1311 v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
1313 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1317 QV8Engine *engine = V8ENGINE_ACCESSOR();
1318 switch (r->context->state.lineJoin) {
1320 return engine->toString(QLatin1String("round"));
1322 return engine->toString(QLatin1String("bevel"));
1324 return engine->toString(QLatin1String("miter"));
1328 return engine->toString(QLatin1String("miter"));
1331 static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1333 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1334 CHECK_CONTEXT_SETTER(r)
1336 QV8Engine *engine = V8ENGINE_ACCESSOR();
1338 QString lineJoin = engine->toString(value);
1339 Qt::PenJoinStyle join;
1340 if (lineJoin == QLatin1String("round"))
1341 join = Qt::RoundJoin;
1342 else if (lineJoin == QLatin1String("bevel"))
1343 join = Qt::BevelJoin;
1344 else if (lineJoin == QLatin1String("miter"))
1345 join = Qt::SvgMiterJoin;
1349 if (join != r->context->state.lineJoin) {
1350 r->context->state.lineJoin = join;
1351 r->context->buffer()->setLineJoin(join);
1356 \qmlproperty real QtQuick2::Context2D::lineWidth
1357 Holds the the current line width. Values that are not finite values greater than zero are ignored.
1359 v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
1361 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1365 return v8::Number::New(r->context->state.lineWidth);
1368 static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1370 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1371 CHECK_CONTEXT_SETTER(r)
1373 qreal w = value->NumberValue();
1375 if (w > 0 && qIsFinite(w) && w != r->context->state.lineWidth) {
1376 r->context->state.lineWidth = w;
1377 r->context->buffer()->setLineWidth(w);
1382 \qmlproperty real QtQuick2::Context2D::miterLimit
1383 Holds the current miter limit ratio.
1384 The default miter limit value is 10.0.
1386 v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
1388 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1392 return v8::Number::New(r->context->state.miterLimit);
1395 static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1397 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1398 CHECK_CONTEXT_SETTER(r)
1400 qreal ml = value->NumberValue();
1402 if (ml > 0 && qIsFinite(ml) && ml != r->context->state.miterLimit) {
1403 r->context->state.miterLimit = ml;
1404 r->context->buffer()->setMiterLimit(ml);
1410 \qmlproperty real QtQuick2::Context2D::shadowBlur
1411 Holds the current level of blur applied to shadows
1413 v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
1415 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1419 return v8::Number::New(r->context->state.shadowBlur);
1422 static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1424 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1425 CHECK_CONTEXT_SETTER(r)
1426 qreal blur = value->NumberValue();
1428 if (blur > 0 && qIsFinite(blur) && blur != r->context->state.shadowBlur) {
1429 r->context->state.shadowBlur = blur;
1430 r->context->buffer()->setShadowBlur(blur);
1435 \qmlproperty string QtQuick2::Context2D::shadowColor
1436 Holds the current shadow color.
1438 v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
1440 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1444 QV8Engine *engine = V8ENGINE_ACCESSOR();
1446 return engine->toString(r->context->state.shadowColor.name());
1449 static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1451 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1452 CHECK_CONTEXT_SETTER(r)
1454 QColor color = qt_color_from_string(value);
1456 if (color.isValid() && color != r->context->state.shadowColor) {
1457 r->context->state.shadowColor = color;
1458 r->context->buffer()->setShadowColor(color);
1464 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
1465 Holds the current shadow offset in the positive horizontal distance.
1467 \sa QtQuick2::Context2D::shadowOffsetY
1469 v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
1471 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1475 return v8::Number::New(r->context->state.shadowOffsetX);
1478 static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1480 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1481 CHECK_CONTEXT_SETTER(r)
1483 qreal offsetX = value->NumberValue();
1484 if (qIsFinite(offsetX) && offsetX != r->context->state.shadowOffsetX) {
1485 r->context->state.shadowOffsetX = offsetX;
1486 r->context->buffer()->setShadowOffsetX(offsetX);
1490 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
1491 Holds the current shadow offset in the positive vertical distance.
1493 \sa QtQuick2::Context2D::shadowOffsetX
1495 v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
1497 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1501 return v8::Number::New(r->context->state.shadowOffsetY);
1504 static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1506 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1507 CHECK_CONTEXT_SETTER(r)
1509 qreal offsetY = value->NumberValue();
1510 if (qIsFinite(offsetY) && offsetY != r->context->state.shadowOffsetY) {
1511 r->context->state.shadowOffsetY = offsetY;
1512 r->context->buffer()->setShadowOffsetY(offsetY);
1516 v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
1518 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1520 return r->context->m_v8path;
1523 static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1525 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1526 CHECK_CONTEXT_SETTER(r)
1527 QV8Engine *engine = V8ENGINE_ACCESSOR();
1529 r->context->beginPath();
1530 if (value->IsObject()) {
1531 QQuickPath* path = qobject_cast<QQuickPath*>(engine->toQObject(value));
1533 r->context->m_path = path->path();
1535 QString path = engine->toString(value->ToString());
1536 QQuickSvgParser::parsePathDataFast(path, r->context->m_path);
1538 r->context->m_v8path = value;
1543 \qmlmethod object QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
1544 Clears all pixels on the canvas in the given rectangle to transparent black.
1546 static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
1548 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1552 if (args.Length() == 4)
1553 r->context->clearRect(args[0]->NumberValue(),
1554 args[1]->NumberValue(),
1555 args[2]->NumberValue(),
1556 args[3]->NumberValue());
1561 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1562 Paint the specified rectangular area using the fillStyle.
1564 \sa QtQuick2::Context2D::fillStyle
1566 static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
1568 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1571 if (args.Length() == 4)
1572 r->context->fillRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1577 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1578 Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
1579 and (if appropriate) miterLimit attributes.
1581 \sa QtQuick2::Context2D::strokeStyle
1582 \sa QtQuick2::Context2D::lineWidth
1583 \sa QtQuick2::Context2D::lineJoin
1584 \sa QtQuick2::Context2D::miterLimit
1586 static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
1588 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1591 if (args.Length() == 4)
1592 r->context->strokeRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1597 // Complex shapes (paths) API
1599 \qmlmethod object QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
1600 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.
1601 \image qml-item-canvas-arcTo2.png
1602 \sa QtQuick2::Context2D::arcTo,
1603 {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
1605 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
1607 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1610 if (args.Length() >= 5) {
1611 bool antiClockwise = false;
1613 if (args.Length() == 6)
1614 antiClockwise = args[5]->BooleanValue();
1616 qreal radius = args[2]->NumberValue();
1618 if (qIsFinite(radius) && radius < 0)
1619 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1621 r->context->arc(args[0]->NumberValue(),
1622 args[1]->NumberValue(),
1624 args[3]->NumberValue(),
1625 args[4]->NumberValue(),
1633 \qmlmethod object QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
1635 Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
1636 To draw an arc, you begin with the same steps your followed to create a line:
1638 \li Call the context.beginPath() method to set a new path.
1639 \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).
1640 \li To draw an arc or circle, call the context.arcTo(\c x1, \c y1, \c x2, \c y2,\c radius) method.
1641 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
1642 it to the previous subpath by a straight line.
1644 \image qml-item-canvas-arcTo.png
1645 Both startAngle and endAngle are measured from the x axis in units of radians.
1647 \image qml-item-canvas-startAngle.png
1648 The anticlockwise has the value TRUE for each arc in the figure above because they are all drawn in the counterclockwise direction.
1649 \sa QtQuick2::Context2D::arc, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d
1650 context standard for arcTo}
1652 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
1654 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1657 if (args.Length() == 5) {
1658 qreal radius = args[4]->NumberValue();
1660 if (qIsFinite(radius) && radius < 0)
1661 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1663 r->context->arcTo(args[0]->NumberValue(),
1664 args[1]->NumberValue(),
1665 args[2]->NumberValue(),
1666 args[3]->NumberValue(),
1674 \qmlmethod object QtQuick2::Context2D::beginPath()
1676 Resets the current path to a new path.
1678 static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
1680 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1684 r->context->beginPath();
1690 \qmlmethod object QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
1692 Adds a cubic Bezier curve between the current position and the given endPoint using the control points specified by (\c cp1x, cp1y),
1693 and (\c cp2x, \c cp2y).
1694 After the curve is added, the current position is updated to be at the end point (\c x, \c y) of the curve.
1695 The following code produces the path shown below:
1697 ctx.strokeStyle = Qt.rgba(0, 0, 0, 1);
1700 ctx.moveTo(20, 0);//start point
1701 ctx.bezierCurveTo(-10, 90, 210, 90, 180, 0);
1704 \image qml-item-canvas-bezierCurveTo.png
1705 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
1706 \sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
1708 static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
1710 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1714 if (args.Length() == 6) {
1715 qreal cp1x = args[0]->NumberValue();
1716 qreal cp1y = args[1]->NumberValue();
1717 qreal cp2x = args[2]->NumberValue();
1718 qreal cp2y = args[3]->NumberValue();
1719 qreal x = args[4]->NumberValue();
1720 qreal y = args[5]->NumberValue();
1722 if (!qIsFinite(cp1x) || !qIsFinite(cp1y) || !qIsFinite(cp2x) || !qIsFinite(cp2y) || !qIsFinite(x) || !qIsFinite(y))
1725 r->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
1732 \qmlmethod object QtQuick2::Context2D::clip()
1734 Creates the clipping region from the current path.
1735 Any parts of the shape outside the clipping path are not displayed.
1736 To create a complex shape using the \a clip() method:
1739 \li Call the \c{context.beginPath()} method to set the clipping path.
1740 \li Define the clipping path by calling any combination of the \c{lineTo},
1741 \c{arcTo}, \c{arc}, \c{moveTo}, etc and \c{closePath} methods.
1742 \li Call the \c{context.clip()} method.
1745 The new shape displays. The following shows how a clipping path can
1746 modify how an image displays:
1748 \image qml-canvas-clip-complex.png
1749 \sa QtQuick2::Context2D::beginPath()
1750 \sa QtQuick2::Context2D::closePath()
1751 \sa QtQuick2::Context2D::stroke()
1752 \sa QtQuick2::Context2D::fill()
1753 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-clip}{W3C 2d context standard for clip}
1755 static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
1757 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1765 \qmlmethod object QtQuick2::Context2D::closePath()
1766 Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting a new path.
1767 The current point of the new path is the previous subpath's first point.
1769 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath}{W3C 2d context standard for closePath}
1771 static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
1773 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1777 r->context->closePath();
1783 \qmlmethod object QtQuick2::Context2D::fill()
1785 Fills the subpaths with the current fill style.
1787 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-fill}{W3C 2d context standard for fill}
1789 \sa QtQuick2::Context2D::fillStyle
1791 static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
1793 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1800 \qmlmethod object QtQuick2::Context2D::lineTo(real x, real y)
1802 Draws a line from the current position to the point (x, y).
1804 static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
1806 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1810 if (args.Length() == 2) {
1811 qreal x = args[0]->NumberValue();
1812 qreal y = args[1]->NumberValue();
1814 if (!qIsFinite(x) || !qIsFinite(y))
1817 r->context->lineTo(x, y);
1824 \qmlmethod object QtQuick2::Context2D::moveTo(real x, real y)
1826 Creates a new subpath with the given point.
1828 static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
1830 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1833 if (args.Length() == 2) {
1834 qreal x = args[0]->NumberValue();
1835 qreal y = args[1]->NumberValue();
1837 if (!qIsFinite(x) || !qIsFinite(y))
1839 r->context->moveTo(x, y);
1845 \qmlmethod object QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
1847 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).
1849 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto}{W3C 2d context standard for for quadraticCurveTo}
1851 static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
1853 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1856 if (args.Length() == 4) {
1857 qreal cpx = args[0]->NumberValue();
1858 qreal cpy = args[1]->NumberValue();
1859 qreal x = args[2]->NumberValue();
1860 qreal y = args[3]->NumberValue();
1862 if (!qIsFinite(cpx) || !qIsFinite(cpy) || !qIsFinite(x) || !qIsFinite(y))
1865 r->context->quadraticCurveTo(cpx, cpy, x, y);
1872 \qmlmethod object QtQuick2::Context2D::rect(real x, real y, real w, real h)
1874 Adds a rectangle at position (\c x, \c y), with the given width \c w and height \c h, as a closed subpath.
1876 static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
1878 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1881 if (args.Length() == 4)
1882 r->context->rect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1887 \qmlmethod object QtQuick2::Context2D::roundedRect(real x, real y, real w, real h, real xRadius, real yRadius)
1889 Adds the given rectangle rect with rounded corners to the path. The \c xRadius and \c yRadius arguments specify the radius of the
1890 ellipses defining the corners of the rounded rectangle.
1892 static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
1894 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1897 if (args.Length() == 6)
1898 r->context->roundedRect(args[0]->NumberValue()
1899 , args[1]->NumberValue()
1900 , args[2]->NumberValue()
1901 , args[3]->NumberValue()
1902 , args[4]->NumberValue()
1903 , args[5]->NumberValue());
1908 \qmlmethod object QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
1910 Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
1911 and adds it to the path as a closed subpath.
1913 The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
1915 static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
1917 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1921 if (args.Length() == 4)
1922 r->context->ellipse(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1928 \qmlmethod object QtQuick2::Context2D::text(string text, real x, real y)
1930 Adds the given \c text to the path as a set of closed subpaths created from the current context font supplied.
1931 The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (\c x, \c y).
1933 static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
1935 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1938 QV8Engine *engine = V8ENGINE();
1939 if (args.Length() == 3) {
1940 qreal x = args[1]->NumberValue();
1941 qreal y = args[2]->NumberValue();
1943 if (!qIsFinite(x) || !qIsFinite(y))
1945 r->context->text(engine->toString(args[0]), x, y);
1951 \qmlmethod object QtQuick2::Context2D::stroke()
1953 Strokes the subpaths with the current stroke style.
1955 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke}{W3C 2d context standard for stroke}
1957 \sa QtQuick2::Context2D::strokeStyle
1959 static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
1961 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1964 r->context->stroke();
1969 \qmlmethod object QtQuick2::Context2D::isPointInPath(real x, real y)
1971 Returns true if the given point is in the current path.
1973 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath}{W3C 2d context standard for isPointInPath}
1975 static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
1977 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1980 bool pointInPath = false;
1981 if (args.Length() == 2)
1982 pointInPath = r->context->isPointInPath(args[0]->NumberValue(), args[1]->NumberValue());
1983 return v8::Boolean::New(pointInPath);
1986 static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
1990 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
1993 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
1997 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
2000 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
2004 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
2008 \qmlproperty string QtQuick2::Context2D::font
2009 Holds the current font settings.
2011 The default font value is "10px sans-serif".
2012 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-font}{w3C 2d context standard for font}
2014 v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
2016 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2019 QV8Engine *engine = V8ENGINE_ACCESSOR();
2021 return engine->toString(r->context->state.font.toString());
2024 static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2026 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2027 CHECK_CONTEXT_SETTER(r)
2029 QV8Engine *engine = V8ENGINE_ACCESSOR();
2030 QString fs = engine->toString(value);
2031 QFont font = qt_font_from_string(fs);
2032 if (font != r->context->state.font) {
2033 r->context->state.font = font;
2038 \qmlproperty string QtQuick2::Context2D::textAlign
2040 Holds the current text alignment settings.
2041 The possible values are:
2049 Other values are ignored. The default value is "start".
2051 v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
2053 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2055 QV8Engine *engine = V8ENGINE_ACCESSOR();
2056 switch (r->context->state.textAlign) {
2057 case QQuickContext2D::Start:
2058 return engine->toString(QLatin1String("start"));
2059 case QQuickContext2D::End:
2060 return engine->toString(QLatin1String("end"));
2061 case QQuickContext2D::Left:
2062 return engine->toString(QLatin1String("left"));
2063 case QQuickContext2D::Right:
2064 return engine->toString(QLatin1String("right"));
2065 case QQuickContext2D::Center:
2066 return engine->toString(QLatin1String("center"));
2070 return engine->toString(QLatin1String("start"));
2073 static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2075 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2076 CHECK_CONTEXT_SETTER(r)
2077 QV8Engine *engine = V8ENGINE_ACCESSOR();
2079 QString textAlign = engine->toString(value);
2081 QQuickContext2D::TextAlignType ta;
2082 if (textAlign == QLatin1String("start"))
2083 ta = QQuickContext2D::Start;
2084 else if (textAlign == QLatin1String("end"))
2085 ta = QQuickContext2D::End;
2086 else if (textAlign == QLatin1String("left"))
2087 ta = QQuickContext2D::Left;
2088 else if (textAlign == QLatin1String("right"))
2089 ta = QQuickContext2D::Right;
2090 else if (textAlign == QLatin1String("center"))
2091 ta = QQuickContext2D::Center;
2095 if (ta != r->context->state.textAlign) {
2096 r->context->state.textAlign = ta;
2101 \qmlproperty string QtQuick2::Context2D::textBaseline
2103 Holds the current baseline alignment settings.
2104 The possible values are:
2113 Other values are ignored. The default value is "alphabetic".
2115 v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
2117 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2120 QV8Engine *engine = V8ENGINE_ACCESSOR();
2121 switch (r->context->state.textBaseline) {
2122 case QQuickContext2D::Alphabetic:
2123 return engine->toString(QLatin1String("alphabetic"));
2124 case QQuickContext2D::Hanging:
2125 return engine->toString(QLatin1String("hanging"));
2126 case QQuickContext2D::Top:
2127 return engine->toString(QLatin1String("top"));
2128 case QQuickContext2D::Bottom:
2129 return engine->toString(QLatin1String("bottom"));
2130 case QQuickContext2D::Middle:
2131 return engine->toString(QLatin1String("middle"));
2135 return engine->toString(QLatin1String("alphabetic"));
2138 static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2140 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2141 CHECK_CONTEXT_SETTER(r)
2142 QV8Engine *engine = V8ENGINE_ACCESSOR();
2143 QString textBaseline = engine->toString(value);
2145 QQuickContext2D::TextBaseLineType tb;
2146 if (textBaseline == QLatin1String("alphabetic"))
2147 tb = QQuickContext2D::Alphabetic;
2148 else if (textBaseline == QLatin1String("hanging"))
2149 tb = QQuickContext2D::Hanging;
2150 else if (textBaseline == QLatin1String("top"))
2151 tb = QQuickContext2D::Top;
2152 else if (textBaseline == QLatin1String("bottom"))
2153 tb = QQuickContext2D::Bottom;
2154 else if (textBaseline == QLatin1String("middle"))
2155 tb = QQuickContext2D::Middle;
2159 if (tb != r->context->state.textBaseline) {
2160 r->context->state.textBaseline = tb;
2165 \qmlmethod object QtQuick2::Context2D::fillText(text, x, y)
2166 Fills the given text at the given position.
2167 \sa QtQuick2::Context2D::font
2168 \sa QtQuick2::Context2D::textAlign
2169 \sa QtQuick2::Context2D::textBaseline
2170 \sa QtQuick2::Context2D::strokeText
2172 static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
2174 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2177 QV8Engine *engine = V8ENGINE();
2178 if (args.Length() == 3) {
2179 qreal x = args[1]->NumberValue();
2180 qreal y = args[2]->NumberValue();
2181 if (!qIsFinite(x) || !qIsFinite(y))
2183 QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
2184 r->context->buffer()->fill(textPath);
2189 \qmlmethod object QtQuick2::Context2D::strokeText(text, x, y)
2190 Strokes the given text at the given position.
2191 \sa QtQuick2::Context2D::font
2192 \sa QtQuick2::Context2D::textAlign
2193 \sa QtQuick2::Context2D::textBaseline
2194 \sa QtQuick2::Context2D::fillText
2196 static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
2198 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2201 QV8Engine *engine = V8ENGINE();
2202 if (args.Length() == 3)
2203 r->context->drawText(engine->toString(args[0]), args[1]->NumberValue(), args[2]->NumberValue(), false);
2207 \qmltype TextMetrics
2208 \inqmlmodule QtQuick 2
2210 \ingroup qtquick-canvas
2211 \brief Provides a Context2D TextMetrics interface
2213 The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
2214 See {http://www.w3.org/TR/2dcontext/#textmetrics}{W3C 2d context TexMetrics} for more details.
2216 \sa QtQuick2::Context2D::measureText
2217 \sa QtQuick2::TextMetrics::width
2221 \qmlproperty int QtQuick2::TextMetrics::width
2222 Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
2223 This property is read only.
2227 \qmlmethod variant QtQuick2::Context2D::measureText(text)
2228 Returns a TextMetrics object with the metrics of the given text in the current font.
2230 static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
2232 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2235 QV8Engine *engine = V8ENGINE();
2237 if (args.Length() == 1) {
2238 QFontMetrics fm(r->context->state.font);
2239 uint width = fm.width(engine->toString(args[0]));
2240 v8::Local<v8::Object> tm = v8::Object::New();
2241 tm->Set(v8::String::New("width"), v8::Number::New(width));
2244 return v8::Undefined();
2249 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
2250 Draws the given \a image on the canvas at position (\a dx, \a dy).
2252 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2253 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2254 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2255 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2257 \sa QtQuick2::CanvasImageData
2259 \sa QtQuick2::Canvas::loadImage
2260 \sa QtQuick2::Canvas::isImageLoaded
2261 \sa QtQuick2::Canvas::imageLoaded
2263 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2266 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
2267 This is an overloaded function.
2268 Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
2272 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2273 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2274 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2275 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2277 \sa QtQuick2::CanvasImageData
2279 \sa QtQuick2::Canvas::loadImage
2280 \sa QtQuick2::Canvas::isImageLoaded
2281 \sa QtQuick2::Canvas::imageLoaded
2283 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2286 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
2287 This is an overloaded function.
2288 Draws the given item as \a image from source point (\a sx, \a sy) and source width \a sw, source height \a sh
2289 onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
2293 The \a image type can be an Image or Canvas item, an image url or a \a {QtQuick2::CanvasImageData} object.
2294 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2295 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2296 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2298 \sa QtQuick2::CanvasImageData
2300 \sa QtQuick2::Canvas::loadImage
2301 \sa QtQuick2::Canvas::isImageLoaded
2302 \sa QtQuick2::Canvas::imageLoaded
2304 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2306 static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
2308 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2311 QV8Engine *engine = V8ENGINE();
2312 qreal sx, sy, sw, sh, dx, dy, dw, dh;
2317 //FIXME:This function should be moved to QQuickContext2D::drawImage(...)
2318 if (!r->context->state.invertibleCTM)
2321 QQmlRefPointer<QQuickCanvasPixmap> pixmap;
2323 if (args[0]->IsString()) {
2324 QUrl url(engine->toString(args[0]->ToString()));
2326 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2328 pixmap = r->context->createPixmap(url);
2329 } else if (args[0]->IsObject()) {
2330 QQuickImage *imageItem = qobject_cast<QQuickImage*>(engine->toQObject(args[0]->ToObject()));
2331 QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(engine->toQObject(args[0]->ToObject()));
2333 QV8Context2DPixelArrayResource *pix = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->GetInternalField(0)->ToObject());
2334 if (pix && !pix->image.isNull()) {
2335 pixmap.take(new QQuickCanvasPixmap(pix->image, r->context->canvas()->window()));
2336 } else if (imageItem) {
2337 pixmap.take(r->context->createPixmap(imageItem->source()));
2338 } else if (canvas) {
2339 QImage img = canvas->toImage();
2341 pixmap.take(new QQuickCanvasPixmap(img, canvas->window()));
2343 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2346 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2349 if (pixmap.isNull() || !pixmap->isValid())
2352 if (args.Length() == 3) {
2353 dx = args[1]->NumberValue();
2354 dy = args[2]->NumberValue();
2357 sw = pixmap->width();
2358 sh = pixmap->height();
2361 } else if (args.Length() == 5) {
2364 sw = pixmap->width();
2365 sh = pixmap->height();
2366 dx = args[1]->NumberValue();
2367 dy = args[2]->NumberValue();
2368 dw = args[3]->NumberValue();
2369 dh = args[4]->NumberValue();
2370 } else if (args.Length() == 9) {
2371 sx = args[1]->NumberValue();
2372 sy = args[2]->NumberValue();
2373 sw = args[3]->NumberValue();
2374 sh = args[4]->NumberValue();
2375 dx = args[5]->NumberValue();
2376 dy = args[6]->NumberValue();
2377 dw = args[7]->NumberValue();
2378 dh = args[8]->NumberValue();
2397 || sx + sw > pixmap->width()
2398 || sy + sh > pixmap->height()
2399 || sx + sw < 0 || sy + sh < 0) {
2400 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
2403 r->context->buffer()->drawPixmap(pixmap, QRectF(sx, sy, sw, sh), QRectF(dx, dy, dw, dh));
2408 // pixel manipulation
2410 \qmltype CanvasImageData
2411 \inqmlmodule QtQuick 2
2412 \ingroup qtquick-canvas
2413 \brief Contains image pixel data in RGBA order
2415 The \a QtQuick2::CanvasImageData object holds the image pixel data.
2417 The \a QtQuick2::CanvasImageData object has the actual dimensions of the data stored in
2418 this object and holds the one-dimensional array containing the data in RGBA order,
2419 as integers in the range 0 to 255.
2421 \sa QtQuick2::CanvasImageData::width
2422 \sa QtQuick2::CanvasImageData::height
2423 \sa QtQuick2::CanvasImageData::data
2424 \sa QtQuick2::Context2D::createImageData
2425 \sa QtQuick2::Context2D::getImageData
2426 \sa QtQuick2::Context2D::putImageData
2429 \qmlproperty QtQuick2::CanvasImageData::width
2430 Holds the actual width dimension of the data in the ImageData object, in device pixels.
2432 v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
2434 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2436 return v8::Integer::New(0);
2437 return v8::Integer::New(r->image.width());
2441 \qmlproperty QtQuick2::CanvasImageData::height
2442 Holds the actual height dimension of the data in the ImageData object, in device pixels.
2444 v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
2446 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2448 return v8::Integer::New(0);
2450 return v8::Integer::New(r->image.height());
2454 \qmlproperty QtQuick2::CanvasImageData::data
2455 Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
2457 v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
2459 return args.This()->GetInternalField(0);
2463 \qmltype CanvasPixelArray
2464 \inqmlmodule QtQuick 2
2465 \ingroup qtquick-canvas
2466 \brief Provides ordered and indexed access to the components of each pixel in image data
2468 The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
2469 The CanvasPixelArray can be accessed as normal Javascript array.
2470 \sa QtQuick2::CanvasImageData
2471 \sa {http://www.w3.org/TR/2dcontext/#canvaspixelarray}{W3C 2d context standard for PixelArray}
2475 \qmlproperty QtQuick2::CanvasPixelArray::length
2476 The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
2477 The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
2478 This property is read only.
2480 v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
2482 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2483 if (!r || r->image.isNull()) return v8::Undefined();
2485 return v8::Integer::New(r->image.width() * r->image.height() * 4);
2488 v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
2490 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2492 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
2493 const quint32 w = r->image.width();
2494 const quint32 row = (index / 4) / w;
2495 const quint32 col = (index / 4) % w;
2496 const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
2498 switch (index % 4) {
2500 return v8::Integer::New(qRed(*pixel));
2502 return v8::Integer::New(qGreen(*pixel));
2504 return v8::Integer::New(qBlue(*pixel));
2506 return v8::Integer::New(qAlpha(*pixel));
2509 return v8::Undefined();
2512 v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
2514 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
2516 const int v = value->Uint32Value();
2517 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4) && v > 0 && v <= 255) {
2518 const quint32 w = r->image.width();
2519 const quint32 row = (index / 4) / w;
2520 const quint32 col = (index / 4) % w;
2522 QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
2524 switch (index % 4) {
2526 *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
2529 *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
2532 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
2535 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
2539 return v8::Undefined();
2542 \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
2543 Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
2546 \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
2547 Creates a CanvasImageData object with the same dimensions as the argument.
2550 \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
2551 Creates a CanvasImageData object with the given image loaded from \a imageUrl.
2552 Note:The \a imageUrl must be already loaded before this function call, if not, an empty
2553 CanvasImageData obect will be returned.
2555 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
2557 static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
2559 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2562 QV8Engine *engine = V8ENGINE();
2564 if (args.Length() == 1) {
2565 if (args[0]->IsObject()) {
2566 v8::Local<v8::Object> imgData = args[0]->ToObject();
2567 QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
2569 qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
2570 qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
2571 return qt_create_image_data(w, h, engine, QImage());
2573 } else if (args[0]->IsString()) {
2574 QImage image = r->context->createPixmap(QUrl(engine->toString(args[0]->ToString())))->image();
2575 return qt_create_image_data(image.width(), image.height(), engine, image);
2577 } else if (args.Length() == 2) {
2578 qreal w = args[0]->NumberValue();
2579 qreal h = args[1]->NumberValue();
2581 if (!qIsFinite(w) || !qIsFinite(h))
2582 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
2585 return qt_create_image_data(w, h, engine, QImage());
2587 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createImageData(): invalid arguments");
2589 return v8::Undefined();
2593 \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
2594 Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
2596 static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
2598 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2601 QV8Engine *engine = V8ENGINE();
2602 if (args.Length() == 4) {
2603 qreal x = args[0]->NumberValue();
2604 qreal y = args[1]->NumberValue();
2605 qreal w = args[2]->NumberValue();
2606 qreal h = args[3]->NumberValue();
2607 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(w))
2608 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
2610 if (w <= 0 || h <= 0)
2611 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
2613 QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
2614 v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
2622 \qmlmethod object QtQuick2::Context2D::putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
2623 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.
2625 static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
2627 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2629 if (args.Length() != 3 && args.Length() != 7)
2630 return v8::Undefined();
2632 if (args[0]->IsNull() || !args[0]->IsObject()) {
2633 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
2635 qreal dx = args[1]->NumberValue();
2636 qreal dy = args[2]->NumberValue();
2637 qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
2639 if (!qIsFinite(dx) || !qIsFinite(dy))
2640 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2642 v8::Local<v8::Object> imageData = args[0]->ToObject();
2643 QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
2645 w = imageData->Get(v8::String::New("width"))->NumberValue();
2646 h = imageData->Get(v8::String::New("height"))->NumberValue();
2648 if (args.Length() == 7) {
2649 dirtyX = args[3]->NumberValue();
2650 dirtyY = args[4]->NumberValue();
2651 dirtyWidth = args[5]->NumberValue();
2652 dirtyHeight = args[6]->NumberValue();
2654 if (!qIsFinite(dirtyX) || !qIsFinite(dirtyY) || !qIsFinite(dirtyWidth) || !qIsFinite(dirtyHeight))
2655 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2658 if (dirtyWidth < 0) {
2659 dirtyX = dirtyX+dirtyWidth;
2660 dirtyWidth = -dirtyWidth;
2663 if (dirtyHeight < 0) {
2664 dirtyY = dirtyY+dirtyHeight;
2665 dirtyHeight = -dirtyHeight;
2669 dirtyWidth = dirtyWidth+dirtyX;
2674 dirtyHeight = dirtyHeight+dirtyY;
2678 if (dirtyX+dirtyWidth > w) {
2679 dirtyWidth = w - dirtyX;
2682 if (dirtyY+dirtyHeight > h) {
2683 dirtyHeight = h - dirtyY;
2686 if (dirtyWidth <=0 || dirtyHeight <= 0)
2695 QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2696 r->context->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight));
2702 \qmltype CanvasGradient
2703 \inqmlmodule QtQuick 2
2705 \ingroup qtquick-canvas
2706 \brief Provides an opaque CanvasGradient interface
2710 \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
2711 Adds a color stop with the given color to the gradient at the given offset.
2712 0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
2716 var gradient = ctx.createLinearGradient(0, 0, 100, 100);
2717 gradient.addColorStop(0.3, Qt.rgba(1, 0, 0, 1));
2718 gradient.addColorStop(0.7, 'rgba(0, 255, 255, 1');
2721 static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
2723 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
2725 V8THROW_ERROR("Not a CanvasGradient object");
2727 QV8Engine *engine = V8ENGINE();
2729 if (args.Length() == 2) {
2731 if (!style->brush.gradient())
2732 V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
2733 QGradient gradient = *(style->brush.gradient());
2734 qreal pos = args[0]->NumberValue();
2737 if (args[1]->IsObject()) {
2738 color = engine->toVariant(args[1], qMetaTypeId<QColor>()).value<QColor>();
2740 color = qt_color_from_string(args[1]);
2742 if (pos < 0.0 || pos > 1.0 || !qIsFinite(pos)) {
2743 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
2746 if (color.isValid()) {
2747 gradient.setColorAt(pos, color);
2749 V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string");
2751 style->brush = gradient;
2757 void QQuickContext2D::scale(qreal x, qreal y)
2759 if (!state.invertibleCTM)
2762 if (!qIsFinite(x) || !qIsFinite(y))
2765 QTransform newTransform = state.matrix;
2766 newTransform.scale(x, y);
2768 if (!newTransform.isInvertible()) {
2769 state.invertibleCTM = false;
2773 state.matrix = newTransform;
2774 buffer()->updateMatrix(state.matrix);
2775 m_path = QTransform().scale(1.0 / x, 1.0 / y).map(m_path);
2778 void QQuickContext2D::rotate(qreal angle)
2780 if (!state.invertibleCTM)
2783 if (!qIsFinite(angle))
2786 QTransform newTransform =state.matrix;
2787 newTransform.rotate(DEGREES(angle));
2789 if (!newTransform.isInvertible()) {
2790 state.invertibleCTM = false;
2794 state.matrix = newTransform;
2795 buffer()->updateMatrix(state.matrix);
2796 m_path = QTransform().rotate(-DEGREES(angle)).map(m_path);
2799 void QQuickContext2D::shear(qreal h, qreal v)
2801 if (!state.invertibleCTM)
2804 if (!qIsFinite(h) || !qIsFinite(v))
2807 QTransform newTransform = state.matrix;
2808 newTransform.shear(h, v);
2810 if (!newTransform.isInvertible()) {
2811 state.invertibleCTM = false;
2815 state.matrix = newTransform;
2816 buffer()->updateMatrix(state.matrix);
2817 m_path = QTransform().shear(-h, -v).map(m_path);
2820 void QQuickContext2D::translate(qreal x, qreal y)
2822 if (!state.invertibleCTM)
2825 if (!qIsFinite(x) || !qIsFinite(y))
2828 QTransform newTransform = state.matrix;
2829 newTransform.translate(x, y);
2831 if (!newTransform.isInvertible()) {
2832 state.invertibleCTM = false;
2836 state.matrix = newTransform;
2837 buffer()->updateMatrix(state.matrix);
2838 m_path = QTransform().translate(-x, -y).map(m_path);
2841 void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
2843 if (!state.invertibleCTM)
2846 if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
2849 QTransform transform(a, b, c, d, e, f);
2850 QTransform newTransform = state.matrix * transform;
2852 if (!newTransform.isInvertible()) {
2853 state.invertibleCTM = false;
2856 state.matrix = newTransform;
2857 buffer()->updateMatrix(state.matrix);
2858 m_path = transform.inverted().map(m_path);
2861 void QQuickContext2D::setTransform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
2863 if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
2866 QTransform ctm = state.matrix;
2867 if (!ctm.isInvertible())
2870 state.matrix = ctm.inverted() * state.matrix;
2871 m_path = ctm.map(m_path);
2872 state.invertibleCTM = true;
2873 transform(a, b, c, d, e, f);
2876 void QQuickContext2D::fill()
2878 if (!state.invertibleCTM)
2881 if (!m_path.elementCount())
2884 m_path.setFillRule(state.fillRule);
2885 buffer()->fill(m_path);
2888 void QQuickContext2D::clip()
2890 if (!state.invertibleCTM)
2893 QPainterPath clipPath = m_path;
2894 clipPath.closeSubpath();
2895 if (!state.clipPath.isEmpty())
2896 state.clipPath = clipPath.intersected(state.clipPath);
2898 state.clipPath = clipPath;
2899 buffer()->clip(state.clipPath);
2902 void QQuickContext2D::stroke()
2904 if (!state.invertibleCTM)
2907 if (!m_path.elementCount())
2910 buffer()->stroke(m_path);
2913 void QQuickContext2D::fillRect(qreal x, qreal y, qreal w, qreal h)
2915 if (!state.invertibleCTM)
2918 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2921 buffer()->fillRect(QRectF(x, y, w, h));
2924 void QQuickContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
2926 if (!state.invertibleCTM)
2929 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2932 buffer()->strokeRect(QRectF(x, y, w, h));
2935 void QQuickContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
2937 if (!state.invertibleCTM)
2940 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2943 buffer()->clearRect(QRectF(x, y, w, h));
2946 void QQuickContext2D::drawText(const QString& text, qreal x, qreal y, bool fill)
2948 if (!state.invertibleCTM)
2951 if (!qIsFinite(x) || !qIsFinite(y))
2954 QPainterPath textPath = createTextGlyphs(x, y, text);
2956 buffer()->fill(textPath);
2958 buffer()->stroke(textPath);
2962 void QQuickContext2D::beginPath()
2964 if (!m_path.elementCount())
2966 m_path = QPainterPath();
2969 void QQuickContext2D::closePath()
2971 if (!m_path.elementCount())
2974 QRectF boundRect = m_path.boundingRect();
2975 if (boundRect.width() || boundRect.height())
2976 m_path.closeSubpath();
2977 //FIXME:QPainterPath set the current point to (0,0) after close subpath
2978 //should be the first point of the previous subpath
2981 void QQuickContext2D::moveTo( qreal x, qreal y)
2983 if (!state.invertibleCTM)
2986 //FIXME: moveTo should not close the previous subpath
2987 m_path.moveTo(QPointF(x, y));
2990 void QQuickContext2D::lineTo( qreal x, qreal y)
2992 if (!state.invertibleCTM)
2997 if (!m_path.elementCount())
2999 else if (m_path.currentPosition() != pt)
3003 void QQuickContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
3006 if (!state.invertibleCTM)
3009 if (!m_path.elementCount())
3010 m_path.moveTo(QPointF(cpx, cpy));
3013 if (m_path.currentPosition() != pt)
3014 m_path.quadTo(QPointF(cpx, cpy), pt);
3017 void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
3018 qreal cp2x, qreal cp2y,
3021 if (!state.invertibleCTM)
3024 if (!m_path.elementCount())
3025 m_path.moveTo(QPointF(cp1x, cp1y));
3028 if (m_path.currentPosition() != pt)
3029 m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y), pt);
3032 void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
3034 QPointF p0(m_path.currentPosition());
3036 QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
3037 QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
3038 float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
3039 float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
3041 double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
3043 // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
3044 // We could have used areCollinear() here, but since we're reusing
3045 // the variables computed above later on we keep this logic.
3046 if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
3051 float tangent = radius / tan(acos(cos_phi) / 2);
3052 float factor_p1p0 = tangent / p1p0_length;
3053 QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
3055 QPointF orth_p1p0(p1p0.y(), -p1p0.x());
3056 float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
3057 float factor_ra = radius / orth_p1p0_length;
3059 // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
3060 double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
3061 if (cos_alpha < 0.f)
3062 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3064 QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
3066 // calculate angles for addArc
3067 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3068 float sa = acos(orth_p1p0.x() / orth_p1p0_length);
3069 if (orth_p1p0.y() < 0.f)
3072 // anticlockwise logic
3073 bool anticlockwise = false;
3075 float factor_p1p2 = tangent / p1p2_length;
3076 QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
3077 QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
3078 float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
3079 float ea = acos(orth_p1p2.x() / orth_p1p2_length);
3080 if (orth_p1p2.y() < 0)
3082 if ((sa > ea) && ((sa - ea) < Q_PI))
3083 anticlockwise = true;
3084 if ((sa < ea) && ((ea - sa) > Q_PI))
3085 anticlockwise = true;
3087 arc(p.x(), p.y(), radius, sa, ea, anticlockwise);
3090 void QQuickContext2D::arcTo(qreal x1, qreal y1,
3094 if (!state.invertibleCTM)
3097 if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2) || !qIsFinite(radius))
3101 QPointF end(x2, y2);
3103 if (!m_path.elementCount())
3105 else if (st == m_path.currentPosition() || st == end || !radius)
3108 addArcTo(st, end, radius);
3111 void QQuickContext2D::rect(qreal x, qreal y, qreal w, qreal h)
3113 if (!state.invertibleCTM)
3115 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
3119 m_path.moveTo(x, y);
3122 m_path.addRect(x, y, w, h);
3125 void QQuickContext2D::roundedRect(qreal x, qreal y,
3129 if (!state.invertibleCTM)
3132 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h) || !qIsFinite(xr) || !qIsFinite(yr))
3136 m_path.moveTo(x, y);
3139 m_path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
3142 void QQuickContext2D::ellipse(qreal x, qreal y,
3145 if (!state.invertibleCTM)
3148 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
3152 m_path.moveTo(x, y);
3156 m_path.addEllipse(x, y, w, h);
3159 void QQuickContext2D::text(const QString& str, qreal x, qreal y)
3161 if (!state.invertibleCTM)
3165 path.addText(x, y, state.font, str);
3166 m_path.addPath(path);
3169 void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear, bool antiClockWise)
3171 if (!state.invertibleCTM)
3174 if (!qIsFinite(xc) || !qIsFinite(yc) || !qIsFinite(sar) || !qIsFinite(ear) || !qIsFinite(radius))
3183 // In Qt we don't switch the coordinate system for degrees
3184 // and still use the 0,0 as bottom left for degrees so we need
3188 antiClockWise = !antiClockWise;
3191 float sa = DEGREES(sar);
3192 float ea = DEGREES(ear);
3196 double xs = xc - radius;
3197 double ys = yc - radius;
3198 double width = radius*2;
3199 double height = radius*2;
3200 if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
3201 // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
3202 // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
3203 // circumference of this circle.
3206 if (!antiClockWise && (ea < sa)) {
3208 } else if (antiClockWise && (sa < ea)) {
3211 //### this is also due to switched coordinate system
3212 // we would end up with a 0 span instead of 360
3213 if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
3214 qFuzzyCompare(qAbs(span), 360))) {
3219 // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
3220 if (!m_path.elementCount())
3221 m_path.arcMoveTo(xs, ys, width, height, sa);
3223 m_path.lineTo(xc, yc);
3227 m_path.arcTo(xs, ys, width, height, sa, span);
3230 int baseLineOffset(QQuickContext2D::TextBaseLineType value, const QFontMetrics &metrics)
3234 case QQuickContext2D::Top:
3236 case QQuickContext2D::Alphabetic:
3237 case QQuickContext2D::Middle:
3238 case QQuickContext2D::Hanging:
3239 offset = metrics.ascent();
3241 case QQuickContext2D::Bottom:
3242 offset = metrics.height();
3248 static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
3251 if (value == QQuickContext2D::Start)
3252 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Left : QQuickContext2D::Right;
3253 else if (value == QQuickContext2D::End)
3254 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Right: QQuickContext2D::Left;
3256 case QQuickContext2D::Center:
3257 offset = metrics.width(text)/2;
3259 case QQuickContext2D::Right:
3260 offset = metrics.width(text);
3261 case QQuickContext2D::Left:
3269 QQmlRefPointer<QQuickCanvasPixmap> QQuickContext2D::createPixmap(const QUrl& url)
3271 return m_canvas->loadedPixmap(url);
3274 QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
3276 const QFontMetrics metrics(state.font);
3277 int yoffset = baseLineOffset(static_cast<QQuickContext2D::TextBaseLineType>(state.textBaseline), metrics);
3278 int xoffset = textAlignOffset(static_cast<QQuickContext2D::TextAlignType>(state.textAlign), metrics, text);
3280 QPainterPath textPath;
3282 textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
3283 textPath = state.matrix.map(textPath);
3288 static inline bool areCollinear(const QPointF& a, const QPointF& b, const QPointF& c)
3290 // Solved from comparing the slopes of a to b and b to c: (ay-by)/(ax-bx) == (cy-by)/(cx-bx)
3291 return qFuzzyCompare((c.y() - b.y()) * (a.x() - b.x()), (a.y() - b.y()) * (c.x() - b.x()));
3294 static inline bool withinRange(qreal p, qreal a, qreal b)
3296 return (p >= a && p <= b) || (p >= b && p <= a);
3299 bool QQuickContext2D::isPointInPath(qreal x, qreal y) const
3301 if (!state.invertibleCTM)
3304 if (!m_path.elementCount())
3307 if (!qIsFinite(x) || !qIsFinite(y))
3310 QPointF point(x, y);
3311 QTransform ctm = state.matrix;
3312 QPointF p = ctm.inverted().map(point);
3313 if (!qIsFinite(p.x()) || !qIsFinite(p.y()))
3316 const_cast<QQuickContext2D *>(this)->m_path.setFillRule(state.fillRule);
3318 bool contains = m_path.contains(p);
3321 // check whether the point is on the border
3322 QPolygonF border = m_path.toFillPolygon();
3324 QPointF p1 = border.at(0);
3327 for (int i = 1; i < border.size(); ++i) {
3329 if (areCollinear(p, p1, p2)
3330 // Once we know that the points are collinear we
3331 // only need to check one of the coordinates
3332 && (qAbs(p2.x() - p1.x()) > qAbs(p2.y() - p1.y()) ?
3333 withinRange(p.x(), p1.x(), p2.x()) :
3334 withinRange(p.y(), p1.y(), p2.y()))) {
3343 QQuickContext2D::QQuickContext2D(QObject *parent)
3344 : QQuickCanvasContext(parent)
3345 , m_buffer(new QQuickContext2DCommandBuffer)
3347 , m_windowManager(0)
3353 QQuickContext2D::~QQuickContext2D()
3358 v8::Handle<v8::Object> QQuickContext2D::v8value() const
3363 QStringList QQuickContext2D::contextNames() const
3365 return QStringList() << QLatin1String("2d");
3368 void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args)
3372 m_canvas = canvasItem;
3373 m_renderTarget = canvasItem->renderTarget();
3375 QQuickWindow *window = canvasItem->window();
3376 m_windowManager = QQuickWindowPrivate::get(window)->windowManager;
3377 m_renderStrategy = canvasItem->renderStrategy();
3379 switch (m_renderTarget) {
3380 case QQuickCanvasItem::Image:
3381 m_texture = new QQuickContext2DImageTexture(m_renderStrategy == QQuickCanvasItem::Threaded);
3383 case QQuickCanvasItem::FramebufferObject:
3385 m_texture = new QQuickContext2DFBOTexture;
3386 // No BufferQueueingOpenGL, falls back to Cooperative mode
3387 if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL))
3388 m_renderStrategy = QQuickCanvasItem::Cooperative;
3393 m_texture->setItem(canvasItem);
3394 m_texture->setCanvasWindow(canvasItem->canvasWindow().toRect());
3395 m_texture->setTileSize(canvasItem->tileSize());
3396 m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
3397 m_texture->setSmooth(canvasItem->smooth());
3399 QThread *renderThread = QThread::currentThread();
3400 QThread *sceneGraphThread = window->openglContext() ? window->openglContext()->thread() : 0;
3402 if (m_renderStrategy == QQuickCanvasItem::Threaded)
3403 renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem));
3404 else if (m_renderStrategy == QQuickCanvasItem::Cooperative)
3405 renderThread = sceneGraphThread;
3407 if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) {
3408 QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->glContext();
3410 m_glContext = new QOpenGLContext;
3411 m_glContext->setFormat(cc->format());
3412 m_glContext->setShareContext(cc);
3413 if (renderThread != QThread::currentThread())
3414 m_glContext->moveToThread(renderThread);
3417 connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
3422 void QQuickContext2D::prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth)
3424 m_texture->canvasChanged(canvasSize, tileSize, canvasWindow, dirtyRect, smooth);
3427 void QQuickContext2D::flush()
3429 if (!m_buffer->isEmpty()) {
3430 QMutexLocker lock(&m_bufferMutex);
3431 m_bufferQueue.enqueue(m_buffer);
3432 m_buffer = new QQuickContext2DCommandBuffer;
3436 switch (m_renderStrategy) {
3437 case QQuickCanvasItem::Immediate:
3438 // Cause the texture to consume paint commands immediately
3441 case QQuickCanvasItem::Threaded:
3442 // wake up thread to consume paint commands
3445 case QQuickCanvasItem::Cooperative:
3446 // NOTE: On SG Thread
3452 QSGDynamicTexture *QQuickContext2D::texture() const
3457 QImage QQuickContext2D::toImage(const QRectF& bounds)
3459 switch (m_renderStrategy) {
3460 case QQuickCanvasItem::Immediate:
3461 case QQuickCanvasItem::Threaded:
3464 case QQuickCanvasItem::Cooperative:
3468 return m_texture->toImage(bounds);
3472 QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
3474 v8::HandleScope handle_scope;
3475 v8::Context::Scope scope(engine->context());
3477 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
3478 ft->InstanceTemplate()->SetHasExternalResource(true);
3479 ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine));
3480 ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine));
3481 ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine));
3482 ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine));
3483 ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine));
3484 ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine));
3485 ft->PrototypeTemplate()->Set(v8::String::New("resetTransform"), V8FUNCTION(ctx2d_resetTransform, engine));
3486 ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine));
3487 ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine));
3488 ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine));
3489 ft->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, engine));
3490 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine));
3491 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine));
3492 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillRule"), ctx2d_fillRule, ctx2d_fillRule_set, v8::External::Wrap(engine));
3493 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine));
3494 ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
3495 ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
3496 ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
3497 ft->PrototypeTemplate()->Set(v8::String::New("createConicalGradient"), V8FUNCTION(ctx2d_createConicalGradient, engine));
3498 ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
3499 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
3500 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
3501 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine));
3502 ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine));
3503 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine));
3504 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine));
3505 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine));
3506 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine));
3507 ft->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_set, v8::External::Wrap(engine));
3508 ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine));
3509 ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine));
3510 ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine));
3511 ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine));
3512 ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine));
3513 ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine));
3514 ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine));
3515 ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine));
3516 ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine));
3517 ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine));
3518 ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine));
3519 ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine));
3520 ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine));
3521 ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine));
3522 ft->PrototypeTemplate()->Set(v8::String::New("roundedRect"), V8FUNCTION(ctx2d_roundedRect, engine));
3523 ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
3524 ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine));
3525 ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine));
3526 ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine));
3527 ft->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
3528 ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
3529 ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, engine));
3530 ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine));
3531 ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine));
3532 ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine));
3533 ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine));
3534 ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine));
3535 ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine));
3536 ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine));
3537 ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine));
3538 ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine));
3539 ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine));
3541 constructorContext = qPersistentNew(ft->GetFunction());
3543 v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
3544 ftGradient->InstanceTemplate()->SetHasExternalResource(true);
3545 ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
3546 constructorGradient = qPersistentNew(ftGradient->GetFunction());
3548 v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
3549 ftPattern->InstanceTemplate()->SetHasExternalResource(true);
3550 constructorPattern = qPersistentNew(ftPattern->GetFunction());
3552 v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
3553 ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
3554 ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
3555 ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
3556 constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
3558 v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
3559 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
3560 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
3561 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
3562 ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
3563 constructorImageData = qPersistentNew(ftImageData->GetFunction());
3566 QQuickContext2DEngineData::~QQuickContext2DEngineData()
3568 qPersistentDispose(constructorContext);
3569 qPersistentDispose(constructorGradient);
3570 qPersistentDispose(constructorPattern);
3571 qPersistentDispose(constructorImageData);
3572 qPersistentDispose(constructorPixelArray);
3575 void QQuickContext2D::popState()
3577 if (m_stateStack.isEmpty())
3580 QQuickContext2D::State newState = m_stateStack.pop();
3582 if (state.matrix != newState.matrix)
3583 buffer()->updateMatrix(newState.matrix);
3585 if (newState.globalAlpha != state.globalAlpha)
3586 buffer()->setGlobalAlpha(newState.globalAlpha);
3588 if (newState.globalCompositeOperation != state.globalCompositeOperation)
3589 buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
3591 if (newState.fillStyle != state.fillStyle)
3592 buffer()->setFillStyle(newState.fillStyle);
3594 if (newState.strokeStyle != state.strokeStyle)
3595 buffer()->setStrokeStyle(newState.strokeStyle);
3597 if (newState.lineWidth != state.lineWidth)
3598 buffer()->setLineWidth(newState.lineWidth);
3600 if (newState.lineCap != state.lineCap)
3601 buffer()->setLineCap(newState.lineCap);
3603 if (newState.lineJoin != state.lineJoin)
3604 buffer()->setLineJoin(newState.lineJoin);
3606 if (newState.miterLimit != state.miterLimit)
3607 buffer()->setMiterLimit(newState.miterLimit);
3609 if (newState.clipPath != state.clipPath) {
3610 buffer()->clip(newState.clipPath);
3613 if (newState.shadowBlur != state.shadowBlur)
3614 buffer()->setShadowBlur(newState.shadowBlur);
3616 if (newState.shadowColor != state.shadowColor)
3617 buffer()->setShadowColor(newState.shadowColor);
3619 if (newState.shadowOffsetX != state.shadowOffsetX)
3620 buffer()->setShadowOffsetX(newState.shadowOffsetX);
3622 if (newState.shadowOffsetY != state.shadowOffsetY)
3623 buffer()->setShadowOffsetY(newState.shadowOffsetY);
3624 m_path = state.matrix.map(m_path);
3626 m_path = state.matrix.inverted().map(m_path);
3628 void QQuickContext2D::pushState()
3630 m_stateStack.push(state);
3633 void QQuickContext2D::reset()
3635 QQuickContext2D::State newState;
3636 newState.matrix = QTransform();
3638 m_path = QPainterPath();
3640 QPainterPath defaultClipPath;
3642 QRect r(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
3643 r = r.united(m_canvas->canvasWindow().toRect());
3644 defaultClipPath.addRect(r);
3645 newState.clipPath = defaultClipPath;
3646 newState.clipPath.setFillRule(Qt::WindingFill);
3648 newState.strokeStyle = QColor("#000000");
3649 newState.fillStyle = QColor("#000000");
3650 newState.fillPatternRepeatX = false;
3651 newState.fillPatternRepeatY = false;
3652 newState.strokePatternRepeatX = false;
3653 newState.strokePatternRepeatY = false;
3654 newState.invertibleCTM = true;
3655 newState.fillRule = Qt::WindingFill;
3656 newState.globalAlpha = 1.0;
3657 newState.lineWidth = 1;
3658 newState.lineCap = Qt::FlatCap;
3659 newState.lineJoin = Qt::MiterJoin;
3660 newState.miterLimit = 10;
3661 newState.shadowOffsetX = 0;
3662 newState.shadowOffsetY = 0;
3663 newState.shadowBlur = 0;
3664 newState.shadowColor = qRgba(0, 0, 0, 0);
3665 newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
3666 newState.font = QFont(QLatin1String("sans-serif"), 10);
3667 newState.textAlign = QQuickContext2D::Start;
3668 newState.textBaseline = QQuickContext2D::Alphabetic;
3670 m_stateStack.clear();
3671 m_stateStack.push(newState);
3673 m_buffer->clearRect(QRectF(0, 0, m_canvas->width(), m_canvas->height()));
3676 void QQuickContext2D::setV8Engine(QV8Engine *engine)
3678 v8::HandleScope handle_scope;
3679 v8::Context::Scope scope(engine->context());
3681 if (m_v8engine != engine) {
3682 m_v8engine = engine;
3684 qPersistentDispose(m_v8value);
3686 if (m_v8engine == 0)
3689 QQuickContext2DEngineData *ed = engineData(engine);
3690 m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
3691 QV8Context2DResource *r = new QV8Context2DResource(engine);
3693 m_v8value->SetExternalResource(r);
3697 QQuickContext2DCommandBuffer* QQuickContext2D::nextBuffer()
3699 QMutexLocker lock(&m_bufferMutex);
3700 return m_bufferQueue.isEmpty() ? 0 : m_bufferQueue.dequeue();