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>
74 \instantiates QQuickContext2D
75 \inqmlmodule QtQuick 2
76 \ingroup qtquick-canvas
78 \brief Provides 2D context for shapes on a Canvas item
80 The Context2D object can be created by \c Canvas item's \c getContext()
86 var ctx = canvas.getContext('2d');
91 The Context2D API implements the same \l
92 {http://www.w3.org/TR/2dcontext}{W3C Canvas 2D Context API standard} with
93 some enhanced features.
95 The Context2D API provides the rendering \b{context} which defines the
96 methods and attributes needed to draw on the \c Canvas item. The following
97 assigns the canvas rendering context to a \c{context} variable:
99 var context = mycanvas.getContext("2d")
102 The Context2D API renders the canvas as a coordinate system whose origin
103 (0,0) is at the top left corner, as shown in the figure below. Coordinates
104 increase along the \c{x} axis from left to right and along the \c{y} axis
105 from top to bottom of the canvas.
106 \image qml-item-canvas-context.gif
111 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
113 static const double Q_PI = 3.14159265358979323846; // pi
115 #define DEGREES(t) ((t) * 180.0 / Q_PI)
117 #define CHECK_CONTEXT(r) if (!r || !r->context || !r->context->bufferValid()) \
118 V8THROW_ERROR("Not a Context2D object");
120 #define CHECK_CONTEXT_SETTER(r) if (!r || !r->context || !r->context->bufferValid()) \
121 V8THROW_ERROR_SETTER("Not a Context2D object");
122 #define qClamp(val, min, max) qMin(qMax(val, min), max)
123 #define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
124 QColor qt_color_from_string(v8::Local<v8::Value> name)
126 v8::String::AsciiValue str(name);
129 int len = str.length();
130 //rgb/hsl color string has at least 7 characters
131 if (!p || len > 255 || len <= 7)
134 bool isRgb(false), isHsl(false), hasAlpha(false);
137 while (isspace(*p)) p++;
138 if (strncmp(p, "rgb", 3) == 0)
140 else if (strncmp(p, "hsl", 3) == 0)
145 p+=3; //skip "rgb" or "hsl"
146 hasAlpha = (*p == 'a') ? true : false;
150 if (hasAlpha) ++p; //skip "a"
152 int rh, gs, bl, alpha = 255;
155 while (isspace(*p)) p++;
156 rh = strtol(p, &p, 10);
158 rh = qRound(rh/100.0 * 255);
161 if (*p++ != ',') return QColor();
164 while (isspace(*p)) p++;
165 gs = strtol(p, &p, 10);
167 gs = qRound(gs/100.0 * 255);
170 if (*p++ != ',') return QColor();
173 while (isspace(*p)) p++;
174 bl = strtol(p, &p, 10);
176 bl = qRound(bl/100.0 * 255);
181 if (*p++!= ',') return QColor();
182 while (isspace(*p)) p++;
184 alpha = qRound(qstrtod(p, const_cast<const char **>(&p), &ok) * 255);
187 if (*p != ')') return QColor();
189 return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)));
191 return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255));
196 QFont qt_font_from_string(const QString& fontString) {
198 // ### this is simplified and incomplete
199 // ### TODO:get code from Qt webkit
200 const QStringList tokens = fontString.split(QLatin1Char(' '));
201 foreach (const QString &token, tokens) {
202 if (token == QLatin1String("italic"))
203 font.setItalic(true);
204 else if (token == QLatin1String("bold"))
206 else if (token.endsWith(QLatin1String("px"))) {
207 QString number = token;
208 number.remove(QLatin1String("px"));
209 //font.setPointSizeF(number.trimmed().toFloat());
210 font.setPixelSize(number.trimmed().toInt());
212 font.setFamily(token);
220 class QQuickContext2DEngineData : public QV8Engine::Deletable
223 QQuickContext2DEngineData(QV8Engine *engine);
224 ~QQuickContext2DEngineData();
226 v8::Persistent<v8::Function> constructorContext;
227 v8::Persistent<v8::Function> constructorGradient;
228 v8::Persistent<v8::Function> constructorPattern;
229 v8::Persistent<v8::Function> constructorPixelArray;
230 v8::Persistent<v8::Function> constructorImageData;
233 V8_DEFINE_EXTENSION(QQuickContext2DEngineData, engineData)
235 class QV8Context2DResource : public QV8ObjectResource
237 V8_RESOURCE_TYPE(Context2DType)
239 QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e), context(0) {}
240 QQuickContext2D* context;
243 class QV8Context2DStyleResource : public QV8ObjectResource
245 V8_RESOURCE_TYPE(Context2DStyleType)
247 QV8Context2DStyleResource(QV8Engine *e)
248 : QV8ObjectResource(e)
249 , patternRepeatX(false)
250 , patternRepeatY(false)
253 bool patternRepeatX:1;
254 bool patternRepeatY:1;
257 class QV8Context2DPixelArrayResource : public QV8ObjectResource
259 V8_RESOURCE_TYPE(Context2DPixelArrayType)
261 QV8Context2DPixelArrayResource(QV8Engine *e) : QV8ObjectResource(e) {}
266 QImage qt_image_convolute_filter(const QImage& src, const QVector<qreal>& weights, int radius = 0)
268 int sides = radius ? radius : qRound(qSqrt(weights.size()));
269 int half = qFloor(sides/2);
271 QImage dst = QImage(src.size(), src.format());
273 int h = src.height();
274 for (int y = 0; y < dst.height(); ++y) {
275 QRgb *dr = (QRgb*)dst.scanLine(y);
276 for (int x = 0; x < dst.width(); ++x) {
277 unsigned char* dRgb = ((unsigned char*)&dr[x]);
278 unsigned char red=0, green=0, blue=0, alpha=0;
282 for (int cy=0; cy<sides; cy++) {
283 for (int cx=0; cx<sides; cx++) {
284 int scy = sy + cy - half;
285 int scx = sx + cx - half;
286 if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
287 const QRgb *sr = (const QRgb*)(src.constScanLine(scy));
288 const unsigned char* sRgb = ((const unsigned char*)&sr[scx]);
289 qreal wt = radius ? weights[0] : weights[cy*sides+cx];
291 green += sRgb[1] * wt;
292 blue += sRgb[2] * wt;
293 alpha += sRgb[3] * wt;
306 void qt_image_boxblur(QImage& image, int radius, bool quality)
308 int passes = quality? 3: 1;
309 for (int i=0; i < passes; i++) {
310 image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0/(radius * radius * 1.0), radius);
314 static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
316 if (compositeOperator == QLatin1String("source-over")) {
317 return QPainter::CompositionMode_SourceOver;
318 } else if (compositeOperator == QLatin1String("source-out")) {
319 return QPainter::CompositionMode_SourceOut;
320 } else if (compositeOperator == QLatin1String("source-in")) {
321 return QPainter::CompositionMode_SourceIn;
322 } else if (compositeOperator == QLatin1String("source-atop")) {
323 return QPainter::CompositionMode_SourceAtop;
324 } else if (compositeOperator == QLatin1String("destination-atop")) {
325 return QPainter::CompositionMode_DestinationAtop;
326 } else if (compositeOperator == QLatin1String("destination-in")) {
327 return QPainter::CompositionMode_DestinationIn;
328 } else if (compositeOperator == QLatin1String("destination-out")) {
329 return QPainter::CompositionMode_DestinationOut;
330 } else if (compositeOperator == QLatin1String("destination-over")) {
331 return QPainter::CompositionMode_DestinationOver;
332 } else if (compositeOperator == QLatin1String("lighter")) {
333 return QPainter::CompositionMode_Lighten;
334 } else if (compositeOperator == QLatin1String("copy")) {
335 return QPainter::CompositionMode_Source;
336 } else if (compositeOperator == QLatin1String("xor")) {
337 return QPainter::CompositionMode_Xor;
338 } else if (compositeOperator == QLatin1String("qt-clear")) {
339 return QPainter::CompositionMode_Clear;
340 } else if (compositeOperator == QLatin1String("qt-destination")) {
341 return QPainter::CompositionMode_Destination;
342 } else if (compositeOperator == QLatin1String("qt-multiply")) {
343 return QPainter::CompositionMode_Multiply;
344 } else if (compositeOperator == QLatin1String("qt-screen")) {
345 return QPainter::CompositionMode_Screen;
346 } else if (compositeOperator == QLatin1String("qt-overlay")) {
347 return QPainter::CompositionMode_Overlay;
348 } else if (compositeOperator == QLatin1String("qt-darken")) {
349 return QPainter::CompositionMode_Darken;
350 } else if (compositeOperator == QLatin1String("qt-lighten")) {
351 return QPainter::CompositionMode_Lighten;
352 } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
353 return QPainter::CompositionMode_ColorDodge;
354 } else if (compositeOperator == QLatin1String("qt-color-burn")) {
355 return QPainter::CompositionMode_ColorBurn;
356 } else if (compositeOperator == QLatin1String("qt-hard-light")) {
357 return QPainter::CompositionMode_HardLight;
358 } else if (compositeOperator == QLatin1String("qt-soft-light")) {
359 return QPainter::CompositionMode_SoftLight;
360 } else if (compositeOperator == QLatin1String("qt-difference")) {
361 return QPainter::CompositionMode_Difference;
362 } else if (compositeOperator == QLatin1String("qt-exclusion")) {
363 return QPainter::CompositionMode_Exclusion;
365 return QPainter::CompositionMode_SourceOver;
368 static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
371 case QPainter::CompositionMode_SourceOver:
372 return QLatin1String("source-over");
373 case QPainter::CompositionMode_DestinationOver:
374 return QLatin1String("destination-over");
375 case QPainter::CompositionMode_Clear:
376 return QLatin1String("qt-clear");
377 case QPainter::CompositionMode_Source:
378 return QLatin1String("copy");
379 case QPainter::CompositionMode_Destination:
380 return QLatin1String("qt-destination");
381 case QPainter::CompositionMode_SourceIn:
382 return QLatin1String("source-in");
383 case QPainter::CompositionMode_DestinationIn:
384 return QLatin1String("destination-in");
385 case QPainter::CompositionMode_SourceOut:
386 return QLatin1String("source-out");
387 case QPainter::CompositionMode_DestinationOut:
388 return QLatin1String("destination-out");
389 case QPainter::CompositionMode_SourceAtop:
390 return QLatin1String("source-atop");
391 case QPainter::CompositionMode_DestinationAtop:
392 return QLatin1String("destination-atop");
393 case QPainter::CompositionMode_Xor:
394 return QLatin1String("xor");
395 case QPainter::CompositionMode_Plus:
396 return QLatin1String("plus");
397 case QPainter::CompositionMode_Multiply:
398 return QLatin1String("qt-multiply");
399 case QPainter::CompositionMode_Screen:
400 return QLatin1String("qt-screen");
401 case QPainter::CompositionMode_Overlay:
402 return QLatin1String("qt-overlay");
403 case QPainter::CompositionMode_Darken:
404 return QLatin1String("qt-darken");
405 case QPainter::CompositionMode_Lighten:
406 return QLatin1String("lighter");
407 case QPainter::CompositionMode_ColorDodge:
408 return QLatin1String("qt-color-dodge");
409 case QPainter::CompositionMode_ColorBurn:
410 return QLatin1String("qt-color-burn");
411 case QPainter::CompositionMode_HardLight:
412 return QLatin1String("qt-hard-light");
413 case QPainter::CompositionMode_SoftLight:
414 return QLatin1String("qt-soft-light");
415 case QPainter::CompositionMode_Difference:
416 return QLatin1String("qt-difference");
417 case QPainter::CompositionMode_Exclusion:
418 return QLatin1String("qt-exclusion");
426 static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
428 QQuickContext2DEngineData *ed = engineData(engine);
429 v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
430 QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
431 if (image.isNull()) {
432 r->image = QImage(w, h, QImage::Format_ARGB32);
433 r->image.fill(0x00000000);
435 Q_ASSERT(image.width() == w && image.height() == h);
436 r->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
438 v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
439 pixelData->SetExternalResource(r);
441 imageData->SetInternalField(0, pixelData);
445 //static script functions
448 \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
449 Holds the canvas item that the context paints on.
451 This property is read only.
453 static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
455 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
459 QV8Engine *engine = V8ENGINE_ACCESSOR();
461 return engine->newQObject(r->context->canvas());
465 \qmlmethod object QtQuick2::Context2D::restore()
466 Pops the top state on the stack, restoring the context to that state.
468 \sa QtQuick2::Context2D::save()
470 static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
472 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
475 r->context->popState();
480 \qmlmethod object QtQuick2::Context2D::reset()
481 Resets the context state and properties to the default values.
483 static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
485 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
494 \qmlmethod object QtQuick2::Context2D::save()
495 Pushes the current state onto the state stack.
497 Before changing any state attributes, you should save the current state
498 for future reference. The context maintains a stack of drawing states.
499 Each state consists of the current transformation matrix, clipping region,
500 and values of the following attributes:
502 \li\a QtQuick2::Context2D::strokeStyle
503 \li\a QtQuick2::Context2D::fillStyle
504 \li\a QtQuick2::Context2D::fillRule
505 \li\a QtQuick2::Context2D::globalAlpha
506 \li\a QtQuick2::Context2D::lineWidth
507 \li\a QtQuick2::Context2D::lineCap
508 \li\a QtQuick2::Context2D::lineJoin
509 \li\a QtQuick2::Context2D::miterLimit
510 \li\a QtQuick2::Context2D::shadowOffsetX
511 \li\a QtQuick2::Context2D::shadowOffsetY
512 \li\a QtQuick2::Context2D::shadowBlur
513 \li\a QtQuick2::Context2D::shadowColor
514 \li\a QtQuick2::Context2D::globalCompositeOperation
515 \li\a QtQuick2::Context2D::font
516 \li\a QtQuick2::Context2D::textAlign
517 \li\a QtQuick2::Context2D::textBaseline
520 The current path is NOT part of the drawing state. The path can be reset by
521 invoking the \a QtQuick2::Context2D::beginPath() method.
523 static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
525 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
528 r->context->pushState();
535 \qmlmethod object QtQuick2::Context2D::rotate(real angle)
536 Rotate the canvas around the current origin by \c angle in radians and clockwise direction.
538 ctx.rotate(Math.PI/2);
540 \image qml-item-canvas-rotate.png
542 The rotation transformation matrix is as follows:
544 \image qml-item-canvas-math-rotate.png
546 where the \c angle of rotation is in radians.
549 static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
551 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
554 if (args.Length() == 1)
555 r->context->rotate(args[0]->NumberValue());
560 \qmlmethod object QtQuick2::Context2D::scale(real x, real y)
561 Increases or decreases the size of each unit in the canvas grid by multiplying the scale factors
562 to the current tranform matrix.
563 Where \c x is the scale factor in the horizontal direction and \c y is the scale factor in the
565 The following code doubles the horizontal size of an object drawn on the canvas and half its
570 \image qml-item-canvas-scale.png
573 static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
575 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
579 if (args.Length() == 2)
580 r->context->scale(args[0]->NumberValue(), args[1]->NumberValue());
585 \qmlmethod object QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
586 Changes the transformation matrix to the matrix given by the arguments as described below.
588 Modifying the transformation matrix directly enables you to perform scaling,
589 rotating, and translating transformations in a single step.
591 Each point on the canvas is multiplied by the matrix before anything is
592 drawn. The \l{HTML5 Canvas API} defines the transformation matrix as:
594 \image qml-item-canvas-math.png
597 \li \c{a} is the scale factor in the horizontal (x) direction
598 \image qml-item-canvas-scalex.png
599 \li \c{c} is the skew factor in the x direction
600 \image qml-item-canvas-canvas-skewx.png
601 \li \c{e} is the translation in the x direction
602 \image qml-item-canvas-canvas-translate.png
603 \li \c{b} is the skew factor in the y (vertical) direction
604 \image qml-item-canvas-canvas-skewy.png
605 \li \c{d} is the scale factor in the y direction
606 \image qml-item-canvas-canvas-scaley.png
607 \li \c{f} is the translation in the y direction
608 \image qml-item-canvas-canvas-translatey.png
609 \li the last row remains constant
611 The scale factors and skew factors are multiples; \c{e} and \c{f} are
612 coordinate space units, just like the units in the \a QtQuick2::Context2D::translate(x,y)
615 \sa QtQuick2::Context2D::transform()
617 static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
619 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
623 if (args.Length() == 6)
624 r->context->setTransform( args[0]->NumberValue()
625 , args[1]->NumberValue()
626 , args[2]->NumberValue()
627 , args[3]->NumberValue()
628 , args[4]->NumberValue()
629 , args[5]->NumberValue());
635 \qmlmethod object QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
636 This method is very similar to \a QtQuick2::Context2D::setTransform(), but instead of replacing the old
637 tranform matrix, this method applies the given tranform matrix to the current matrix by mulitplying to it.
639 The \a setTransform(a, b, c, d, e, f) method actually resets the current transform to the identity matrix,
640 and then invokes the transform(a, b, c, d, e, f) method with the same arguments.
642 \sa QtQuick2::Context2D::setTransform()
644 static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
646 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
650 if (args.Length() == 6)
651 r->context->transform( args[0]->NumberValue()
652 , args[1]->NumberValue()
653 , args[2]->NumberValue()
654 , args[3]->NumberValue()
655 , args[4]->NumberValue()
656 , args[5]->NumberValue());
662 \qmlmethod object QtQuick2::Context2D::translate(real x, real y)
663 Translates the origin of the canvas to point (\c x, \c y).
665 \c x is the horizontal distance that the origin is translated, in coordinate space units,
666 \c y is the vertical distance that the origin is translated, in coordinate space units.
667 Translating the origin enables you to draw patterns of different objects on the canvas
668 without having to measure the coordinates manually for each shape.
670 static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
672 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
676 if (args.Length() == 2)
677 r->context->translate(args[0]->NumberValue(), args[1]->NumberValue());
683 \qmlmethod object QtQuick2::Context2D::resetTransform()
684 Reset the transformation matrix to default value.
686 \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform(), QtQuick2::Context2D::reset()
688 static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
690 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
693 r->context->setTransform(1, 0, 0, 1, 0, 0);
700 \qmlmethod object QtQuick2::Context2D::shear(real sh, real sv )
701 Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
703 static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
705 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
708 if (args.Length() == 2)
709 r->context->shear(args[0]->NumberValue(), args[1]->NumberValue());
716 \qmlproperty real QtQuick2::Context2D::globalAlpha
717 Holds the the current alpha value applied to rendering operations.
718 The value must be in the range from 0.0 (fully transparent) to 1.0 (fully opque).
719 The default value is 1.0.
721 static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
723 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
726 return v8::Number::New(r->context->state.globalAlpha);
729 static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
731 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
732 CHECK_CONTEXT_SETTER(r)
734 qreal globalAlpha = value->NumberValue();
736 if (!qIsFinite(globalAlpha))
739 if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
740 r->context->state.globalAlpha = globalAlpha;
741 r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
746 \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
747 Holds the the current the current composition operation, from the list below:
749 \li source-atop - A atop B. Display the source image wherever both images are opaque.
750 Display the destination image wherever the destination image is opaque but the source image is transparent.
751 Display transparency elsewhere.
752 \li source-in - A in B. Display the source image wherever both the source image and destination image are opaque.
753 Display transparency elsewhere.
754 \li source-out - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
755 Display transparency elsewhere.
756 \li source-over - (default) A over B. Display the source image wherever the source image is opaque.
757 Display the destination image elsewhere.
758 \li destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
759 \li destination-in - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
760 \li destination-out - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
761 \li destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
762 \li lighter - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
763 \li copy - A (B is ignored). Display the source image instead of the destination image.
764 \li xor - A xor B. Exclusive OR of the source image and destination image.
767 Additionally, this property also accepts the compositon modes listed in \a {QPainter::CompositionMode}. According to the W3C standard, these
768 extension composition modes are provided as "vendorName-operationName" syntax, for example: \c {QPainter::CompositionMode_Exclusion} is porvided as
771 static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
773 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
777 QV8Engine *engine = V8ENGINE_ACCESSOR();
779 return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
782 static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
784 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
785 CHECK_CONTEXT_SETTER(r)
787 QV8Engine *engine = V8ENGINE_ACCESSOR();
790 QString mode = engine->toString(value);
791 QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
792 if (cm == QPainter::CompositionMode_SourceOver && mode != QStringLiteral("source-over"))
795 if (cm != r->context->state.globalCompositeOperation) {
796 r->context->state.globalCompositeOperation = cm;
797 r->context->buffer()->setGlobalCompositeOperation(cm);
803 \qmlproperty variant QtQuick2::Context2D::fillStyle
804 Holds the current style used for filling shapes.
805 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object. Invalid values are ignored.
806 This property accepts several color syntaxes:
808 \li 'rgb(red, green, blue)' - for example: 'rgb(255, 100, 55)' or 'rgb(100%, 70%, 30%)'
809 \li 'rgba(red, green, blue, alpha)' - for example: 'rgb(255, 100, 55, 1.0)' or 'rgb(100%, 70%, 30%, 0.5)'
810 \li 'hsl(hue, saturation, lightness)'
811 \li 'hsla(hue, saturation, lightness, alpha)'
812 \li '#RRGGBB' - for example: '#00FFCC'
813 \li Qt.rgba(red, green, blue, alpha) - for example: Qt.rgba(0.3, 0.7, 1, 1.0)
815 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
816 best performance, because it's already a valid QColor value, does not need to be parsed everytime.
818 The default value is '#000000'.
819 \sa QtQuick2::Context2D::createLinearGradient
820 \sa QtQuick2::Context2D::createRadialGradient
821 \sa QtQuick2::Context2D::createPattern
822 \sa QtQuick2::Context2D::strokeStyle
824 static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
826 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
829 QV8Engine *engine = V8ENGINE_ACCESSOR();
831 QColor color = r->context->state.fillStyle.color();
832 if (color.isValid()) {
833 if (color.alpha() == 255)
834 return engine->toString(color.name());
835 QString alphaString = QString::number(color.alphaF(), 'f');
836 while (alphaString.endsWith(QLatin1Char('0')))
838 if (alphaString.endsWith(QLatin1Char('.')))
839 alphaString += QLatin1Char('0');
840 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
842 return r->context->m_fillStyle;
845 static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
847 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
848 CHECK_CONTEXT_SETTER(r)
850 QV8Engine *engine = V8ENGINE_ACCESSOR();
852 if (value->IsObject()) {
853 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
854 if (color.isValid()) {
855 r->context->state.fillStyle = color;
856 r->context->buffer()->setFillStyle(color);
857 r->context->m_fillStyle = value;
859 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
860 if (style && style->brush != r->context->state.fillStyle) {
861 r->context->state.fillStyle = style->brush;
862 r->context->buffer()->setFillStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
863 r->context->m_fillStyle = value;
864 r->context->state.fillPatternRepeatX = style->patternRepeatX;
865 r->context->state.fillPatternRepeatY = style->patternRepeatY;
868 } else if (value->IsString()) {
869 QColor color = qt_color_from_string(value);
870 if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
871 r->context->state.fillStyle = QBrush(color);
872 r->context->buffer()->setFillStyle(r->context->state.fillStyle);
873 r->context->m_fillStyle = value;
878 \qmlproperty enumeration QtQuick2::Context2D::fillRule
879 Holds the current fill rule used for filling shapes. The following fill rules supported:
884 Note: Unlike the \a QPainterPath, the Canvas API uses the winding fill as the default fill rule.
885 The fillRule property is part of the context rendering state.
887 \sa QtQuick2::Context2D::fillStyle
889 static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
891 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
893 QV8Engine *engine = V8ENGINE_ACCESSOR();
895 return engine->fromVariant(r->context->state.fillRule);
898 static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
900 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
901 CHECK_CONTEXT_SETTER(r)
903 QV8Engine *engine = V8ENGINE_ACCESSOR();
905 if ((value->IsString() && engine->toString(value) == QStringLiteral("WindingFill"))
906 ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
907 r->context->state.fillRule = Qt::WindingFill;
908 } else if ((value->IsString() && engine->toString(value) == QStringLiteral("OddEvenFill"))
909 ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
910 r->context->state.fillRule = Qt::OddEvenFill;
914 r->context->m_path.setFillRule(r->context->state.fillRule);
917 \qmlproperty variant QtQuick2::Context2D::strokeStyle
918 Holds the current color or style to use for the lines around shapes,
919 The style can be either a string containing a CSS color, a CanvasGradient or CanvasPattern object.
920 Invalid values are ignored.
922 The default value is '#000000'.
924 \sa QtQuick2::Context2D::createLinearGradient
925 \sa QtQuick2::Context2D::createRadialGradient
926 \sa QtQuick2::Context2D::createPattern
927 \sa QtQuick2::Context2D::fillStyle
929 v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
931 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
934 QV8Engine *engine = V8ENGINE_ACCESSOR();
936 QColor color = r->context->state.strokeStyle.color();
937 if (color.isValid()) {
938 if (color.alpha() == 255)
939 return engine->toString(color.name());
940 QString alphaString = QString::number(color.alphaF(), 'f');
941 while (alphaString.endsWith(QLatin1Char('0')))
943 if (alphaString.endsWith(QLatin1Char('.')))
944 alphaString += QLatin1Char('0');
945 return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
947 return r->context->m_strokeStyle;
950 static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
952 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
953 CHECK_CONTEXT_SETTER(r)
955 QV8Engine *engine = V8ENGINE_ACCESSOR();
957 if (value->IsObject()) {
958 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
959 if (color.isValid()) {
960 r->context->state.fillStyle = color;
961 r->context->buffer()->setStrokeStyle(color);
962 r->context->m_strokeStyle = value;
964 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
965 if (style && style->brush != r->context->state.strokeStyle) {
966 r->context->state.strokeStyle = style->brush;
967 r->context->buffer()->setStrokeStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
968 r->context->m_strokeStyle = value;
969 r->context->state.strokePatternRepeatX = style->patternRepeatX;
970 r->context->state.strokePatternRepeatY = style->patternRepeatY;
974 } else if (value->IsString()) {
975 QColor color = qt_color_from_string(value);
976 if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
977 r->context->state.strokeStyle = QBrush(color);
978 r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
979 r->context->m_strokeStyle = value;
985 \qmlmethod object QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
986 Returns a CanvasGradient object that represents a linear gradient that transitions the color along a line between
987 the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
989 A gradient is a smooth transition between colors. There are two types of gradients: linear and radial.
990 Gradients must have two or more color stops, representing color shifts positioned from 0 to 1 between
991 to the gradient's starting and end points or circles.
993 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
994 \sa QtQuick2::Context2D::createRadialGradient
995 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
996 \sa QtQuick2::Context2D::createPattern
997 \sa QtQuick2::Context2D::fillStyle
998 \sa QtQuick2::Context2D::strokeStyle
1001 static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
1003 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1007 QV8Engine *engine = V8ENGINE();
1009 if (args.Length() == 4) {
1010 QQuickContext2DEngineData *ed = engineData(engine);
1011 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1012 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1013 qreal x0 = args[0]->NumberValue();
1014 qreal y0 = args[1]->NumberValue();
1015 qreal x1 = args[2]->NumberValue();
1016 qreal y1 = args[3]->NumberValue();
1021 || !qIsFinite(y1)) {
1023 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
1026 r->brush = QLinearGradient(x0, y0, x1, y1);
1027 gradient->SetExternalResource(r);
1035 \qmlmethod object QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
1036 Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
1037 origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
1039 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1040 \sa QtQuick2::Context2D::createLinearGradient
1041 \sa QtQuick2::Context2D::ctx2d_createConicalGradient
1042 \sa QtQuick2::Context2D::createPattern
1043 \sa QtQuick2::Context2D::fillStyle
1044 \sa QtQuick2::Context2D::strokeStyle
1047 static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
1049 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1053 QV8Engine *engine = V8ENGINE();
1055 if (args.Length() == 6) {
1056 QQuickContext2DEngineData *ed = engineData(engine);
1057 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1058 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1060 qreal x0 = args[0]->NumberValue();
1061 qreal y0 = args[1]->NumberValue();
1062 qreal r0 = args[2]->NumberValue();
1063 qreal x1 = args[3]->NumberValue();
1064 qreal y1 = args[4]->NumberValue();
1065 qreal r1 = args[5]->NumberValue();
1072 || !qIsFinite(y1)) {
1074 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
1077 if (r0 < 0 || r1 < 0)
1078 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
1081 r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
1082 gradient->SetExternalResource(r);
1090 \qmlmethod object QtQuick2::Context2D::createConicalGradient(real x, real y, real angle)
1091 Returns a CanvasGradient object that represents a conical gradient that interpolate colors counter-clockwise around a center point (\c x, \c y)
1092 with start angle \c angle in units of radians.
1094 \sa QtQuick2::Context2D::CanvasGradient::addColorStop
1095 \sa QtQuick2::Context2D::createLinearGradient
1096 \sa QtQuick2::Context2D::ctx2d_createRadialGradient
1097 \sa QtQuick2::Context2D::createPattern
1098 \sa QtQuick2::Context2D::fillStyle
1099 \sa QtQuick2::Context2D::strokeStyle
1102 static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &args)
1104 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1108 QV8Engine *engine = V8ENGINE();
1110 if (args.Length() == 6) {
1111 QQuickContext2DEngineData *ed = engineData(engine);
1112 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
1113 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1115 qreal x = args[0]->NumberValue();
1116 qreal y = args[1]->NumberValue();
1117 qreal angle = DEGREES(args[2]->NumberValue());
1118 if (!qIsFinite(x) || !qIsFinite(y)) {
1120 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
1123 if (!qIsFinite(angle)) {
1125 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
1128 r->brush = QConicalGradient(x, y, angle);
1129 gradient->SetExternalResource(r);
1136 \qmlmethod variant createPattern(Color color, enumeration patternMode)
1137 This is a overload function.
1138 Returns a CanvasPattern object that uses the given \c color and \c patternMode.
1139 The valid pattern modes are:
1142 \li Qt.Dense1Pattern
1143 \li Qt.Dense2Pattern
1144 \li Qt.Dense3Pattern
1145 \li Qt.Dense4Pattern
1146 \li Qt.Dense5Pattern
1147 \li Qt.Dense6Pattern
1148 \li Qt.Dense7Pattern
1154 \li Qt.DiagCrossPattern
1159 \qmlmethod variant createPattern(Image image, string repetition)
1160 Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
1162 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.
1164 The allowed values for \a repetition are:
1167 \li "repeat" - both directions
1168 \li "repeat-x - horizontal only
1169 \li "repeat-y" - vertical only
1170 \li "no-repeat" - neither
1173 If the repetition argument is empty or null, the value "repeat" is used.
1175 \sa QtQuick2::Context2D::strokeStyle
1176 \sa QtQuick2::Context2D::fillStyle
1178 static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
1180 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1184 QV8Engine *engine = V8ENGINE();
1186 if (args.Length() == 2) {
1187 QQuickContext2DEngineData *ed = engineData(engine);
1188 QV8Context2DStyleResource *styleResouce = new QV8Context2DStyleResource(engine);
1190 QColor color = engine->toVariant(args[0], qMetaTypeId<QColor>()).value<QColor>();
1191 if (color.isValid()) {
1192 int patternMode = args[1]->IntegerValue();
1193 Qt::BrushStyle style = Qt::SolidPattern;
1194 if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
1195 style = static_cast<Qt::BrushStyle>(patternMode);
1197 styleResouce->brush = QBrush(color, style);
1199 QImage patternTexture;
1201 if (args[0]->IsObject()) {
1202 QV8Context2DPixelArrayResource *pixelData = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->Get(v8::String::New("data"))->ToObject());
1204 patternTexture = pixelData->image;
1207 patternTexture = r->context->createPixmap(QUrl(engine->toString(args[0]->ToString())))->image();
1210 if (!patternTexture.isNull()) {
1211 styleResouce->brush.setTextureImage(patternTexture);
1213 QString repetition = engine->toString(args[1]);
1214 if (repetition == QStringLiteral("repeat") || repetition.isEmpty()) {
1215 styleResouce->patternRepeatX = true;
1216 styleResouce->patternRepeatY = true;
1217 } else if (repetition == QStringLiteral("repeat-x")) {
1218 styleResouce->patternRepeatX = true;
1219 } else if (repetition == QStringLiteral("repeat-y")) {
1220 styleResouce->patternRepeatY = true;
1221 } else if (repetition == QStringLiteral("no-repeat")) {
1222 styleResouce->patternRepeatY = false;
1223 styleResouce->patternRepeatY = false;
1225 //TODO: exception: SYNTAX_ERR
1231 v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
1232 pattern->SetExternalResource(styleResouce);
1236 return v8::Undefined();
1241 \qmlproperty string QtQuick2::Context2D::lineCap
1242 Holds the the current line cap style.
1243 The possible line cap styles are:
1245 \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.
1246 \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.
1247 \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.
1249 Other values are ignored.
1251 v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
1253 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1257 QV8Engine *engine = V8ENGINE_ACCESSOR();
1258 switch (r->context->state.lineCap) {
1260 return engine->toString(QLatin1String("round"));
1262 return engine->toString(QLatin1String("butt"));
1264 return engine->toString(QLatin1String("square"));
1268 return engine->toString(QLatin1String("butt"));;
1271 static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1273 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1274 CHECK_CONTEXT_SETTER(r)
1276 QV8Engine *engine = V8ENGINE_ACCESSOR();
1278 QString lineCap = engine->toString(value);
1279 Qt::PenCapStyle cap;
1280 if (lineCap == QLatin1String("round"))
1282 else if (lineCap == QLatin1String("butt"))
1284 else if (lineCap == QLatin1String("square"))
1285 cap = Qt::SquareCap;
1289 if (cap != r->context->state.lineCap) {
1290 r->context->state.lineCap = cap;
1291 r->context->buffer()->setLineCap(cap);
1296 \qmlproperty string QtQuick2::Context2D::lineJoin
1297 Holds the the current line join style. A join exists at any point in a subpath
1298 shared by two consecutive lines. When a subpath is closed, then a join also exists
1299 at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
1301 The possible line join styles are:
1303 \li bevel - this is all that is rendered at joins.
1304 \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.
1305 \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.
1307 Other values are ignored.
1309 v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
1311 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1315 QV8Engine *engine = V8ENGINE_ACCESSOR();
1316 switch (r->context->state.lineJoin) {
1318 return engine->toString(QLatin1String("round"));
1320 return engine->toString(QLatin1String("bevel"));
1322 return engine->toString(QLatin1String("miter"));
1326 return engine->toString(QLatin1String("miter"));
1329 static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1331 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1332 CHECK_CONTEXT_SETTER(r)
1334 QV8Engine *engine = V8ENGINE_ACCESSOR();
1336 QString lineJoin = engine->toString(value);
1337 Qt::PenJoinStyle join;
1338 if (lineJoin == QLatin1String("round"))
1339 join = Qt::RoundJoin;
1340 else if (lineJoin == QLatin1String("bevel"))
1341 join = Qt::BevelJoin;
1342 else if (lineJoin == QLatin1String("miter"))
1343 join = Qt::SvgMiterJoin;
1347 if (join != r->context->state.lineJoin) {
1348 r->context->state.lineJoin = join;
1349 r->context->buffer()->setLineJoin(join);
1354 \qmlproperty real QtQuick2::Context2D::lineWidth
1355 Holds the the current line width. Values that are not finite values greater than zero are ignored.
1357 v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
1359 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1363 return v8::Number::New(r->context->state.lineWidth);
1366 static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1368 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1369 CHECK_CONTEXT_SETTER(r)
1371 qreal w = value->NumberValue();
1373 if (w > 0 && qIsFinite(w) && w != r->context->state.lineWidth) {
1374 r->context->state.lineWidth = w;
1375 r->context->buffer()->setLineWidth(w);
1380 \qmlproperty real QtQuick2::Context2D::miterLimit
1381 Holds the current miter limit ratio.
1382 The default miter limit value is 10.0.
1384 v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
1386 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1390 return v8::Number::New(r->context->state.miterLimit);
1393 static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1395 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1396 CHECK_CONTEXT_SETTER(r)
1398 qreal ml = value->NumberValue();
1400 if (ml > 0 && qIsFinite(ml) && ml != r->context->state.miterLimit) {
1401 r->context->state.miterLimit = ml;
1402 r->context->buffer()->setMiterLimit(ml);
1408 \qmlproperty real QtQuick2::Context2D::shadowBlur
1409 Holds the current level of blur applied to shadows
1411 v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
1413 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1417 return v8::Number::New(r->context->state.shadowBlur);
1420 static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1422 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1423 CHECK_CONTEXT_SETTER(r)
1424 qreal blur = value->NumberValue();
1426 if (blur > 0 && qIsFinite(blur) && blur != r->context->state.shadowBlur) {
1427 r->context->state.shadowBlur = blur;
1428 r->context->buffer()->setShadowBlur(blur);
1433 \qmlproperty string QtQuick2::Context2D::shadowColor
1434 Holds the current shadow color.
1436 v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
1438 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1442 QV8Engine *engine = V8ENGINE_ACCESSOR();
1444 return engine->toString(r->context->state.shadowColor.name());
1447 static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1449 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1450 CHECK_CONTEXT_SETTER(r)
1452 QColor color = qt_color_from_string(value);
1454 if (color.isValid() && color != r->context->state.shadowColor) {
1455 r->context->state.shadowColor = color;
1456 r->context->buffer()->setShadowColor(color);
1462 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
1463 Holds the current shadow offset in the positive horizontal distance.
1465 \sa QtQuick2::Context2D::shadowOffsetY
1467 v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
1469 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1473 return v8::Number::New(r->context->state.shadowOffsetX);
1476 static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1478 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1479 CHECK_CONTEXT_SETTER(r)
1481 qreal offsetX = value->NumberValue();
1482 if (qIsFinite(offsetX) && offsetX != r->context->state.shadowOffsetX) {
1483 r->context->state.shadowOffsetX = offsetX;
1484 r->context->buffer()->setShadowOffsetX(offsetX);
1488 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
1489 Holds the current shadow offset in the positive vertical distance.
1491 \sa QtQuick2::Context2D::shadowOffsetX
1493 v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
1495 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1499 return v8::Number::New(r->context->state.shadowOffsetY);
1502 static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1504 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1505 CHECK_CONTEXT_SETTER(r)
1507 qreal offsetY = value->NumberValue();
1508 if (qIsFinite(offsetY) && offsetY != r->context->state.shadowOffsetY) {
1509 r->context->state.shadowOffsetY = offsetY;
1510 r->context->buffer()->setShadowOffsetY(offsetY);
1514 v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
1516 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1518 return r->context->m_v8path;
1521 static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1523 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1524 CHECK_CONTEXT_SETTER(r)
1525 QV8Engine *engine = V8ENGINE_ACCESSOR();
1527 r->context->beginPath();
1528 if (value->IsObject()) {
1529 QQuickPath* path = qobject_cast<QQuickPath*>(engine->toQObject(value));
1531 r->context->m_path = path->path();
1533 QString path = engine->toString(value->ToString());
1534 QQuickSvgParser::parsePathDataFast(path, r->context->m_path);
1536 r->context->m_v8path = value;
1541 \qmlmethod object QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
1542 Clears all pixels on the canvas in the given rectangle to transparent black.
1544 static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
1546 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1550 if (args.Length() == 4)
1551 r->context->clearRect(args[0]->NumberValue(),
1552 args[1]->NumberValue(),
1553 args[2]->NumberValue(),
1554 args[3]->NumberValue());
1559 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1560 Paint the specified rectangular area using the fillStyle.
1562 \sa QtQuick2::Context2D::fillStyle
1564 static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
1566 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1569 if (args.Length() == 4)
1570 r->context->fillRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1575 \qmlmethod object QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1576 Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
1577 and (if appropriate) miterLimit attributes.
1579 \sa QtQuick2::Context2D::strokeStyle
1580 \sa QtQuick2::Context2D::lineWidth
1581 \sa QtQuick2::Context2D::lineJoin
1582 \sa QtQuick2::Context2D::miterLimit
1584 static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
1586 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1589 if (args.Length() == 4)
1590 r->context->strokeRect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1595 // Complex shapes (paths) API
1597 \qmlmethod object QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
1598 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.
1599 \image qml-item-canvas-arcTo2.png
1600 \sa QtQuick2::Context2D::arcTo,
1601 {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
1603 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
1605 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1608 if (args.Length() >= 5) {
1609 bool antiClockwise = false;
1611 if (args.Length() == 6)
1612 antiClockwise = args[5]->BooleanValue();
1614 qreal radius = args[2]->NumberValue();
1616 if (qIsFinite(radius) && radius < 0)
1617 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1619 r->context->arc(args[0]->NumberValue(),
1620 args[1]->NumberValue(),
1622 args[3]->NumberValue(),
1623 args[4]->NumberValue(),
1631 \qmlmethod object QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
1633 Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
1634 To draw an arc, you begin with the same steps your followed to create a line:
1636 \li Call the context.beginPath() method to set a new path.
1637 \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).
1638 \li To draw an arc or circle, call the context.arcTo(\c x1, \c y1, \c x2, \c y2,\c radius) method.
1639 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
1640 it to the previous subpath by a straight line.
1642 \image qml-item-canvas-arcTo.png
1643 Both startAngle and endAngle are measured from the x axis in units of radians.
1645 \image qml-item-canvas-startAngle.png
1646 The anticlockwise has the value TRUE for each arc in the figure above because they are all drawn in the counterclockwise direction.
1647 \sa QtQuick2::Context2D::arc, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d
1648 context standard for arcTo}
1650 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
1652 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1655 if (args.Length() == 5) {
1656 qreal radius = args[4]->NumberValue();
1658 if (qIsFinite(radius) && radius < 0)
1659 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
1661 r->context->arcTo(args[0]->NumberValue(),
1662 args[1]->NumberValue(),
1663 args[2]->NumberValue(),
1664 args[3]->NumberValue(),
1672 \qmlmethod object QtQuick2::Context2D::beginPath()
1674 Resets the current path to a new path.
1676 static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
1678 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1682 r->context->beginPath();
1688 \qmlmethod object QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
1690 Adds a cubic Bezier curve between the current position and the given endPoint using the control points specified by (\c cp1x, cp1y),
1691 and (\c cp2x, \c cp2y).
1692 After the curve is added, the current position is updated to be at the end point (\c x, \c y) of the curve.
1693 The following code produces the path shown below:
1695 ctx.strokeStyle = Qt.rgba(0, 0, 0, 1);
1698 ctx.moveTo(20, 0);//start point
1699 ctx.bezierCurveTo(-10, 90, 210, 90, 180, 0);
1702 \image qml-item-canvas-bezierCurveTo.png
1703 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
1704 \sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
1706 static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
1708 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1712 if (args.Length() == 6) {
1713 qreal cp1x = args[0]->NumberValue();
1714 qreal cp1y = args[1]->NumberValue();
1715 qreal cp2x = args[2]->NumberValue();
1716 qreal cp2y = args[3]->NumberValue();
1717 qreal x = args[4]->NumberValue();
1718 qreal y = args[5]->NumberValue();
1720 if (!qIsFinite(cp1x) || !qIsFinite(cp1y) || !qIsFinite(cp2x) || !qIsFinite(cp2y) || !qIsFinite(x) || !qIsFinite(y))
1723 r->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
1730 \qmlmethod object QtQuick2::Context2D::clip()
1732 Creates the clipping region from the current path.
1733 Any parts of the shape outside the clipping path are not displayed.
1734 To create a complex shape using the \a clip() method:
1737 \li Call the \c{context.beginPath()} method to set the clipping path.
1738 \li Define the clipping path by calling any combination of the \c{lineTo},
1739 \c{arcTo}, \c{arc}, \c{moveTo}, etc and \c{closePath} methods.
1740 \li Call the \c{context.clip()} method.
1743 The new shape displays. The following shows how a clipping path can
1744 modify how an image displays:
1746 \image qml-canvas-clip-complex.png
1747 \sa QtQuick2::Context2D::beginPath()
1748 \sa QtQuick2::Context2D::closePath()
1749 \sa QtQuick2::Context2D::stroke()
1750 \sa QtQuick2::Context2D::fill()
1751 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-clip}{W3C 2d context standard for clip}
1753 static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
1755 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1763 \qmlmethod object QtQuick2::Context2D::closePath()
1764 Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting a new path.
1765 The current point of the new path is the previous subpath's first point.
1767 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath}{W3C 2d context standard for closePath}
1769 static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
1771 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1775 r->context->closePath();
1781 \qmlmethod object QtQuick2::Context2D::fill()
1783 Fills the subpaths with the current fill style.
1785 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-fill}{W3C 2d context standard for fill}
1787 \sa QtQuick2::Context2D::fillStyle
1789 static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
1791 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1798 \qmlmethod object QtQuick2::Context2D::lineTo(real x, real y)
1800 Draws a line from the current position to the point (x, y).
1802 static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
1804 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1808 if (args.Length() == 2) {
1809 qreal x = args[0]->NumberValue();
1810 qreal y = args[1]->NumberValue();
1812 if (!qIsFinite(x) || !qIsFinite(y))
1815 r->context->lineTo(x, y);
1822 \qmlmethod object QtQuick2::Context2D::moveTo(real x, real y)
1824 Creates a new subpath with the given point.
1826 static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
1828 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1831 if (args.Length() == 2) {
1832 qreal x = args[0]->NumberValue();
1833 qreal y = args[1]->NumberValue();
1835 if (!qIsFinite(x) || !qIsFinite(y))
1837 r->context->moveTo(x, y);
1843 \qmlmethod object QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
1845 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).
1847 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto}{W3C 2d context standard for for quadraticCurveTo}
1849 static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
1851 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1854 if (args.Length() == 4) {
1855 qreal cpx = args[0]->NumberValue();
1856 qreal cpy = args[1]->NumberValue();
1857 qreal x = args[2]->NumberValue();
1858 qreal y = args[3]->NumberValue();
1860 if (!qIsFinite(cpx) || !qIsFinite(cpy) || !qIsFinite(x) || !qIsFinite(y))
1863 r->context->quadraticCurveTo(cpx, cpy, x, y);
1870 \qmlmethod object QtQuick2::Context2D::rect(real x, real y, real w, real h)
1872 Adds a rectangle at position (\c x, \c y), with the given width \c w and height \c h, as a closed subpath.
1874 static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
1876 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1879 if (args.Length() == 4)
1880 r->context->rect(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1885 \qmlmethod object QtQuick2::Context2D::roundedRect(real x, real y, real w, real h, real xRadius, real yRadius)
1887 Adds the given rectangle rect with rounded corners to the path. The \c xRadius and \c yRadius arguments specify the radius of the
1888 ellipses defining the corners of the rounded rectangle.
1890 static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
1892 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1895 if (args.Length() == 6)
1896 r->context->roundedRect(args[0]->NumberValue()
1897 , args[1]->NumberValue()
1898 , args[2]->NumberValue()
1899 , args[3]->NumberValue()
1900 , args[4]->NumberValue()
1901 , args[5]->NumberValue());
1906 \qmlmethod object QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
1908 Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
1909 and adds it to the path as a closed subpath.
1911 The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
1913 static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
1915 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1919 if (args.Length() == 4)
1920 r->context->ellipse(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), args[3]->NumberValue());
1926 \qmlmethod object QtQuick2::Context2D::text(string text, real x, real y)
1928 Adds the given \c text to the path as a set of closed subpaths created from the current context font supplied.
1929 The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (\c x, \c y).
1931 static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
1933 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1936 QV8Engine *engine = V8ENGINE();
1937 if (args.Length() == 3) {
1938 qreal x = args[1]->NumberValue();
1939 qreal y = args[2]->NumberValue();
1941 if (!qIsFinite(x) || !qIsFinite(y))
1943 r->context->text(engine->toString(args[0]), x, y);
1949 \qmlmethod object QtQuick2::Context2D::stroke()
1951 Strokes the subpaths with the current stroke style.
1953 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke}{W3C 2d context standard for stroke}
1955 \sa QtQuick2::Context2D::strokeStyle
1957 static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
1959 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1962 r->context->stroke();
1967 \qmlmethod object QtQuick2::Context2D::isPointInPath(real x, real y)
1969 Returns true if the given point is in the current path.
1971 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath}{W3C 2d context standard for isPointInPath}
1973 static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
1975 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1978 bool pointInPath = false;
1979 if (args.Length() == 2)
1980 pointInPath = r->context->isPointInPath(args[0]->NumberValue(), args[1]->NumberValue());
1981 return v8::Boolean::New(pointInPath);
1984 static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
1988 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
1991 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
1995 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
1998 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
2002 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
2006 \qmlproperty string QtQuick2::Context2D::font
2007 Holds the current font settings.
2009 The default font value is "10px sans-serif".
2010 See {http://www.w3.org/TR/2dcontext/#dom-context-2d-font}{w3C 2d context standard for font}
2012 v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
2014 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2017 QV8Engine *engine = V8ENGINE_ACCESSOR();
2019 return engine->toString(r->context->state.font.toString());
2022 static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2024 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2025 CHECK_CONTEXT_SETTER(r)
2027 QV8Engine *engine = V8ENGINE_ACCESSOR();
2028 QString fs = engine->toString(value);
2029 QFont font = qt_font_from_string(fs);
2030 if (font != r->context->state.font) {
2031 r->context->state.font = font;
2036 \qmlproperty string QtQuick2::Context2D::textAlign
2038 Holds the current text alignment settings.
2039 The possible values are:
2047 Other values are ignored. The default value is "start".
2049 v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
2051 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2053 QV8Engine *engine = V8ENGINE_ACCESSOR();
2054 switch (r->context->state.textAlign) {
2055 case QQuickContext2D::Start:
2056 return engine->toString(QLatin1String("start"));
2057 case QQuickContext2D::End:
2058 return engine->toString(QLatin1String("end"));
2059 case QQuickContext2D::Left:
2060 return engine->toString(QLatin1String("left"));
2061 case QQuickContext2D::Right:
2062 return engine->toString(QLatin1String("right"));
2063 case QQuickContext2D::Center:
2064 return engine->toString(QLatin1String("center"));
2068 return engine->toString(QLatin1String("start"));
2071 static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2073 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2074 CHECK_CONTEXT_SETTER(r)
2075 QV8Engine *engine = V8ENGINE_ACCESSOR();
2077 QString textAlign = engine->toString(value);
2079 QQuickContext2D::TextAlignType ta;
2080 if (textAlign == QLatin1String("start"))
2081 ta = QQuickContext2D::Start;
2082 else if (textAlign == QLatin1String("end"))
2083 ta = QQuickContext2D::End;
2084 else if (textAlign == QLatin1String("left"))
2085 ta = QQuickContext2D::Left;
2086 else if (textAlign == QLatin1String("right"))
2087 ta = QQuickContext2D::Right;
2088 else if (textAlign == QLatin1String("center"))
2089 ta = QQuickContext2D::Center;
2093 if (ta != r->context->state.textAlign) {
2094 r->context->state.textAlign = ta;
2099 \qmlproperty string QtQuick2::Context2D::textBaseline
2101 Holds the current baseline alignment settings.
2102 The possible values are:
2111 Other values are ignored. The default value is "alphabetic".
2113 v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
2115 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2118 QV8Engine *engine = V8ENGINE_ACCESSOR();
2119 switch (r->context->state.textBaseline) {
2120 case QQuickContext2D::Alphabetic:
2121 return engine->toString(QLatin1String("alphabetic"));
2122 case QQuickContext2D::Hanging:
2123 return engine->toString(QLatin1String("hanging"));
2124 case QQuickContext2D::Top:
2125 return engine->toString(QLatin1String("top"));
2126 case QQuickContext2D::Bottom:
2127 return engine->toString(QLatin1String("bottom"));
2128 case QQuickContext2D::Middle:
2129 return engine->toString(QLatin1String("middle"));
2133 return engine->toString(QLatin1String("alphabetic"));
2136 static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
2138 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
2139 CHECK_CONTEXT_SETTER(r)
2140 QV8Engine *engine = V8ENGINE_ACCESSOR();
2141 QString textBaseline = engine->toString(value);
2143 QQuickContext2D::TextBaseLineType tb;
2144 if (textBaseline == QLatin1String("alphabetic"))
2145 tb = QQuickContext2D::Alphabetic;
2146 else if (textBaseline == QLatin1String("hanging"))
2147 tb = QQuickContext2D::Hanging;
2148 else if (textBaseline == QLatin1String("top"))
2149 tb = QQuickContext2D::Top;
2150 else if (textBaseline == QLatin1String("bottom"))
2151 tb = QQuickContext2D::Bottom;
2152 else if (textBaseline == QLatin1String("middle"))
2153 tb = QQuickContext2D::Middle;
2157 if (tb != r->context->state.textBaseline) {
2158 r->context->state.textBaseline = tb;
2163 \qmlmethod object QtQuick2::Context2D::fillText(text, x, y)
2164 Fills the given text at the given position.
2165 \sa QtQuick2::Context2D::font
2166 \sa QtQuick2::Context2D::textAlign
2167 \sa QtQuick2::Context2D::textBaseline
2168 \sa QtQuick2::Context2D::strokeText
2170 static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
2172 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2175 QV8Engine *engine = V8ENGINE();
2176 if (args.Length() == 3) {
2177 qreal x = args[1]->NumberValue();
2178 qreal y = args[2]->NumberValue();
2179 if (!qIsFinite(x) || !qIsFinite(y))
2181 QPainterPath textPath = r->context->createTextGlyphs(x, y, engine->toString(args[0]));
2182 r->context->buffer()->fill(textPath);
2187 \qmlmethod object QtQuick2::Context2D::strokeText(text, x, y)
2188 Strokes the given text at the given position.
2189 \sa QtQuick2::Context2D::font
2190 \sa QtQuick2::Context2D::textAlign
2191 \sa QtQuick2::Context2D::textBaseline
2192 \sa QtQuick2::Context2D::fillText
2194 static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
2196 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2199 QV8Engine *engine = V8ENGINE();
2200 if (args.Length() == 3)
2201 r->context->drawText(engine->toString(args[0]), args[1]->NumberValue(), args[2]->NumberValue(), false);
2205 \qmltype TextMetrics
2206 \inqmlmodule QtQuick 2
2208 \ingroup qtquick-canvas
2209 \brief Provides a Context2D TextMetrics interface
2211 The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
2212 See {http://www.w3.org/TR/2dcontext/#textmetrics}{W3C 2d context TexMetrics} for more details.
2214 \sa QtQuick2::Context2D::measureText
2215 \sa QtQuick2::TextMetrics::width
2219 \qmlproperty int QtQuick2::TextMetrics::width
2220 Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
2221 This property is read only.
2225 \qmlmethod variant QtQuick2::Context2D::measureText(text)
2226 Returns a TextMetrics object with the metrics of the given text in the current font.
2228 static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
2230 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2233 QV8Engine *engine = V8ENGINE();
2235 if (args.Length() == 1) {
2236 QFontMetrics fm(r->context->state.font);
2237 uint width = fm.width(engine->toString(args[0]));
2238 v8::Local<v8::Object> tm = v8::Object::New();
2239 tm->Set(v8::String::New("width"), v8::Number::New(width));
2242 return v8::Undefined();
2247 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
2248 Draws the given \a image on the canvas at position (\a dx, \a dy).
2250 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2251 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2252 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2253 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2255 \sa QtQuick2::CanvasImageData
2257 \sa QtQuick2::Canvas::loadImage
2258 \sa QtQuick2::Canvas::isImageLoaded
2259 \sa QtQuick2::Canvas::imageLoaded
2261 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2264 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
2265 This is an overloaded function.
2266 Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
2270 The \a image type can be an Image item, an image url or a \a {QtQuick2::CanvasImageData} object.
2271 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2272 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2273 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2275 \sa QtQuick2::CanvasImageData
2277 \sa QtQuick2::Canvas::loadImage
2278 \sa QtQuick2::Canvas::isImageLoaded
2279 \sa QtQuick2::Canvas::imageLoaded
2281 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2284 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
2285 This is an overloaded function.
2286 Draws the given item as \a image from source point (\a sx, \a sy) and source width \a sw, source height \a sh
2287 onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
2291 The \a image type can be an Image or Canvas item, an image url or a \a {QtQuick2::CanvasImageData} object.
2292 When given as Image item, if the image isn't fully loaded, this method draws nothing.
2293 When given as url string, the image should be loaded by calling Canvas item's \a QtQuick2::Canvas::loadImage() method first.
2294 This image been drawing is subject to the current context clip path, even the given \c image is a {QtQuick2::CanvasImageData} object.
2296 \sa QtQuick2::CanvasImageData
2298 \sa QtQuick2::Canvas::loadImage
2299 \sa QtQuick2::Canvas::isImageLoaded
2300 \sa QtQuick2::Canvas::imageLoaded
2302 \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
2304 static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
2306 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2309 QV8Engine *engine = V8ENGINE();
2310 qreal sx, sy, sw, sh, dx, dy, dw, dh;
2315 //FIXME:This function should be moved to QQuickContext2D::drawImage(...)
2316 if (!r->context->state.invertibleCTM)
2319 QQmlRefPointer<QQuickCanvasPixmap> pixmap;
2321 if (args[0]->IsString()) {
2322 QUrl url(engine->toString(args[0]->ToString()));
2324 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2326 pixmap = r->context->createPixmap(url);
2327 } else if (args[0]->IsObject()) {
2328 QQuickImage *imageItem = qobject_cast<QQuickImage*>(engine->toQObject(args[0]->ToObject()));
2329 QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(engine->toQObject(args[0]->ToObject()));
2331 QV8Context2DPixelArrayResource *pix = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->GetInternalField(0)->ToObject());
2332 if (pix && !pix->image.isNull()) {
2333 pixmap.take(new QQuickCanvasPixmap(pix->image, r->context->canvas()->window()));
2334 } else if (imageItem) {
2335 pixmap.take(r->context->createPixmap(imageItem->source()));
2336 } else if (canvas) {
2337 QImage img = canvas->toImage();
2339 pixmap.take(new QQuickCanvasPixmap(img, canvas->window()));
2341 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2344 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
2347 if (pixmap.isNull() || !pixmap->isValid())
2350 if (args.Length() == 3) {
2351 dx = args[1]->NumberValue();
2352 dy = args[2]->NumberValue();
2355 sw = pixmap->width();
2356 sh = pixmap->height();
2359 } else if (args.Length() == 5) {
2362 sw = pixmap->width();
2363 sh = pixmap->height();
2364 dx = args[1]->NumberValue();
2365 dy = args[2]->NumberValue();
2366 dw = args[3]->NumberValue();
2367 dh = args[4]->NumberValue();
2368 } else if (args.Length() == 9) {
2369 sx = args[1]->NumberValue();
2370 sy = args[2]->NumberValue();
2371 sw = args[3]->NumberValue();
2372 sh = args[4]->NumberValue();
2373 dx = args[5]->NumberValue();
2374 dy = args[6]->NumberValue();
2375 dw = args[7]->NumberValue();
2376 dh = args[8]->NumberValue();
2395 || sx + sw > pixmap->width()
2396 || sy + sh > pixmap->height()
2397 || sx + sw < 0 || sy + sh < 0) {
2398 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
2401 r->context->buffer()->drawPixmap(pixmap, QRectF(sx, sy, sw, sh), QRectF(dx, dy, dw, dh));
2406 // pixel manipulation
2408 \qmltype CanvasImageData
2409 \inqmlmodule QtQuick 2
2410 \ingroup qtquick-canvas
2411 \brief Contains image pixel data in RGBA order
2413 The \a QtQuick2::CanvasImageData object holds the image pixel data.
2415 The \a QtQuick2::CanvasImageData object has the actual dimensions of the data stored in
2416 this object and holds the one-dimensional array containing the data in RGBA order,
2417 as integers in the range 0 to 255.
2419 \sa QtQuick2::CanvasImageData::width
2420 \sa QtQuick2::CanvasImageData::height
2421 \sa QtQuick2::CanvasImageData::data
2422 \sa QtQuick2::Context2D::createImageData
2423 \sa QtQuick2::Context2D::getImageData
2424 \sa QtQuick2::Context2D::putImageData
2427 \qmlproperty QtQuick2::CanvasImageData::width
2428 Holds the actual width dimension of the data in the ImageData object, in device pixels.
2430 v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
2432 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2434 return v8::Integer::New(0);
2435 return v8::Integer::New(r->image.width());
2439 \qmlproperty QtQuick2::CanvasImageData::height
2440 Holds the actual height dimension of the data in the ImageData object, in device pixels.
2442 v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
2444 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2446 return v8::Integer::New(0);
2448 return v8::Integer::New(r->image.height());
2452 \qmlproperty QtQuick2::CanvasImageData::data
2453 Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
2455 v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
2457 return args.This()->GetInternalField(0);
2461 \qmltype CanvasPixelArray
2462 \inqmlmodule QtQuick 2
2463 \ingroup qtquick-canvas
2464 \brief Provides ordered and indexed access to the components of each pixel in image data
2466 The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
2467 The CanvasPixelArray can be accessed as normal Javascript array.
2468 \sa QtQuick2::CanvasImageData
2469 \sa {http://www.w3.org/TR/2dcontext/#canvaspixelarray}{W3C 2d context standard for PixelArray}
2473 \qmlproperty QtQuick2::CanvasPixelArray::length
2474 The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
2475 The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
2476 This property is read only.
2478 v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
2480 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2481 if (!r || r->image.isNull()) return v8::Undefined();
2483 return v8::Integer::New(r->image.width() * r->image.height() * 4);
2486 v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
2488 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2490 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
2491 const quint32 w = r->image.width();
2492 const quint32 row = (index / 4) / w;
2493 const quint32 col = (index / 4) % w;
2494 const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
2496 switch (index % 4) {
2498 return v8::Integer::New(qRed(*pixel));
2500 return v8::Integer::New(qGreen(*pixel));
2502 return v8::Integer::New(qBlue(*pixel));
2504 return v8::Integer::New(qAlpha(*pixel));
2507 return v8::Undefined();
2510 v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
2512 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
2514 const int v = value->Uint32Value();
2515 if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4) && v > 0 && v <= 255) {
2516 const quint32 w = r->image.width();
2517 const quint32 row = (index / 4) / w;
2518 const quint32 col = (index / 4) % w;
2520 QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
2522 switch (index % 4) {
2524 *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
2527 *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
2530 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
2533 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
2537 return v8::Undefined();
2540 \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
2541 Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
2544 \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
2545 Creates a CanvasImageData object with the same dimensions as the argument.
2548 \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
2549 Creates a CanvasImageData object with the given image loaded from \a imageUrl.
2550 Note:The \a imageUrl must be already loaded before this function call, if not, an empty
2551 CanvasImageData obect will be returned.
2553 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
2555 static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
2557 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2560 QV8Engine *engine = V8ENGINE();
2562 if (args.Length() == 1) {
2563 if (args[0]->IsObject()) {
2564 v8::Local<v8::Object> imgData = args[0]->ToObject();
2565 QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
2567 qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
2568 qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
2569 return qt_create_image_data(w, h, engine, QImage());
2571 } else if (args[0]->IsString()) {
2572 QImage image = r->context->createPixmap(QUrl(engine->toString(args[0]->ToString())))->image();
2573 return qt_create_image_data(image.width(), image.height(), engine, image);
2575 } else if (args.Length() == 2) {
2576 qreal w = args[0]->NumberValue();
2577 qreal h = args[1]->NumberValue();
2579 if (!qIsFinite(w) || !qIsFinite(h))
2580 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
2583 return qt_create_image_data(w, h, engine, QImage());
2585 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createImageData(): invalid arguments");
2587 return v8::Undefined();
2591 \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
2592 Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
2594 static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
2596 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2599 QV8Engine *engine = V8ENGINE();
2600 if (args.Length() == 4) {
2601 qreal x = args[0]->NumberValue();
2602 qreal y = args[1]->NumberValue();
2603 qreal w = args[2]->NumberValue();
2604 qreal h = args[3]->NumberValue();
2605 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(w))
2606 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
2608 if (w <= 0 || h <= 0)
2609 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
2611 QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
2612 v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
2620 \qmlmethod object QtQuick2::Context2D::putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
2621 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.
2623 static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
2625 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2627 if (args.Length() != 3 && args.Length() != 7)
2628 return v8::Undefined();
2630 if (args[0]->IsNull() || !args[0]->IsObject()) {
2631 V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
2633 qreal dx = args[1]->NumberValue();
2634 qreal dy = args[2]->NumberValue();
2635 qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
2637 if (!qIsFinite(dx) || !qIsFinite(dy))
2638 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2640 v8::Local<v8::Object> imageData = args[0]->ToObject();
2641 QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
2643 w = imageData->Get(v8::String::New("width"))->NumberValue();
2644 h = imageData->Get(v8::String::New("height"))->NumberValue();
2646 if (args.Length() == 7) {
2647 dirtyX = args[3]->NumberValue();
2648 dirtyY = args[4]->NumberValue();
2649 dirtyWidth = args[5]->NumberValue();
2650 dirtyHeight = args[6]->NumberValue();
2652 if (!qIsFinite(dirtyX) || !qIsFinite(dirtyY) || !qIsFinite(dirtyWidth) || !qIsFinite(dirtyHeight))
2653 V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
2656 if (dirtyWidth < 0) {
2657 dirtyX = dirtyX+dirtyWidth;
2658 dirtyWidth = -dirtyWidth;
2661 if (dirtyHeight < 0) {
2662 dirtyY = dirtyY+dirtyHeight;
2663 dirtyHeight = -dirtyHeight;
2667 dirtyWidth = dirtyWidth+dirtyX;
2672 dirtyHeight = dirtyHeight+dirtyY;
2676 if (dirtyX+dirtyWidth > w) {
2677 dirtyWidth = w - dirtyX;
2680 if (dirtyY+dirtyHeight > h) {
2681 dirtyHeight = h - dirtyY;
2684 if (dirtyWidth <=0 || dirtyHeight <= 0)
2693 QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2694 r->context->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight));
2700 \qmltype CanvasGradient
2701 \inqmlmodule QtQuick 2
2703 \ingroup qtquick-canvas
2704 \brief Provides an opaque CanvasGradient interface
2708 \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
2709 Adds a color stop with the given color to the gradient at the given offset.
2710 0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
2714 var gradient = ctx.createLinearGradient(0, 0, 100, 100);
2715 gradient.addColorStop(0.3, Qt.rgba(1, 0, 0, 1));
2716 gradient.addColorStop(0.7, 'rgba(0, 255, 255, 1');
2719 static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
2721 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
2723 V8THROW_ERROR("Not a CanvasGradient object");
2725 QV8Engine *engine = V8ENGINE();
2727 if (args.Length() == 2) {
2729 if (!style->brush.gradient())
2730 V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
2731 QGradient gradient = *(style->brush.gradient());
2732 qreal pos = args[0]->NumberValue();
2735 if (args[1]->IsObject()) {
2736 color = engine->toVariant(args[1], qMetaTypeId<QColor>()).value<QColor>();
2738 color = qt_color_from_string(args[1]);
2740 if (pos < 0.0 || pos > 1.0 || !qIsFinite(pos)) {
2741 V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
2744 if (color.isValid()) {
2745 gradient.setColorAt(pos, color);
2747 V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string");
2749 style->brush = gradient;
2755 void QQuickContext2D::scale(qreal x, qreal y)
2757 if (!state.invertibleCTM)
2760 if (!qIsFinite(x) || !qIsFinite(y))
2763 QTransform newTransform = state.matrix;
2764 newTransform.scale(x, y);
2766 if (!newTransform.isInvertible()) {
2767 state.invertibleCTM = false;
2771 state.matrix = newTransform;
2772 buffer()->updateMatrix(state.matrix);
2773 m_path = QTransform().scale(1.0 / x, 1.0 / y).map(m_path);
2776 void QQuickContext2D::rotate(qreal angle)
2778 if (!state.invertibleCTM)
2781 if (!qIsFinite(angle))
2784 QTransform newTransform =state.matrix;
2785 newTransform.rotate(DEGREES(angle));
2787 if (!newTransform.isInvertible()) {
2788 state.invertibleCTM = false;
2792 state.matrix = newTransform;
2793 buffer()->updateMatrix(state.matrix);
2794 m_path = QTransform().rotate(-DEGREES(angle)).map(m_path);
2797 void QQuickContext2D::shear(qreal h, qreal v)
2799 if (!state.invertibleCTM)
2802 if (!qIsFinite(h) || !qIsFinite(v))
2805 QTransform newTransform = state.matrix;
2806 newTransform.shear(h, v);
2808 if (!newTransform.isInvertible()) {
2809 state.invertibleCTM = false;
2813 state.matrix = newTransform;
2814 buffer()->updateMatrix(state.matrix);
2815 m_path = QTransform().shear(-h, -v).map(m_path);
2818 void QQuickContext2D::translate(qreal x, qreal y)
2820 if (!state.invertibleCTM)
2823 if (!qIsFinite(x) || !qIsFinite(y))
2826 QTransform newTransform = state.matrix;
2827 newTransform.translate(x, y);
2829 if (!newTransform.isInvertible()) {
2830 state.invertibleCTM = false;
2834 state.matrix = newTransform;
2835 buffer()->updateMatrix(state.matrix);
2836 m_path = QTransform().translate(-x, -y).map(m_path);
2839 void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
2841 if (!state.invertibleCTM)
2844 if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
2847 QTransform transform(a, b, c, d, e, f);
2848 QTransform newTransform = state.matrix * transform;
2850 if (!newTransform.isInvertible()) {
2851 state.invertibleCTM = false;
2854 state.matrix = newTransform;
2855 buffer()->updateMatrix(state.matrix);
2856 m_path = transform.inverted().map(m_path);
2859 void QQuickContext2D::setTransform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
2861 if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
2864 QTransform ctm = state.matrix;
2865 if (!ctm.isInvertible())
2868 state.matrix = ctm.inverted() * state.matrix;
2869 m_path = ctm.map(m_path);
2870 state.invertibleCTM = true;
2871 transform(a, b, c, d, e, f);
2874 void QQuickContext2D::fill()
2876 if (!state.invertibleCTM)
2879 if (!m_path.elementCount())
2882 m_path.setFillRule(state.fillRule);
2883 buffer()->fill(m_path);
2886 void QQuickContext2D::clip()
2888 if (!state.invertibleCTM)
2891 QPainterPath clipPath = m_path;
2892 clipPath.closeSubpath();
2893 if (!state.clipPath.isEmpty())
2894 state.clipPath = clipPath.intersected(state.clipPath);
2896 state.clipPath = clipPath;
2897 buffer()->clip(state.clipPath);
2900 void QQuickContext2D::stroke()
2902 if (!state.invertibleCTM)
2905 if (!m_path.elementCount())
2908 buffer()->stroke(m_path);
2911 void QQuickContext2D::fillRect(qreal x, qreal y, qreal w, qreal h)
2913 if (!state.invertibleCTM)
2916 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2919 buffer()->fillRect(QRectF(x, y, w, h));
2922 void QQuickContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
2924 if (!state.invertibleCTM)
2927 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2930 buffer()->strokeRect(QRectF(x, y, w, h));
2933 void QQuickContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
2935 if (!state.invertibleCTM)
2938 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
2941 buffer()->clearRect(QRectF(x, y, w, h));
2944 void QQuickContext2D::drawText(const QString& text, qreal x, qreal y, bool fill)
2946 if (!state.invertibleCTM)
2949 if (!qIsFinite(x) || !qIsFinite(y))
2952 QPainterPath textPath = createTextGlyphs(x, y, text);
2954 buffer()->fill(textPath);
2956 buffer()->stroke(textPath);
2960 void QQuickContext2D::beginPath()
2962 if (!m_path.elementCount())
2964 m_path = QPainterPath();
2967 void QQuickContext2D::closePath()
2969 if (!m_path.elementCount())
2972 QRectF boundRect = m_path.boundingRect();
2973 if (boundRect.width() || boundRect.height())
2974 m_path.closeSubpath();
2975 //FIXME:QPainterPath set the current point to (0,0) after close subpath
2976 //should be the first point of the previous subpath
2979 void QQuickContext2D::moveTo( qreal x, qreal y)
2981 if (!state.invertibleCTM)
2984 //FIXME: moveTo should not close the previous subpath
2985 m_path.moveTo(QPointF(x, y));
2988 void QQuickContext2D::lineTo( qreal x, qreal y)
2990 if (!state.invertibleCTM)
2995 if (!m_path.elementCount())
2997 else if (m_path.currentPosition() != pt)
3001 void QQuickContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
3004 if (!state.invertibleCTM)
3007 if (!m_path.elementCount())
3008 m_path.moveTo(QPointF(cpx, cpy));
3011 if (m_path.currentPosition() != pt)
3012 m_path.quadTo(QPointF(cpx, cpy), pt);
3015 void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
3016 qreal cp2x, qreal cp2y,
3019 if (!state.invertibleCTM)
3022 if (!m_path.elementCount())
3023 m_path.moveTo(QPointF(cp1x, cp1y));
3026 if (m_path.currentPosition() != pt)
3027 m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y), pt);
3030 void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
3032 QPointF p0(m_path.currentPosition());
3034 QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
3035 QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
3036 float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
3037 float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
3039 double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
3041 // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
3042 // We could have used areCollinear() here, but since we're reusing
3043 // the variables computed above later on we keep this logic.
3044 if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
3049 float tangent = radius / tan(acos(cos_phi) / 2);
3050 float factor_p1p0 = tangent / p1p0_length;
3051 QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
3053 QPointF orth_p1p0(p1p0.y(), -p1p0.x());
3054 float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
3055 float factor_ra = radius / orth_p1p0_length;
3057 // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
3058 double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
3059 if (cos_alpha < 0.f)
3060 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3062 QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
3064 // calculate angles for addArc
3065 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
3066 float sa = acos(orth_p1p0.x() / orth_p1p0_length);
3067 if (orth_p1p0.y() < 0.f)
3070 // anticlockwise logic
3071 bool anticlockwise = false;
3073 float factor_p1p2 = tangent / p1p2_length;
3074 QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
3075 QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
3076 float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
3077 float ea = acos(orth_p1p2.x() / orth_p1p2_length);
3078 if (orth_p1p2.y() < 0)
3080 if ((sa > ea) && ((sa - ea) < Q_PI))
3081 anticlockwise = true;
3082 if ((sa < ea) && ((ea - sa) > Q_PI))
3083 anticlockwise = true;
3085 arc(p.x(), p.y(), radius, sa, ea, anticlockwise);
3088 void QQuickContext2D::arcTo(qreal x1, qreal y1,
3092 if (!state.invertibleCTM)
3095 if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2) || !qIsFinite(radius))
3099 QPointF end(x2, y2);
3101 if (!m_path.elementCount())
3103 else if (st == m_path.currentPosition() || st == end || !radius)
3106 addArcTo(st, end, radius);
3109 void QQuickContext2D::rect(qreal x, qreal y, qreal w, qreal h)
3111 if (!state.invertibleCTM)
3113 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
3117 m_path.moveTo(x, y);
3120 m_path.addRect(x, y, w, h);
3123 void QQuickContext2D::roundedRect(qreal x, qreal y,
3127 if (!state.invertibleCTM)
3130 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h) || !qIsFinite(xr) || !qIsFinite(yr))
3134 m_path.moveTo(x, y);
3137 m_path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
3140 void QQuickContext2D::ellipse(qreal x, qreal y,
3143 if (!state.invertibleCTM)
3146 if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
3150 m_path.moveTo(x, y);
3154 m_path.addEllipse(x, y, w, h);
3157 void QQuickContext2D::text(const QString& str, qreal x, qreal y)
3159 if (!state.invertibleCTM)
3163 path.addText(x, y, state.font, str);
3164 m_path.addPath(path);
3167 void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear, bool antiClockWise)
3169 if (!state.invertibleCTM)
3172 if (!qIsFinite(xc) || !qIsFinite(yc) || !qIsFinite(sar) || !qIsFinite(ear) || !qIsFinite(radius))
3181 // In Qt we don't switch the coordinate system for degrees
3182 // and still use the 0,0 as bottom left for degrees so we need
3186 antiClockWise = !antiClockWise;
3189 float sa = DEGREES(sar);
3190 float ea = DEGREES(ear);
3194 double xs = xc - radius;
3195 double ys = yc - radius;
3196 double width = radius*2;
3197 double height = radius*2;
3198 if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
3199 // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
3200 // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
3201 // circumference of this circle.
3204 if (!antiClockWise && (ea < sa)) {
3206 } else if (antiClockWise && (sa < ea)) {
3209 //### this is also due to switched coordinate system
3210 // we would end up with a 0 span instead of 360
3211 if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
3212 qFuzzyCompare(qAbs(span), 360))) {
3217 // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
3218 if (!m_path.elementCount())
3219 m_path.arcMoveTo(xs, ys, width, height, sa);
3221 m_path.lineTo(xc, yc);
3225 m_path.arcTo(xs, ys, width, height, sa, span);
3228 int baseLineOffset(QQuickContext2D::TextBaseLineType value, const QFontMetrics &metrics)
3232 case QQuickContext2D::Top:
3234 case QQuickContext2D::Alphabetic:
3235 case QQuickContext2D::Middle:
3236 case QQuickContext2D::Hanging:
3237 offset = metrics.ascent();
3239 case QQuickContext2D::Bottom:
3240 offset = metrics.height();
3246 static int textAlignOffset(QQuickContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
3249 if (value == QQuickContext2D::Start)
3250 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Left : QQuickContext2D::Right;
3251 else if (value == QQuickContext2D::End)
3252 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QQuickContext2D::Right: QQuickContext2D::Left;
3254 case QQuickContext2D::Center:
3255 offset = metrics.width(text)/2;
3257 case QQuickContext2D::Right:
3258 offset = metrics.width(text);
3259 case QQuickContext2D::Left:
3266 void QQuickContext2D::setGrabbedImage(const QImage& grab)
3268 m_grabbedImage = grab;
3272 QQmlRefPointer<QQuickCanvasPixmap> QQuickContext2D::createPixmap(const QUrl& url)
3274 return m_canvas->loadedPixmap(url);
3277 QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
3279 const QFontMetrics metrics(state.font);
3280 int yoffset = baseLineOffset(static_cast<QQuickContext2D::TextBaseLineType>(state.textBaseline), metrics);
3281 int xoffset = textAlignOffset(static_cast<QQuickContext2D::TextAlignType>(state.textAlign), metrics, text);
3283 QPainterPath textPath;
3285 textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
3286 textPath = state.matrix.map(textPath);
3291 static inline bool areCollinear(const QPointF& a, const QPointF& b, const QPointF& c)
3293 // Solved from comparing the slopes of a to b and b to c: (ay-by)/(ax-bx) == (cy-by)/(cx-bx)
3294 return qFuzzyCompare((c.y() - b.y()) * (a.x() - b.x()), (a.y() - b.y()) * (c.x() - b.x()));
3297 static inline bool withinRange(qreal p, qreal a, qreal b)
3299 return (p >= a && p <= b) || (p >= b && p <= a);
3302 bool QQuickContext2D::isPointInPath(qreal x, qreal y) const
3304 if (!state.invertibleCTM)
3307 if (!m_path.elementCount())
3310 if (!qIsFinite(x) || !qIsFinite(y))
3313 QPointF point(x, y);
3314 QTransform ctm = state.matrix;
3315 QPointF p = ctm.inverted().map(point);
3316 if (!qIsFinite(p.x()) || !qIsFinite(p.y()))
3319 const_cast<QQuickContext2D *>(this)->m_path.setFillRule(state.fillRule);
3321 bool contains = m_path.contains(p);
3324 // check whether the point is on the border
3325 QPolygonF border = m_path.toFillPolygon();
3327 QPointF p1 = border.at(0);
3330 for (int i = 1; i < border.size(); ++i) {
3332 if (areCollinear(p, p1, p2)
3333 // Once we know that the points are collinear we
3334 // only need to check one of the coordinates
3335 && (qAbs(p2.x() - p1.x()) > qAbs(p2.y() - p1.y()) ?
3336 withinRange(p.x(), p1.x(), p2.x()) :
3337 withinRange(p.y(), p1.y(), p2.y()))) {
3346 QQuickContext2D::QQuickContext2D(QObject *parent)
3347 : QQuickCanvasContext(parent)
3348 , m_buffer(new QQuickContext2DCommandBuffer)
3350 , m_windowManager(0)
3358 QQuickContext2D::~QQuickContext2D()
3361 m_texture->deleteLater();
3364 v8::Handle<v8::Object> QQuickContext2D::v8value() const
3369 QStringList QQuickContext2D::contextNames() const
3371 return QStringList() << QLatin1String("2d");
3374 void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args)
3378 m_canvas = canvasItem;
3379 m_renderTarget = canvasItem->renderTarget();
3381 QQuickWindow *window = canvasItem->window();
3382 m_windowManager = QQuickWindowPrivate::get(window)->windowManager;
3383 m_renderStrategy = canvasItem->renderStrategy();
3385 switch (m_renderTarget) {
3386 case QQuickCanvasItem::Image:
3387 m_texture = new QQuickContext2DImageTexture;
3389 case QQuickCanvasItem::FramebufferObject:
3390 m_texture = new QQuickContext2DFBOTexture;
3394 m_texture->setItem(canvasItem);
3395 m_texture->setCanvasWindow(canvasItem->canvasWindow().toRect());
3396 m_texture->setTileSize(canvasItem->tileSize());
3397 m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
3398 m_texture->setSmooth(canvasItem->smooth());
3400 m_thread = QThread::currentThread();
3402 QThread *renderThread = m_thread;
3403 QThread *sceneGraphThread = window->openglContext() ? window->openglContext()->thread() : 0;
3405 if (m_renderStrategy == QQuickCanvasItem::Threaded)
3406 renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem));
3407 else if (m_renderStrategy == QQuickCanvasItem::Cooperative)
3408 renderThread = sceneGraphThread;
3410 if (renderThread && renderThread != QThread::currentThread())
3411 m_texture->moveToThread(renderThread);
3413 if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) {
3414 QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->glContext();
3416 m_glContext = new QOpenGLContext;
3417 m_glContext->setFormat(cc->format());
3418 m_glContext->setShareContext(cc);
3419 if (renderThread != QThread::currentThread())
3420 m_glContext->moveToThread(renderThread);
3423 connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
3428 void QQuickContext2D::prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth)
3430 QMetaObject::invokeMethod(m_texture,
3433 Q_ARG(QSize, canvasSize),
3434 Q_ARG(QSize, tileSize),
3435 Q_ARG(QRect, canvasWindow),
3436 Q_ARG(QRect, dirtyRect),
3437 Q_ARG(bool, smooth));
3440 void QQuickContext2D::flush()
3443 QMetaObject::invokeMethod(m_texture,
3446 Q_ARG(QQuickContext2DCommandBuffer*, m_buffer));
3447 m_buffer = new QQuickContext2DCommandBuffer();
3450 QSGDynamicTexture *QQuickContext2D::texture() const
3455 QImage QQuickContext2D::toImage(const QRectF& bounds)
3458 if (m_texture->thread() == QThread::currentThread())
3459 m_texture->grabImage(bounds);
3460 else if (m_renderStrategy == QQuickCanvasItem::Cooperative) {
3461 qWarning() << "Pixel read back is not support in Cooperative mode, please try Theaded or Immediate mode";
3464 QMetaObject::invokeMethod(m_texture,
3466 Qt::BlockingQueuedConnection,
3467 Q_ARG(QRectF, bounds));
3469 QImage img = m_grabbedImage;
3470 m_grabbedImage = QImage();
3476 QQuickContext2DEngineData::QQuickContext2DEngineData(QV8Engine *engine)
3478 v8::HandleScope handle_scope;
3479 v8::Context::Scope scope(engine->context());
3481 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
3482 ft->InstanceTemplate()->SetHasExternalResource(true);
3483 ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine));
3484 ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine));
3485 ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine));
3486 ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine));
3487 ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine));
3488 ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine));
3489 ft->PrototypeTemplate()->Set(v8::String::New("resetTransform"), V8FUNCTION(ctx2d_resetTransform, engine));
3490 ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine));
3491 ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine));
3492 ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine));
3493 ft->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, engine));
3494 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine));
3495 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine));
3496 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillRule"), ctx2d_fillRule, ctx2d_fillRule_set, v8::External::Wrap(engine));
3497 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine));
3498 ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
3499 ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
3500 ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
3501 ft->PrototypeTemplate()->Set(v8::String::New("createConicalGradient"), V8FUNCTION(ctx2d_createConicalGradient, engine));
3502 ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
3503 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
3504 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
3505 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine));
3506 ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine));
3507 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine));
3508 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine));
3509 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine));
3510 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine));
3511 ft->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_set, v8::External::Wrap(engine));
3512 ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine));
3513 ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine));
3514 ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine));
3515 ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine));
3516 ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine));
3517 ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine));
3518 ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine));
3519 ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine));
3520 ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine));
3521 ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine));
3522 ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine));
3523 ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine));
3524 ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine));
3525 ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine));
3526 ft->PrototypeTemplate()->Set(v8::String::New("roundedRect"), V8FUNCTION(ctx2d_roundedRect, engine));
3527 ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
3528 ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine));
3529 ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine));
3530 ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine));
3531 ft->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
3532 ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
3533 ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, engine));
3534 ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine));
3535 ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine));
3536 ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine));
3537 ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine));
3538 ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine));
3539 ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine));
3540 ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine));
3541 ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine));
3542 ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine));
3543 ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine));
3545 constructorContext = qPersistentNew(ft->GetFunction());
3547 v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
3548 ftGradient->InstanceTemplate()->SetHasExternalResource(true);
3549 ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
3550 constructorGradient = qPersistentNew(ftGradient->GetFunction());
3552 v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
3553 ftPattern->InstanceTemplate()->SetHasExternalResource(true);
3554 constructorPattern = qPersistentNew(ftPattern->GetFunction());
3556 v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
3557 ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
3558 ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
3559 ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
3560 constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
3562 v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
3563 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
3564 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
3565 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
3566 ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
3567 constructorImageData = qPersistentNew(ftImageData->GetFunction());
3570 QQuickContext2DEngineData::~QQuickContext2DEngineData()
3572 qPersistentDispose(constructorContext);
3573 qPersistentDispose(constructorGradient);
3574 qPersistentDispose(constructorPattern);
3575 qPersistentDispose(constructorImageData);
3576 qPersistentDispose(constructorPixelArray);
3579 void QQuickContext2D::popState()
3581 if (m_stateStack.isEmpty())
3584 QQuickContext2D::State newState = m_stateStack.pop();
3586 if (state.matrix != newState.matrix)
3587 buffer()->updateMatrix(newState.matrix);
3589 if (newState.globalAlpha != state.globalAlpha)
3590 buffer()->setGlobalAlpha(newState.globalAlpha);
3592 if (newState.globalCompositeOperation != state.globalCompositeOperation)
3593 buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
3595 if (newState.fillStyle != state.fillStyle)
3596 buffer()->setFillStyle(newState.fillStyle);
3598 if (newState.strokeStyle != state.strokeStyle)
3599 buffer()->setStrokeStyle(newState.strokeStyle);
3601 if (newState.lineWidth != state.lineWidth)
3602 buffer()->setLineWidth(newState.lineWidth);
3604 if (newState.lineCap != state.lineCap)
3605 buffer()->setLineCap(newState.lineCap);
3607 if (newState.lineJoin != state.lineJoin)
3608 buffer()->setLineJoin(newState.lineJoin);
3610 if (newState.miterLimit != state.miterLimit)
3611 buffer()->setMiterLimit(newState.miterLimit);
3613 if (newState.clipPath != state.clipPath) {
3614 buffer()->clip(newState.clipPath);
3617 if (newState.shadowBlur != state.shadowBlur)
3618 buffer()->setShadowBlur(newState.shadowBlur);
3620 if (newState.shadowColor != state.shadowColor)
3621 buffer()->setShadowColor(newState.shadowColor);
3623 if (newState.shadowOffsetX != state.shadowOffsetX)
3624 buffer()->setShadowOffsetX(newState.shadowOffsetX);
3626 if (newState.shadowOffsetY != state.shadowOffsetY)
3627 buffer()->setShadowOffsetY(newState.shadowOffsetY);
3628 m_path = state.matrix.map(m_path);
3630 m_path = state.matrix.inverted().map(m_path);
3632 void QQuickContext2D::pushState()
3634 m_stateStack.push(state);
3637 void QQuickContext2D::reset()
3639 QQuickContext2D::State newState;
3640 newState.matrix = QTransform();
3642 m_path = QPainterPath();
3644 QPainterPath defaultClipPath;
3646 QRect r(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
3647 r = r.united(m_canvas->canvasWindow().toRect());
3648 defaultClipPath.addRect(r);
3649 newState.clipPath = defaultClipPath;
3650 newState.clipPath.setFillRule(Qt::WindingFill);
3652 newState.strokeStyle = QColor("#000000");
3653 newState.fillStyle = QColor("#000000");
3654 newState.fillPatternRepeatX = false;
3655 newState.fillPatternRepeatY = false;
3656 newState.strokePatternRepeatX = false;
3657 newState.strokePatternRepeatY = false;
3658 newState.invertibleCTM = true;
3659 newState.fillRule = Qt::WindingFill;
3660 newState.globalAlpha = 1.0;
3661 newState.lineWidth = 1;
3662 newState.lineCap = Qt::FlatCap;
3663 newState.lineJoin = Qt::MiterJoin;
3664 newState.miterLimit = 10;
3665 newState.shadowOffsetX = 0;
3666 newState.shadowOffsetY = 0;
3667 newState.shadowBlur = 0;
3668 newState.shadowColor = qRgba(0, 0, 0, 0);
3669 newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
3670 newState.font = QFont(QLatin1String("sans-serif"), 10);
3671 newState.textAlign = QQuickContext2D::Start;
3672 newState.textBaseline = QQuickContext2D::Alphabetic;
3674 m_stateStack.clear();
3675 m_stateStack.push(newState);
3677 m_buffer->clearRect(QRectF(0, 0, m_canvas->width(), m_canvas->height()));
3680 void QQuickContext2D::setV8Engine(QV8Engine *engine)
3682 v8::HandleScope handle_scope;
3683 v8::Context::Scope scope(engine->context());
3685 if (m_v8engine != engine) {
3686 m_v8engine = engine;
3688 qPersistentDispose(m_v8value);
3690 if (m_v8engine == 0)
3693 QQuickContext2DEngineData *ed = engineData(engine);
3694 m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
3695 QV8Context2DResource *r = new QV8Context2DResource(engine);
3697 m_v8value->SetExternalResource(r);
3701 QQuickContext2DCommandBuffer* QQuickContext2D::nextBuffer()
3703 QMutexLocker lock(&m_mutex);
3704 return m_bufferQueue.isEmpty() ? 0 : m_bufferQueue.dequeue();