1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qsgcontext2d_p.h"
43 #include "qsgcontext2dcommandbuffer_p.h"
44 #include "qsgcanvasitem_p.h"
45 #include "qsgitem_p.h"
46 #include "qsgshadereffectsource_p.h"
47 #include <QtGui/qopenglframebufferobject.h>
49 #include <QtCore/qdebug.h>
50 #include "private/qsgcontext_p.h"
51 #include "private/qdeclarativesvgparser_p.h"
52 #include "private/qdeclarativepath_p.h"
54 #include "private/qsgimage_p_p.h"
56 #include <QtGui/qguiapplication.h>
57 #include <qdeclarativeinfo.h>
58 #include <QtCore/qmath.h>
59 #include "qv8engine_p.h"
61 #include "qdeclarativeengine.h"
64 \qmlclass Context2D QSGContext2D
65 \inqmlmodule QtQuick 2
67 \brief The Context2D element allows you to draw 2d graphic shapes on Canvas item.
69 static const double Q_PI = 3.14159265358979323846; // pi
72 static bool parsePathDataFast(const QString &dataStr, QPainterPath &path);
74 #define DEGREES(t) ((t) * 180.0 / Q_PI)
75 #define qClamp(val, min, max) qMin(qMax(val, min), max)
77 #define CHECK_CONTEXT(r) if (!r || !r->context || !r->context->buffer()) \
78 V8THROW_ERROR("Not a Context2D object");
80 #define CHECK_CONTEXT_SETTER(r) if (!r || !r->context || !r->context->buffer()) \
81 V8THROW_ERROR_SETTER("Not a Context2D object");
83 static inline int extractInt(const char **name)
86 bool negative = false;
88 //eat leading whitespace
89 while (isspace(*name[0]))
92 if (*name[0] == '-') {
95 } /*else if (name[0] == '+')
99 while (isdigit(*name[0])) {
100 result = result * 10 + (*name[0] - '0');
106 //handle optional percentage
108 result *= qreal(255)/100; //### floor or round?
110 //eat trailing whitespace
111 while (isspace(*name[0]))
117 static bool qt_get_rgb(const QString &string, QRgb *rgb)
119 const char *name = string.toLatin1().constData();
120 int len = qstrlen(name);
125 bool handleAlpha = false;
133 if (name[3] == 'a') {
137 } else if (name[3] != '(')
146 result = extractInt(&name);
147 if (name[0] == ',') {
154 result = extractInt(&name);
155 if (name[0] == ',') {
161 char nextChar = handleAlpha ? ',' : ')';
164 result = extractInt(&name);
165 if (name[0] == nextChar) {
173 result = extractInt(&name);
174 if (name[0] == ')') {
175 a = result * 255; //map 0-1 to 0-255
184 *rgb = qRgba(qClamp(r,0,255), qClamp(g,0,255), qClamp(b,0,255), qClamp(a,0,255));
188 //### unify with qt_get_rgb?
189 static bool qt_get_hsl(const QString &string, QColor *color)
191 const char *name = string.toLatin1().constData();
192 int len = qstrlen(name);
197 bool handleAlpha = false;
205 if (name[3] == 'a') {
209 } else if (name[3] != '(')
218 result = extractInt(&name);
219 if (name[0] == ',') {
226 result = extractInt(&name);
227 if (name[0] == ',') {
233 char nextChar = handleAlpha ? ',' : ')';
236 result = extractInt(&name);
237 if (name[0] == nextChar) {
245 result = extractInt(&name);
246 if (name[0] == ')') {
247 a = result * 255; //map 0-1 to 0-255
256 *color = QColor::fromHsl(qClamp(h,0,255), qClamp(s,0,255), qClamp(l,0,255), qClamp(a,0,255));
260 //### optimize further
261 QColor qt_color_from_string(const QString &name)
263 if (name.startsWith(QLatin1String("rgb"))) {
265 if (qt_get_rgb(name, &rgb))
267 } else if (name.startsWith(QLatin1String("hsl"))) {
269 if (qt_get_hsl(name, &color))
276 QFont qt_font_from_string(const QString& fontString) {
278 // ### this is simplified and incomplete
279 // ### TODO:get code from Qt webkit
280 QStringList tokens = fontString.split(QLatin1String(" "));
281 foreach (const QString &token, tokens) {
282 if (token == QLatin1String("italic"))
283 font.setItalic(true);
284 else if (token == QLatin1String("bold"))
286 else if (token.endsWith(QLatin1String("px"))) {
287 QString number = token;
288 number.remove(QLatin1String("px"));
289 //font.setPointSizeF(number.trimmed().toFloat());
290 font.setPixelSize(number.trimmed().toInt());
292 font.setFamily(token);
300 class QSGContext2DEngineData : public QV8Engine::Deletable
303 QSGContext2DEngineData(QV8Engine *engine);
304 ~QSGContext2DEngineData();
306 v8::Persistent<v8::Function> constructorContext;
307 v8::Persistent<v8::Function> constructorGradient;
308 v8::Persistent<v8::Function> constructorPattern;
309 v8::Persistent<v8::Function> constructorPixelArray;
310 v8::Persistent<v8::Function> constructorImageData;
312 V8_DEFINE_EXTENSION(QSGContext2DEngineData, engineData);
316 class QV8Context2DResource : public QV8ObjectResource
318 V8_RESOURCE_TYPE(Context2DType)
320 QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
321 QSGContext2D* context;
324 class QV8Context2DStyleResource : public QV8ObjectResource
326 V8_RESOURCE_TYPE(Context2DStyleType)
328 QV8Context2DStyleResource(QV8Engine *e) : QV8ObjectResource(e) {}
332 class QV8Context2DPixelArrayResource : public QV8ObjectResource
334 V8_RESOURCE_TYPE(Context2DPixelArrayType)
336 QV8Context2DPixelArrayResource(QV8Engine *e) : QV8ObjectResource(e) {}
341 QImage qt_image_convolute_filter(const QImage& src, const QVector<qreal>& weights, int radius = 0)
343 int sides = radius ? radius : qRound(qSqrt(weights.size()));
344 int half = qFloor(sides/2);
346 QImage dst = QImage(src.size(), src.format());
348 int h = src.height();
349 for (int y = 0; y < dst.height(); ++y) {
350 QRgb *dr = (QRgb*)dst.scanLine(y);
351 for (int x = 0; x < dst.width(); ++x) {
352 unsigned char* dRgb = ((unsigned char*)&dr[x]);
353 unsigned char red=0, green=0, blue=0, alpha=0;
357 for (int cy=0; cy<sides; cy++) {
358 for (int cx=0; cx<sides; cx++) {
359 int scy = sy + cy - half;
360 int scx = sx + cx - half;
361 if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
362 const QRgb *sr = (const QRgb*)(src.constScanLine(scy));
363 const unsigned char* sRgb = ((const unsigned char*)&sr[scx]);
364 qreal wt = radius ? weights[0] : weights[cy*sides+cx];
366 green += sRgb[1] * wt;
367 blue += sRgb[2] * wt;
368 alpha += sRgb[3] * wt;
381 void qt_image_boxblur(QImage& image, int radius, bool quality)
383 int passes = quality? 3: 1;
384 for (int i=0; i < passes; i++) {
385 image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0/(radius * radius * 1.0), radius);
389 static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
391 if (compositeOperator == QLatin1String("source-over")) {
392 return QPainter::CompositionMode_SourceOver;
393 } else if (compositeOperator == QLatin1String("source-out")) {
394 return QPainter::CompositionMode_SourceOut;
395 } else if (compositeOperator == QLatin1String("source-in")) {
396 return QPainter::CompositionMode_SourceIn;
397 } else if (compositeOperator == QLatin1String("source-atop")) {
398 return QPainter::CompositionMode_SourceAtop;
399 } else if (compositeOperator == QLatin1String("destination-atop")) {
400 return QPainter::CompositionMode_DestinationAtop;
401 } else if (compositeOperator == QLatin1String("destination-in")) {
402 return QPainter::CompositionMode_DestinationIn;
403 } else if (compositeOperator == QLatin1String("destination-out")) {
404 return QPainter::CompositionMode_DestinationOut;
405 } else if (compositeOperator == QLatin1String("destination-over")) {
406 return QPainter::CompositionMode_DestinationOver;
407 } else if (compositeOperator == QLatin1String("lighter")) {
408 return QPainter::CompositionMode_Lighten;
409 } else if (compositeOperator == QLatin1String("copy")) {
410 return QPainter::CompositionMode_Source;
411 } else if (compositeOperator == QLatin1String("xor")) {
412 return QPainter::CompositionMode_Xor;
413 } else if (compositeOperator == QLatin1String("qt-clear")) {
414 return QPainter::CompositionMode_Clear;
415 } else if (compositeOperator == QLatin1String("qt-destination")) {
416 return QPainter::CompositionMode_Destination;
417 } else if (compositeOperator == QLatin1String("qt-multiply")) {
418 return QPainter::CompositionMode_Multiply;
419 } else if (compositeOperator == QLatin1String("qt-screen")) {
420 return QPainter::CompositionMode_Screen;
421 } else if (compositeOperator == QLatin1String("qt-overlay")) {
422 return QPainter::CompositionMode_Overlay;
423 } else if (compositeOperator == QLatin1String("qt-darken")) {
424 return QPainter::CompositionMode_Darken;
425 } else if (compositeOperator == QLatin1String("qt-lighten")) {
426 return QPainter::CompositionMode_Lighten;
427 } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
428 return QPainter::CompositionMode_ColorDodge;
429 } else if (compositeOperator == QLatin1String("qt-color-burn")) {
430 return QPainter::CompositionMode_ColorBurn;
431 } else if (compositeOperator == QLatin1String("qt-hard-light")) {
432 return QPainter::CompositionMode_HardLight;
433 } else if (compositeOperator == QLatin1String("qt-soft-light")) {
434 return QPainter::CompositionMode_SoftLight;
435 } else if (compositeOperator == QLatin1String("qt-difference")) {
436 return QPainter::CompositionMode_Difference;
437 } else if (compositeOperator == QLatin1String("qt-exclusion")) {
438 return QPainter::CompositionMode_Exclusion;
440 return QPainter::CompositionMode_SourceOver;
443 static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
446 case QPainter::CompositionMode_SourceOver:
447 return QLatin1String("source-over");
448 case QPainter::CompositionMode_DestinationOver:
449 return QLatin1String("destination-over");
450 case QPainter::CompositionMode_Clear:
451 return QLatin1String("qt-clear");
452 case QPainter::CompositionMode_Source:
453 return QLatin1String("copy");
454 case QPainter::CompositionMode_Destination:
455 return QLatin1String("qt-destination");
456 case QPainter::CompositionMode_SourceIn:
457 return QLatin1String("source-in");
458 case QPainter::CompositionMode_DestinationIn:
459 return QLatin1String("destination-in");
460 case QPainter::CompositionMode_SourceOut:
461 return QLatin1String("source-out");
462 case QPainter::CompositionMode_DestinationOut:
463 return QLatin1String("destination-out");
464 case QPainter::CompositionMode_SourceAtop:
465 return QLatin1String("source-atop");
466 case QPainter::CompositionMode_DestinationAtop:
467 return QLatin1String("destination-atop");
468 case QPainter::CompositionMode_Xor:
469 return QLatin1String("xor");
470 case QPainter::CompositionMode_Plus:
471 return QLatin1String("plus");
472 case QPainter::CompositionMode_Multiply:
473 return QLatin1String("qt-multiply");
474 case QPainter::CompositionMode_Screen:
475 return QLatin1String("qt-screen");
476 case QPainter::CompositionMode_Overlay:
477 return QLatin1String("qt-overlay");
478 case QPainter::CompositionMode_Darken:
479 return QLatin1String("qt-darken");
480 case QPainter::CompositionMode_Lighten:
481 return QLatin1String("lighter");
482 case QPainter::CompositionMode_ColorDodge:
483 return QLatin1String("qt-color-dodge");
484 case QPainter::CompositionMode_ColorBurn:
485 return QLatin1String("qt-color-burn");
486 case QPainter::CompositionMode_HardLight:
487 return QLatin1String("qt-hard-light");
488 case QPainter::CompositionMode_SoftLight:
489 return QLatin1String("qt-soft-light");
490 case QPainter::CompositionMode_Difference:
491 return QLatin1String("qt-difference");
492 case QPainter::CompositionMode_Exclusion:
493 return QLatin1String("qt-exclusion");
501 static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
503 QSGContext2DEngineData *ed = engineData(engine);
504 v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
505 QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
506 if (image.isNull()) {
507 r->image = QImage(w, h, QImage::Format_ARGB32);
508 r->image.fill(Qt::transparent);
510 Q_ASSERT(image.width() == w && image.height() == h);
513 v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
514 pixelData->SetExternalResource(r);
516 imageData->SetInternalField(0, pixelData);
520 //static script functions
523 \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
524 Holds the canvas item that the context paints on.
526 static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
528 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
532 QV8Engine *engine = V8ENGINE_ACCESSOR();
534 return engine->newQObject(r->context->canvas());
538 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::restore()
539 Pops the top state on the stack, restoring the context to that state.
541 static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
543 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
546 r->context->popState();
551 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::reset()
552 Resets the context state and properties to the default values.
554 static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
556 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
564 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::save()
565 Pushes the current state onto the stack.
567 static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
569 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
572 r->context->pushState();
579 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::rotate(real angle)
580 Changes the transformation matrix to apply a rotation transformation with the given characteristics.
581 Note: The angle is in radians.
583 static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
585 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
589 if (args.Length() == 1) {
590 qreal angle = args[0]->NumberValue();
591 r->context->state.matrix.rotate(DEGREES(angle));
592 r->context->buffer()->updateMatrix(r->context->state.matrix);
599 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::scale(real x, real y)
600 Changes the transformation matrix to apply a scaling transformation with the given characteristics.
602 static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
604 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
608 if (args.Length() == 2) {
610 x = args[0]->NumberValue();
611 y = args[1]->NumberValue();
612 r->context->state.matrix.scale(x, y);
613 r->context->buffer()->updateMatrix(r->context->state.matrix);
620 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
621 Changes the transformation matrix to the matrix given by the arguments as described below.
623 \sa QtQuick2::Context2D::transform()
625 static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
627 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
631 if (args.Length() == 6) {
632 r->context->state.matrix = QTransform(args[0]->NumberValue(),
633 args[1]->NumberValue(),
634 args[2]->NumberValue(),
635 args[3]->NumberValue(),
636 args[4]->NumberValue(),
637 args[5]->NumberValue());
638 r->context->buffer()->updateMatrix(r->context->state.matrix);
645 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
646 Changes the transformation matrix to apply the matrix given by the arguments as described below.
648 \sa QtQuick2::Context2D::setTransform()
650 static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
652 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
656 if (args.Length() == 6) {
657 r->context->state.matrix *= QTransform(args[0]->NumberValue(),
658 args[1]->NumberValue(),
659 args[2]->NumberValue(),
660 args[3]->NumberValue(),
661 args[4]->NumberValue(),
662 args[5]->NumberValue());
663 r->context->buffer()->updateMatrix(r->context->state.matrix);
670 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::translate(real x, real y)
671 Changes the transformation matrix to apply a translation transformation with the given characteristics.
673 static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
675 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
679 if (args.Length() == 2) {
680 r->context->state.matrix.translate(args[0]->NumberValue(),
681 args[1]->NumberValue());
682 r->context->buffer()->updateMatrix(r->context->state.matrix);
690 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::resetTransform()
691 Reset the transformation matrix default value.
693 \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform()
695 static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
697 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
700 r->context->state.matrix = QTransform();
701 r->context->buffer()->updateMatrix(r->context->state.matrix);
708 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::shear(real sh, real sv )
709 Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
711 static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
713 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
716 r->context->state.matrix.shear(args[0]->NumberValue(),
717 args[1]->NumberValue());
718 r->context->buffer()->updateMatrix(r->context->state.matrix);
725 \qmlproperty real QtQuick2::Context2D::globalAlpha
726 Holds the the current alpha value applied to rendering operations.
727 The value must be in the range from 0.0 (fully transparent) to 1.0 (no additional transparency).
729 static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
731 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
734 return v8::Number::New(r->context->state.globalAlpha);
737 static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
739 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
740 CHECK_CONTEXT_SETTER(r)
742 qreal globalAlpha = value->NumberValue();
744 if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
745 r->context->state.globalAlpha = globalAlpha;
746 r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
751 \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
752 Holds the the current the current composition operation, from the list below:
754 \o source-atop - A atop B. Display the source image wherever both images are opaque.
755 Display the destination image wherever the destination image is opaque but the source image is transparent.
756 Display transparency elsewhere.
757 \o source-in - A in B. Display the source image wherever both the source image and destination image are opaque.
758 Display transparency elsewhere.
759 \o source-out - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
760 Display transparency elsewhere.
761 \o source-over - (default) A over B. Display the source image wherever the source image is opaque.
762 Display the destination image elsewhere.
763 \o destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
764 \o destination-in - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
765 \o destination-out - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
766 \o destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
767 \o lighter - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
768 \o copy - A (B is ignored). Display the source image instead of the destination image.
769 \o xor - A xor B. Exclusive OR of the source image and destination image.
772 static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
774 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
778 QV8Engine *engine = V8ENGINE_ACCESSOR();
780 return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
783 static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
785 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
786 CHECK_CONTEXT_SETTER(r)
788 QV8Engine *engine = V8ENGINE_ACCESSOR();
790 QPainter::CompositionMode cm = qt_composite_mode_from_string(engine->toString(value));
791 if (cm != r->context->state.globalCompositeOperation) {
792 r->context->state.globalCompositeOperation = cm;
793 r->context->buffer()->setGlobalCompositeOperation(cm);
799 \qmlproperty variant QtQuick2::Context2D::fillStyle
800 Holds the current style used for filling shapes.
801 The style can be either a string containing a CSS color, or a CanvasGradient or CanvasPattern object. Invalid values are ignored.
802 \sa QtQuick2::Context2D::createLinearGradient
803 \sa QtQuick2::Context2D::createRadialGradient
804 \sa QtQuick2::Context2D::createPattern
805 \sa QtQuick2::Context2D::strokeStyle
807 static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
809 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
812 return r->context->m_fillStyle;
815 static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
817 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
818 CHECK_CONTEXT_SETTER(r)
820 QV8Engine *engine = V8ENGINE_ACCESSOR();
822 r->context->m_fillStyle = value;
823 if (value->IsObject()) {
824 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
825 if (color.isValid()) {
826 r->context->state.fillStyle = color;
827 r->context->buffer()->setFillStyle(color);
829 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
830 if (style && style->brush != r->context->state.fillStyle) {
831 r->context->state.fillStyle = style->brush;
832 r->context->buffer()->setFillStyle(style->brush);
835 } else if (value->IsString()) {
836 QColor color = qt_color_from_string(engine->toString(value));
837 if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
838 r->context->state.fillStyle = QBrush(color);
839 r->context->buffer()->setFillStyle(r->context->state.fillStyle);
844 static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
846 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
848 QV8Engine *engine = V8ENGINE_ACCESSOR();
850 return engine->fromVariant(r->context->state.fillRule);
853 static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
855 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
856 CHECK_CONTEXT_SETTER(r)
858 QV8Engine *engine = V8ENGINE_ACCESSOR();
860 if ((value->IsString() && engine->toString(value) == "WindingFill")
861 ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
862 r->context->state.fillRule = Qt::WindingFill;
863 } else if ((value->IsString() && engine->toString(value) == "OddEvenFill")
864 ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
865 r->context->state.fillRule = Qt::OddEvenFill;
869 r->context->m_path.setFillRule(r->context->state.fillRule);
872 \qmlproperty variant QtQuick2::Context2D::strokeStyle
873 Holds the current color or style to use for the lines around shapes,
874 The style can be either a string containing a CSS color, or a CanvasGradient or CanvasPattern object. Invalid values are ignored.
875 \sa QtQuick2::Context2D::createLinearGradient
876 \sa QtQuick2::Context2D::createRadialGradient
877 \sa QtQuick2::Context2D::createPattern
878 \sa QtQuick2::Context2D::fillStyle
880 v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
882 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
886 return r->context->m_strokeStyle;
889 static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
891 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
892 CHECK_CONTEXT_SETTER(r)
894 QV8Engine *engine = V8ENGINE_ACCESSOR();
896 r->context->m_strokeStyle = value;
897 if (value->IsObject()) {
898 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
899 if (color.isValid()) {
900 r->context->state.fillStyle = color;
901 r->context->buffer()->setStrokeStyle(color);
903 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
904 if (style && style->brush != r->context->state.strokeStyle) {
905 r->context->state.strokeStyle = style->brush;
906 r->context->buffer()->setStrokeStyle(style->brush);
909 } else if (value->IsString()) {
910 QColor color = qt_color_from_string(engine->toString(value));
911 if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
912 r->context->state.strokeStyle = QBrush(color);
913 r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
919 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
920 Returns a CanvasGradient object that represents a linear gradient that paints along the line given by the coordinates
921 represented by the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
922 \sa QtQuick2::Context2D::createRadialGradient
923 \sa QtQuick2::Context2D::createPattern
924 \sa QtQuick2::Context2D::fillStyle
925 \sa QtQuick2::Context2D::strokeStyle
928 static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
930 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
934 QV8Engine *engine = V8ENGINE();
936 if (args.Length() == 4) {
937 //TODO:infinite or NaN, the method must raise a NOT_SUPPORTED_ERR
938 QSGContext2DEngineData *ed = engineData(engine);
939 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
940 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
941 r->brush = QLinearGradient(args[0]->NumberValue(),
942 args[1]->NumberValue(),
943 args[2]->NumberValue(),
944 args[3]->NumberValue());
945 gradient->SetExternalResource(r);
953 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
954 Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
955 origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
957 \sa QtQuick2::Context2D::createLinearGradient
958 \sa QtQuick2::Context2D::createPattern
959 \sa QtQuick2::Context2D::fillStyle
960 \sa QtQuick2::Context2D::strokeStyle
963 static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
965 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
969 QV8Engine *engine = V8ENGINE();
971 if (args.Length() == 6) {
972 QSGContext2DEngineData *ed = engineData(engine);
973 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
974 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
976 qreal x0 = args[0]->NumberValue();
977 qreal y0 = args[1]->NumberValue();
978 qreal r0 = args[2]->NumberValue();
979 qreal x1 = args[3]->NumberValue();
980 qreal y1 = args[4]->NumberValue();
981 qreal r1 = args[5]->NumberValue();
982 //TODO:infinite or NaN, a NOT_SUPPORTED_ERR exception must be raised.
983 //If either of r0 or r1 are negative, an INDEX_SIZE_ERR exception must be raised.
984 r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
985 gradient->SetExternalResource(r);
993 \qmlmethod variant createPattern(Image image, string repetition)
994 Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
996 The \a image parameter must be a valid Image item, if there is no image data, throws an INVALID_STATE_ERR exception.
998 The allowed values for \a repetition are:
1001 \o "repeat" - both directions
1002 \o "repeat-x - horizontal only
1003 \o "repeat-y" - vertical only
1004 \o "no-repeat" - neither
1007 If the repetition argument is empty or null, the value "repeat" is used.
1009 \sa QtQuick2::Context2D::strokeStyle
1010 \sa QtQuick2::Context2D::fillStyle
1012 static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
1014 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1018 QV8Engine *engine = V8ENGINE();
1020 // if (args.Length() == 2) {
1021 // QSGContext2DEngineData *ed = engineData(engine);
1022 // v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
1023 // QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1027 // QSGItem* item = qobject_cast<QSGItem*>(engine->toQObject(args[0]));
1029 // img = qt_item_to_image(item);
1030 // if (img.isNull()) {
1031 // //exception: INVALID_STATE_ERR
1034 // //exception: TYPE_MISMATCH_ERR
1037 // QString repetition = engine->toString(args[1]);
1039 // if (repetition == "repeat" || repetition.isEmpty()) {
1041 // } else if (repetition == "repeat-x") {
1043 // } else if (repetition == "repeat-y") {
1045 // } else if (repetition == "no-repeat") {
1048 // //TODO: exception: SYNTAX_ERR
1051 // pattern->SetExternalResource(r);
1059 \qmlproperty string QtQuick2::Context2D::lineCap
1060 Holds the the current line cap style.
1061 The possible line cap styles are:
1063 \o butt - the end of each line has a flat edge perpendicular to the direction of the line, this is the default line cap value.
1064 \o round - a semi-circle with the diameter equal to the width of the line must then be added on to the end of the line.
1065 \o square - a rectangle with the length of the line width and the width of half the line width, placed flat against the edge perpendicular to the direction of the line.
1067 Other values are ignored.
1069 v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
1071 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1075 QV8Engine *engine = V8ENGINE_ACCESSOR();
1076 switch (r->context->state.lineCap) {
1078 return engine->toString(QLatin1String("round"));
1080 return engine->toString(QLatin1String("butt"));
1082 return engine->toString(QLatin1String("square"));
1086 return engine->toString(QLatin1String("butt"));;
1089 static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1091 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1092 CHECK_CONTEXT_SETTER(r)
1094 QV8Engine *engine = V8ENGINE_ACCESSOR();
1096 QString lineCap = engine->toString(value);
1097 Qt::PenCapStyle cap;
1098 if (lineCap == QLatin1String("round"))
1100 else if (lineCap == QLatin1String("butt"))
1102 else if (lineCap == QLatin1String("square"))
1103 cap = Qt::SquareCap;
1105 if (cap != r->context->state.lineCap) {
1106 r->context->state.lineCap = cap;
1107 r->context->buffer()->setLineCap(cap);
1112 \qmlproperty string QtQuick2::Context2D::lineJoin
1113 Holds the the current line join style. A join exists at any point in a subpath
1114 shared by two consecutive lines. When a subpath is closed, then a join also exists
1115 at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
1117 The possible line join styles are:
1119 \o bevel - this is all that is rendered at joins.
1120 \o round - a filled arc connecting the two aforementioned corners of the join, abutting (and not overlapping) the aforementioned triangle, with the diameter equal to the line width and the origin at the point of the join, must be rendered at joins.
1121 \o miter - a second filled triangle must (if it can given the miter length) be rendered at the join, this is the default line join style.
1123 Other values are ignored.
1125 v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
1127 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1131 QV8Engine *engine = V8ENGINE_ACCESSOR();
1132 switch (r->context->state.lineJoin) {
1134 return engine->toString(QLatin1String("round"));
1136 return engine->toString(QLatin1String("bevel"));
1138 return engine->toString(QLatin1String("miter"));
1142 return engine->toString(QLatin1String("miter"));
1145 static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1147 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1148 CHECK_CONTEXT_SETTER(r)
1150 QV8Engine *engine = V8ENGINE_ACCESSOR();
1152 QString lineJoin = engine->toString(value);
1153 Qt::PenJoinStyle join;
1154 if (lineJoin == QLatin1String("round"))
1155 join = Qt::RoundJoin;
1156 else if (lineJoin == QLatin1String("bevel"))
1157 join = Qt::BevelJoin;
1158 else if (lineJoin == QLatin1String("miter"))
1159 join = Qt::MiterJoin;
1161 if (join != r->context->state.lineJoin) {
1162 r->context->state.lineJoin = join;
1163 r->context->buffer()->setLineJoin(join);
1168 \qmlproperty real QtQuick2::Context2D::lineWidth
1169 Holds the the current line width. Values that are not finite values greater than zero are ignored.
1171 v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
1173 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1177 return v8::Number::New(r->context->state.lineWidth);
1180 static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1182 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1183 CHECK_CONTEXT_SETTER(r)
1185 qreal w = value->NumberValue();
1187 if (w > 0 && w != r->context->state.lineWidth) {
1188 r->context->state.lineWidth = w;
1189 r->context->buffer()->setLineWidth(w);
1194 \qmlproperty real QtQuick2::Context2D::miterLimit
1195 Holds the current miter limit ratio.
1196 The default miter limit value is 10.0.
1198 v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
1200 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1204 return v8::Number::New(r->context->state.miterLimit);
1207 static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1209 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1210 CHECK_CONTEXT_SETTER(r)
1212 qreal ml = value->NumberValue();
1214 if (ml > 0 && ml != r->context->state.miterLimit) {
1215 r->context->state.miterLimit = ml;
1216 r->context->buffer()->setMiterLimit(ml);
1222 \qmlproperty real QtQuick2::Context2D::shadowBlur
1223 Holds the current level of blur applied to shadows
1225 v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
1227 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1231 return v8::Number::New(r->context->state.shadowBlur);
1234 static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1236 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1237 CHECK_CONTEXT_SETTER(r)
1238 qreal blur = value->NumberValue();
1240 if (blur > 0 && blur != r->context->state.shadowBlur) {
1241 r->context->state.shadowBlur = blur;
1242 r->context->buffer()->setShadowBlur(blur);
1247 \qmlproperty string QtQuick2::Context2D::shadowColor
1248 Holds the current shadow color.
1250 v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
1252 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1256 QV8Engine *engine = V8ENGINE_ACCESSOR();
1258 return engine->toString(r->context->state.shadowColor.name());
1261 static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1263 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1264 CHECK_CONTEXT_SETTER(r)
1266 QV8Engine *engine = V8ENGINE_ACCESSOR();
1268 QColor color = qt_color_from_string(engine->toString(value));
1270 if (color.isValid() && color != r->context->state.shadowColor) {
1271 r->context->state.shadowColor = color;
1272 r->context->buffer()->setShadowColor(color);
1278 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
1279 Holds the current shadow offset in the positive horizontal distance.
1281 \sa QtQuick2::Context2D::shadowOffsetY
1283 v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
1285 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1289 return v8::Number::New(r->context->state.shadowOffsetX);
1292 static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1294 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1295 CHECK_CONTEXT_SETTER(r)
1297 //TODO: check value:infinite or NaN
1298 qreal offsetX = value->NumberValue();
1299 if (offsetX != r->context->state.shadowOffsetX) {
1300 r->context->state.shadowOffsetX = offsetX;
1301 r->context->buffer()->setShadowOffsetX(offsetX);
1305 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
1306 Holds the current shadow offset in the positive vertical distance.
1308 \sa QtQuick2::Context2D::shadowOffsetX
1310 v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
1312 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1316 return v8::Number::New(r->context->state.shadowOffsetY);
1319 static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1321 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1322 CHECK_CONTEXT_SETTER(r)
1323 //TODO: check value:infinite or NaN
1324 qreal offsetY = value->NumberValue();
1325 if (offsetY != r->context->state.shadowOffsetY) {
1326 r->context->state.shadowOffsetY = offsetY;
1327 r->context->buffer()->setShadowOffsetY(offsetY);
1331 v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
1333 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1335 return r->context->m_v8path;
1338 static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1340 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1341 CHECK_CONTEXT_SETTER(r)
1342 QV8Engine *engine = V8ENGINE_ACCESSOR();
1344 r->context->beginPath();
1345 if (value->IsObject()) {
1346 QDeclarativePath* path = qobject_cast<QDeclarativePath*>(engine->toQObject(value));
1348 r->context->m_path = path->path();
1350 QString path = engine->toString(value->ToString());
1351 QDeclarativeSvgParser::parsePathDataFast(path, r->context->m_path);
1353 r->context->m_v8path = value;
1358 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
1359 Clears all pixels on the canvas in the given rectangle to transparent black.
1361 static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
1363 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1367 if (args.Length() == 4) {
1368 r->context->buffer()->clearRect(args[0]->NumberValue(),
1369 args[1]->NumberValue(),
1370 args[2]->NumberValue(),
1371 args[3]->NumberValue());
1377 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1378 Paint the specified rectangular area using the fillStyle.
1380 \sa QtQuick2::Context2D::fillStyle
1382 static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
1384 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1388 if (args.Length() == 4) {
1389 r->context->buffer()->fillRect(args[0]->NumberValue(),
1390 args[1]->NumberValue(),
1391 args[2]->NumberValue(),
1392 args[3]->NumberValue());
1399 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1400 Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
1401 and (if appropriate) miterLimit attributes.
1403 \sa QtQuick2::Context2D::strokeStyle
1404 \sa QtQuick2::Context2D::lineWidth
1405 \sa QtQuick2::Context2D::lineJoin
1406 \sa QtQuick2::Context2D::miterLimit
1408 static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
1410 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1414 if (args.Length() == 4) {
1415 r->context->buffer()->strokeRect(args[0]->NumberValue(),
1416 args[1]->NumberValue(),
1417 args[2]->NumberValue(),
1418 args[3]->NumberValue());
1424 // Complex shapes (paths) API
1426 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
1427 Adds points to the subpath such that the arc described by the circumference of
1428 the circle described by the arguments.
1430 See http://www.w3.org/TR/2dcontext/#dom-context-2d-arc for details.
1432 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
1434 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1437 if (args.Length() >= 5) {
1438 bool antiClockwise = false;
1440 if (args.Length() == 6)
1441 antiClockwise = args[5]->BooleanValue();
1443 qreal radius = args[2]->NumberValue();
1444 //Throws an INDEX_SIZE_ERR exception if the given radius is negative.
1445 r->context->arc(args[0]->NumberValue(),
1446 args[1]->NumberValue(),
1448 args[3]->NumberValue(),
1449 args[4]->NumberValue(),
1457 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
1459 Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
1460 See http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto for details.
1462 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
1464 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1468 if (args.Length() == 5) {
1469 r->context->arcTo(args[0]->NumberValue(),
1470 args[1]->NumberValue(),
1471 args[2]->NumberValue(),
1472 args[3]->NumberValue(),
1473 args[4]->NumberValue());
1480 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::beginPath()
1482 Resets the current path.
1484 static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
1486 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1490 r->context->beginPath();
1496 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
1498 Adds the given point to the current subpath, connected to the previous one by a cubic Bézier curve with the given control points.
1500 See http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto for details.
1502 static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
1504 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1508 if (args.Length() == 6) {
1509 r->context->bezierCurveTo(args[0]->NumberValue(),
1510 args[1]->NumberValue(),
1511 args[2]->NumberValue(),
1512 args[3]->NumberValue(),
1513 args[4]->NumberValue(),
1514 args[5]->NumberValue());
1521 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::clip()
1523 constrains the clipping region to the given path.
1525 See http://www.w3.org/TR/2dcontext/#dom-context-2d-clip for details.
1527 static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
1529 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1532 r->context->state.clipPath = r->context->m_path;
1533 r->context->buffer()->clip(r->context->state.clipPath);
1539 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::closePath()
1541 Marks the current subpath as closed, and starts a new subpath with a point the same as the start and end of the newly closed subpath.
1543 See http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath for details.
1545 static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
1547 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1551 r->context->closePath();
1557 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fill()
1559 Fills the subpaths with the current fill style.
1561 See http://www.w3.org/TR/2dcontext/#dom-context-2d-fill for details.
1563 \sa QtQuick2::Context2D::fillStyle
1565 static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
1567 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1570 r->context->buffer()->fill(r->context->m_path);
1576 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::lineTo(real x, real y)
1578 Adds the given point to the current subpath, connected to the previous one by a straight line.
1580 static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
1582 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1586 if (args.Length() == 2) {
1587 r->context->lineTo(args[0]->NumberValue(),
1588 args[1]->NumberValue());
1595 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::moveTo(real x, real y)
1597 Creates a new subpath with the given point.
1599 static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
1601 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1605 if (args.Length() == 2) {
1606 r->context->moveTo(args[0]->NumberValue(),
1607 args[1]->NumberValue());
1614 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
1616 Adds the given point to the current subpath, connected to the previous one by a quadratic Bézier curve with the given control point.
1618 See http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto for details.
1620 static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
1622 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1626 if (args.Length() == 4) {
1627 r->context->quadraticCurveTo(args[0]->NumberValue(),
1628 args[1]->NumberValue(),
1629 args[2]->NumberValue(),
1630 args[3]->NumberValue());
1637 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::rect(real x, real y, real w, real h)
1639 Adds a new closed subpath to the path, representing the given rectangle.
1641 See http://www.w3.org/TR/2dcontext/#dom-context-2d-rect for details.
1643 static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
1645 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1649 if (args.Length() == 4) {
1650 r->context->rect(args[0]->NumberValue(),
1651 args[1]->NumberValue(),
1652 args[2]->NumberValue(),
1653 args[3]->NumberValue());
1660 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::roundedRect(real x, real y, real w, real h, real xRadius, real yRadius)
1662 Adds the given rectangle rect with rounded corners to the path. The xRadius and yRadius arguments specify the radii of the
1663 ellipses defining the corners of the rounded rectangle.
1665 static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
1667 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1671 if (args.Length() == 6) {
1672 r->context->roundedRect(args[0]->NumberValue(),
1673 args[1]->NumberValue(),
1674 args[2]->NumberValue(),
1675 args[3]->NumberValue(),
1676 args[4]->NumberValue(),
1677 args[5]->NumberValue());
1684 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
1686 Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
1687 and adds it to the path as a closed subpath.
1689 The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
1691 static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
1693 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1697 if (args.Length() == 4) {
1698 r->context->ellipse(args[0]->NumberValue(),
1699 args[1]->NumberValue(),
1700 args[2]->NumberValue(),
1701 args[3]->NumberValue());
1708 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::text(string text, real x, real y)
1710 Adds the given \a text to the path as a set of closed subpaths created from the current context font supplied.
1711 The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (x, y).
1713 static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
1715 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1718 QV8Engine *engine = V8ENGINE();
1719 if (args.Length() == 3) {
1720 r->context->text(engine->toString(args[0]),
1721 args[1]->NumberValue(),
1722 args[2]->NumberValue());
1729 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::stroke()
1731 Strokes the subpaths with the current stroke style.
1733 See http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke for details.
1735 \sa QtQuick2::Context2D::strokeStyle
1737 static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
1739 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1743 r->context->buffer()->stroke(r->context->m_path);
1749 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::isPointInPath(real x, real y)
1751 Returns true if the given point is in the current path.
1753 See http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath for details.
1755 static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
1757 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1761 bool pointInPath = false;
1762 if (args.Length() == 2) {
1763 pointInPath = r->context->isPointInPath(args[0]->NumberValue(),
1764 args[1]->NumberValue());
1767 return v8::Boolean::New(pointInPath);
1770 static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
1772 V8THROW_ERROR("Context2D::drawFocusRing is not supported")
1776 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
1778 V8THROW_ERROR("Context2D::setCaretSelectionRect is not supported")
1782 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
1784 V8THROW_ERROR("Context2D::caretBlinkRate is not supported")
1790 \qmlproperty string QtQuick2::Context2D::font
1791 Holds the current font settings, default value is "10px sans-serif".
1793 See http://www.w3.org/TR/2dcontext/#dom-context-2d-font for details.
1795 v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
1797 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1800 QV8Engine *engine = V8ENGINE_ACCESSOR();
1802 return engine->toString(r->context->m_fontString);
1805 static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1807 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1808 CHECK_CONTEXT_SETTER(r)
1810 QV8Engine *engine = V8ENGINE_ACCESSOR();
1811 QString fs = engine->toString(value);
1812 if (fs != r->context->m_fontString) {
1813 r->context->m_fontString = fs;
1814 QFont font = qt_font_from_string(fs);
1815 r->context->state.font = font;
1820 \qmlproperty string QtQuick2::Context2D::textAlign
1822 Holds the current text alignment settings.
1823 The possible values are:
1831 Other values are ignored. The default is start.
1833 v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
1835 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1837 QV8Engine *engine = V8ENGINE_ACCESSOR();
1838 switch (r->context->state.textAlign) {
1839 case QSGContext2D::Start:
1840 return engine->toString(QLatin1String("start"));
1841 case QSGContext2D::End:
1842 return engine->toString(QLatin1String("end"));
1843 case QSGContext2D::Left:
1844 return engine->toString(QLatin1String("left"));
1845 case QSGContext2D::Right:
1846 return engine->toString(QLatin1String("right"));
1847 case QSGContext2D::Center:
1848 return engine->toString(QLatin1String("center"));
1852 return engine->toString(QLatin1String("start"));
1855 static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1857 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1858 CHECK_CONTEXT_SETTER(r)
1859 QV8Engine *engine = V8ENGINE_ACCESSOR();
1861 QString textAlign = engine->toString(value);
1863 QSGContext2D::TextAlignType ta;
1864 if (textAlign == QLatin1String("start"))
1865 ta = QSGContext2D::Start;
1866 else if (textAlign == QLatin1String("end"))
1867 ta = QSGContext2D::End;
1868 else if (textAlign == QLatin1String("left"))
1869 ta = QSGContext2D::Left;
1870 else if (textAlign == QLatin1String("right"))
1871 ta = QSGContext2D::Right;
1872 else if (textAlign == QLatin1String("center"))
1873 ta = QSGContext2D::Center;
1875 if (ta != r->context->state.textAlign) {
1876 r->context->state.textAlign = ta;
1881 \qmlproperty string QtQuick2::Context2D::textBaseline
1883 Holds the current baseline alignment settings.
1884 The possible values are:
1893 Other values are ignored. The default value is "alphabetic".
1894 See http://www.w3.org/TR/2dcontext/#dom-context-2d-textbaseline for details.
1896 v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
1898 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1901 QV8Engine *engine = V8ENGINE_ACCESSOR();
1902 switch (r->context->state.textBaseline) {
1903 case QSGContext2D::Alphabetic:
1904 return engine->toString(QLatin1String("alphabetic"));
1905 case QSGContext2D::Hanging:
1906 return engine->toString(QLatin1String("hanging"));
1907 case QSGContext2D::Top:
1908 return engine->toString(QLatin1String("top"));
1909 case QSGContext2D::Bottom:
1910 return engine->toString(QLatin1String("bottom"));
1911 case QSGContext2D::Middle:
1912 return engine->toString(QLatin1String("middle"));
1916 return engine->toString(QLatin1String("alphabetic"));
1919 static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1921 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1922 CHECK_CONTEXT_SETTER(r)
1923 QV8Engine *engine = V8ENGINE_ACCESSOR();
1924 QString textBaseline = engine->toString(value);
1926 QSGContext2D::TextBaseLineType tb;
1927 if (textBaseline == QLatin1String("alphabetic"))
1928 tb = QSGContext2D::Alphabetic;
1929 else if (textBaseline == QLatin1String("hanging"))
1930 tb = QSGContext2D::Hanging;
1931 else if (textBaseline == QLatin1String("top"))
1932 tb = QSGContext2D::Top;
1933 else if (textBaseline == QLatin1String("bottom"))
1934 tb = QSGContext2D::Bottom;
1935 else if (textBaseline == QLatin1String("middle"))
1936 tb = QSGContext2D::Middle;
1938 if (tb != r->context->state.textBaseline) {
1939 r->context->state.textBaseline = tb;
1944 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillText(text, x, y)
1945 Fills the given text at the given position.
1946 See http://www.w3.org/TR/2dcontext/#dom-context-2d-filltext for details.
1948 static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
1950 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1954 QV8Engine *engine = V8ENGINE();
1956 if (args.Length() == 3) {
1957 QPainterPath textPath = r->context->createTextGlyphs(args[1]->NumberValue(),
1958 args[2]->NumberValue(),
1959 engine->toString(args[0]));
1960 r->context->buffer()->fill(textPath);
1966 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::strokeText(text, x, y)
1967 Strokes the given text at the given position.
1968 See http://www.w3.org/TR/2dcontext/#dom-context-2d-stroketext for details.
1970 static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
1972 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1976 QV8Engine *engine = V8ENGINE();
1978 if (args.Length() == 3) {
1979 QPainterPath textPath = r->context->createTextGlyphs(args[1]->NumberValue(),
1980 args[2]->NumberValue(),
1981 engine->toString(args[0]));
1982 r->context->buffer()->stroke(textPath);
1988 \qmlclass QtQuick2::TextMetrics
1989 \inqmlmodule QtQuick 2
1991 \brief The Context2D TextMetrics interface.
1992 The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
1993 See http://www.w3.org/TR/2dcontext/#textmetrics for more details.
1995 \sa QtQuick2::Context2D::measureText
1996 \sa QtQuick2::TextMetrics::width
2000 \qmlproperty int QtQuick2::TextMetrics::width
2001 Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
2002 This property is read only.
2003 See http://www.w3.org/TR/2dcontext/#dom-textmetrics-width for more details.
2007 \qmlmethod variant QtQuick2::Context2D::measureText(text)
2008 Returns a TextMetrics object with the metrics of the given text in the current font.
2009 See http://www.w3.org/TR/2dcontext/#dom-context-2d-measuretext for details.
2011 static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
2013 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2017 QV8Engine *engine = V8ENGINE();
2019 if (args.Length() == 1) {
2020 QFontMetrics fm(r->context->state.font);
2021 uint width = fm.width(engine->toString(args[0]));
2022 v8::Local<v8::Object> tm = v8::Object::New();
2023 tm->Set(v8::String::New("width"), v8::Number::New(width));
2027 return v8::Undefined();
2032 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
2033 Draws the given \a image on the canvas at position (\a dx, \a dy).
2035 The \a image type can be an Image item or a image url. When given as Image
2036 type, if the image isn't fully loaded, will draw nothing. When given as url string,
2037 the context loads the image asynchorously and redraw the canvas when the image is loaded.
2039 See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
2042 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
2043 Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
2045 See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
2048 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
2049 Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
2050 onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
2051 See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
2053 static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
2055 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2059 QV8Engine *engine = V8ENGINE();
2061 //TODO: handle exceptions
2063 qreal sx, sy, sw, sh, dx, dy, dw, dh;
2065 if (args.Length() != 3 && args.Length() != 5 && args.Length() != 9) {
2072 if (args[0]->IsString()) {
2073 image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2074 } /*else if (args[0]->IsObject()) {
2075 QSGImage* imageItem = qobject_cast<QSGImage*>(engine->toQObject(args[0]->ToObject()));
2077 image = imageItem->pixmap().toImage();
2083 if (args.Length() == 3) {
2084 dx = args[1]->NumberValue();
2085 dy = args[2]->NumberValue();
2088 sw = image.isNull()? -1 : image.width();
2089 sh = image.isNull()? -1 : image.height();
2092 } else if (args.Length() == 5) {
2095 sw = image.isNull()? -1 : image.width();
2096 sh = image.isNull()? -1 : image.height();
2097 dx = args[1]->NumberValue();
2098 dy = args[2]->NumberValue();
2099 dw = args[3]->NumberValue();
2100 dh = args[4]->NumberValue();
2101 } else if (args.Length() == 9) {
2102 sx = args[1]->NumberValue();
2103 sy = args[2]->NumberValue();
2104 sw = args[3]->NumberValue();
2105 sh = args[4]->NumberValue();
2106 dx = args[5]->NumberValue();
2107 dy = args[6]->NumberValue();
2108 dw = args[7]->NumberValue();
2109 dh = args[8]->NumberValue();
2115 r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
2120 // pixel manipulation
2122 \qmlclass QtQuick2::CanvasImageData
2126 \qmlproperty QtQuick2::CanvasImageData::width
2127 Holds the actual width dimension of the data in the ImageData object, in device pixels.
2129 v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
2131 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2133 return v8::Integer::New(0);
2134 return v8::Integer::New(r->image.width());
2138 \qmlproperty QtQuick2::CanvasImageData::height
2139 Holds the actual height dimension of the data in the ImageData object, in device pixels.
2141 v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
2143 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2145 return v8::Integer::New(0);
2147 return v8::Integer::New(r->image.height());
2151 \qmlproperty QtQuick2::CanvasImageData::data
2152 Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
2154 v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
2156 return args.This()->GetInternalField(0);
2159 static v8::Handle<v8::Value> ctx2d_imageData_mirror(const v8::Arguments &args)
2161 bool horizontal = false, vertical = true;
2162 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2166 return v8::Undefined();
2169 if (args.Length() > 2) {
2171 return v8::Undefined();
2174 if (args.Length() == 1) {
2175 horizontal = args[0]->BooleanValue();
2176 } else if (args.Length() == 2) {
2177 horizontal = args[0]->BooleanValue();
2178 vertical = args[1]->BooleanValue();
2180 r->image = r->image.mirrored(horizontal, vertical);
2185 static v8::Handle<v8::Value> ctx2d_imageData_filter(const v8::Arguments &args)
2187 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2191 return v8::Undefined();
2194 if (args.Length() >= 1) {
2195 int filterFlag = args[0]->IntegerValue();
2196 switch(filterFlag) {
2197 case QSGCanvasItem::GrayScale :
2199 for (int y = 0; y < r->image.height(); ++y) {
2200 QRgb *row = (QRgb*)r->image.scanLine(y);
2201 for (int x = 0; x < r->image.width(); ++x) {
2202 unsigned char* rgb = ((unsigned char*)&row[x]);
2203 rgb[0] = rgb[1] = rgb[2] = qGray(rgb[0], rgb[1], rgb[2]);
2208 case QSGCanvasItem::Threshold :
2210 int threshold = 127;
2211 if (args.Length() > 1)
2212 threshold = args[1]->IntegerValue();
2214 for (int y = 0; y < r->image.height(); ++y) {
2215 QRgb *row = (QRgb*)r->image.scanLine(y);
2216 for (int x = 0; x < r->image.width(); ++x) {
2217 unsigned char* rgb = ((unsigned char*)&row[x]);
2218 unsigned char v = qGray(rgb[0], rgb[1], rgb[2]) >= threshold ? 255 : 0;
2219 rgb[0] = rgb[1] = rgb[2] = v;
2224 case QSGCanvasItem::Brightness :
2227 if (args.Length() > 1)
2228 adjustment = args[1]->IntegerValue();
2230 for (int y = 0; y < r->image.height(); ++y) {
2231 QRgb *row = (QRgb*)r->image.scanLine(y);
2232 for (int x = 0; x < r->image.width(); ++x) {
2233 ((unsigned char*)&row[x])[0] += adjustment;
2234 ((unsigned char*)&row[x])[1] += adjustment;
2235 ((unsigned char*)&row[x])[2] += adjustment;
2240 case QSGCanvasItem::Invert :
2242 r->image.invertPixels();
2245 case QSGCanvasItem::Blur :
2248 bool quality = false;
2250 if (args.Length() > 1)
2251 radius = args[1]->IntegerValue() / 2;
2252 if (args.Length() > 2)
2253 quality = args[2]->BooleanValue();
2255 qt_image_boxblur(r->image, radius, quality);
2258 case QSGCanvasItem::Opaque :
2260 for (int y = 0; y < r->image.height(); ++y) {
2261 QRgb *row = (QRgb*)r->image.scanLine(y);
2262 for (int x = 0; x < r->image.width(); ++x) {
2263 ((unsigned char*)&row[x])[3] = 255;
2268 case QSGCanvasItem::Convolute :
2270 if (args.Length() > 1 && args[1]->IsArray()) {
2271 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(args[1]);
2272 QVector<qreal> weights;
2273 for (uint32_t i = 0; i < array->Length(); ++i)
2274 weights.append(array->Get(i)->NumberValue());
2275 r->image = qt_image_convolute_filter(r->image, weights);
2289 \qmlclass QtQuick2::CanvasPixelArray
2290 The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
2291 See http://www.w3.org/TR/2dcontext/#canvaspixelarray for more details.
2295 \qmlproperty QtQuick2::CanvasPixelArray::length
2296 The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
2297 The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
2299 v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
2301 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2302 if (!r || r->image.isNull()) return v8::Undefined();
2304 return v8::Integer::New(r->image.width() * r->image.height() * 4);
2307 v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
2309 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2311 if (r && index && index < r->image.width() * r->image.height() * 4) {
2312 const int w = r->image.width();
2313 const int h = r->image.height();
2314 const int row = (index / 4) / w;
2315 const int col = (index / 4) % w;
2316 const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
2318 switch (index % 4) {
2320 return v8::Integer::New(qRed(*pixel));
2322 return v8::Integer::New(qGreen(*pixel));
2324 return v8::Integer::New(qBlue(*pixel));
2326 return v8::Integer::New(qAlpha(*pixel));
2329 return v8::Undefined();
2332 v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
2334 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
2336 const int v = value->Uint32Value();
2337 if (r && index > 0 && index < r->image.width() * r->image.height() * 4 && v > 0 && v <= 255) {
2338 const int w = r->image.width();
2339 const int h = r->image.height();
2340 const int row = (index / 4) / w;
2341 const int col = (index / 4) % w;
2343 QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
2345 switch (index % 4) {
2347 *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
2350 *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
2353 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
2356 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
2360 return v8::Undefined();
2363 \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
2364 Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
2367 \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
2368 Creates a CanvasImageData object with the same dimensions as the argument.
2371 \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
2372 Creates a CanvasImageData object with the given image loaded from \a imageUrl.
2373 Note:The \a imageUrl must be already loaded before this function call, if not, an empty
2374 CanvasImageData obect will be returned.
2376 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
2378 static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
2380 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2384 QV8Engine *engine = V8ENGINE();
2386 if (args.Length() == 1) {
2387 if (args[0]->IsObject()) {
2388 v8::Local<v8::Object> imgData = args[0]->ToObject();
2389 QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
2391 qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
2392 qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
2393 return qt_create_image_data(w, h, engine, QImage());
2395 } else if (args[0]->IsString()) {
2396 QImage image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2397 return qt_create_image_data(image.width(), image.height(), engine, image);
2399 } else if (args.Length() == 2) {
2400 qreal w = args[0]->NumberValue();
2401 qreal h = args[1]->NumberValue();
2403 return qt_create_image_data(w, h, engine, QImage());
2405 return v8::Undefined();
2409 \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
2410 Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
2412 static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
2414 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2417 QV8Engine *engine = V8ENGINE();
2418 if (args.Length() == 4) {
2419 qreal x = args[0]->NumberValue();
2420 qreal y = args[1]->NumberValue();
2421 qreal w = args[2]->NumberValue();
2422 qreal h = args[3]->NumberValue();
2423 QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
2424 if (image.format() != QImage::Format_ARGB32)
2425 image = image.convertToFormat(QImage::Format_ARGB32);
2426 v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
2434 \qmlmethod QtQuick2::Context2D putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
2435 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.
2437 static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
2439 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2441 if (args.Length() != 3 && args.Length() != 7)
2442 return v8::Undefined();
2444 if (args[0]->IsNull() || !args[0]->IsObject()) {
2445 V8THROW_ERROR("Context2D::putImageData, the image data type mismatch");
2447 qreal dx = args[1]->NumberValue();
2448 qreal dy = args[2]->NumberValue();
2449 qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
2451 v8::Local<v8::Object> imageData = args[0]->ToObject();
2452 QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
2454 w = imageData->Get(v8::String::New("width"))->NumberValue();
2455 h = imageData->Get(v8::String::New("height"))->NumberValue();
2457 if (args.Length() == 7) {
2458 dirtyX = args[3]->NumberValue();
2459 dirtyY = args[4]->NumberValue();
2460 dirtyWidth = args[5]->NumberValue();
2461 dirtyHeight = args[6]->NumberValue();
2462 if (dirtyWidth < 0) {
2463 dirtyX = dirtyX+dirtyWidth;
2464 dirtyWidth = -dirtyWidth;
2467 if (dirtyHeight < 0) {
2468 dirtyY = dirtyY+dirtyHeight;
2469 dirtyHeight = -dirtyHeight;
2473 dirtyWidth = dirtyWidth+dirtyX;
2478 dirtyHeight = dirtyHeight+dirtyY;
2482 if (dirtyX+dirtyWidth > w) {
2483 dirtyWidth = w - dirtyX;
2486 if (dirtyY+dirtyHeight > h) {
2487 dirtyHeight = h - dirtyY;
2490 if (dirtyWidth <=0 || dirtyHeight <= 0)
2499 QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2500 r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
2506 \qmlclass QtQuick2::CanvasGradient
2507 \inqmlmodule QtQuick 2
2509 \brief The Context2D opaque CanvasGradient interface.
2513 \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
2514 Adds a color stop with the given color to the gradient at the given offset.
2515 0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
2517 static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
2519 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
2521 V8THROW_ERROR("Not a CanvasGradient object");
2523 QV8Engine *engine = V8ENGINE();
2525 if (args.Length() == 2) {
2527 if (!style->brush.gradient())
2528 V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
2529 QGradient gradient = *(style->brush.gradient());
2530 qreal pos = args[0]->NumberValue();
2531 QColor color = qt_color_from_string(engine->toString(args[1]));
2532 if (pos < 0.0 || pos > 1.0) {
2533 //Throws an INDEX_SIZE_ERR exception
2534 V8THROW_ERROR("CanvasGradient: parameter offset out of range");
2537 if (color.isValid()) {
2538 gradient.setColorAt(pos, color);
2540 //Throws a SYNTAX_ERR exception
2541 V8THROW_ERROR("CanvasGradient: parameter color is not a valid color string");
2543 style->brush = gradient;
2550 void QSGContext2D::beginPath()
2552 m_path = QPainterPath();
2553 m_path.setFillRule(state.fillRule);
2556 void QSGContext2D::closePath()
2558 if (m_path.isEmpty())
2561 QRectF boundRect = m_path.boundingRect();
2562 if (boundRect.width() || boundRect.height())
2563 m_path.closeSubpath();
2566 void QSGContext2D::moveTo( qreal x, qreal y)
2568 m_path.moveTo(state.matrix.map(QPointF(x, y)));
2571 void QSGContext2D::lineTo( qreal x, qreal y)
2573 m_path.lineTo(state.matrix.map(QPointF(x, y)));
2576 void QSGContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
2579 m_path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
2580 state.matrix.map(QPointF(x, y)));
2583 void QSGContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
2584 qreal cp2x, qreal cp2y,
2587 m_path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
2588 state.matrix.map(QPointF(cp2x, cp2y)),
2589 state.matrix.map(QPointF(x, y)));
2592 void QSGContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
2594 QPointF p0(m_path.currentPosition());
2596 QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
2597 QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
2598 float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
2599 float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
2601 double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
2603 // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
2604 // We could have used areCollinear() here, but since we're reusing
2605 // the variables computed above later on we keep this logic.
2606 if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
2611 float tangent = radius / tan(acos(cos_phi) / 2);
2612 float factor_p1p0 = tangent / p1p0_length;
2613 QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
2615 QPointF orth_p1p0(p1p0.y(), -p1p0.x());
2616 float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
2617 float factor_ra = radius / orth_p1p0_length;
2619 // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
2620 double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
2621 if (cos_alpha < 0.f)
2622 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
2624 QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
2626 // calculate angles for addArc
2627 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
2628 float sa = acos(orth_p1p0.x() / orth_p1p0_length);
2629 if (orth_p1p0.y() < 0.f)
2632 // anticlockwise logic
2633 bool anticlockwise = false;
2635 float factor_p1p2 = tangent / p1p2_length;
2636 QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
2637 QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
2638 float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
2639 float ea = acos(orth_p1p2.x() / orth_p1p2_length);
2640 if (orth_p1p2.y() < 0)
2642 if ((sa > ea) && ((sa - ea) < Q_PI))
2643 anticlockwise = true;
2644 if ((sa < ea) && ((ea - sa) > Q_PI))
2645 anticlockwise = true;
2647 arc(p.x(), p.y(), radius, sa, ea, anticlockwise, false);
2650 void QSGContext2D::arcTo(qreal x1, qreal y1,
2654 QPointF st = state.matrix.map(QPointF(x1, y1));
2655 QPointF end = state.matrix.map(QPointF(x2, y2));
2657 if (!m_path.elementCount()) {
2659 } else if (st == m_path.currentPosition() || st == end || !radius) {
2662 addArcTo(st, end, radius);
2666 void QSGContext2D::rect(qreal x, qreal y,
2669 m_path.addPolygon(state.matrix.map(QRectF(x, y, w, h)));
2672 void QSGContext2D::roundedRect(qreal x, qreal y,
2677 path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
2678 m_path.addPath(state.matrix.map(path));
2681 void QSGContext2D::ellipse(qreal x, qreal y,
2685 path.addEllipse(x, y, w, h);
2686 m_path.addPath(state.matrix.map(path));
2689 void QSGContext2D::text(const QString& str, qreal x, qreal y)
2692 path.addText(x, y, state.font, str);
2693 m_path.addPath(state.matrix.map(path));
2696 void QSGContext2D::arc(qreal xc,
2706 QPointF point = state.matrix.map(QPointF(xc, yc));
2712 // In Qt we don't switch the coordinate system for degrees
2713 // and still use the 0,0 as bottom left for degrees so we need
2717 antiClockWise = !antiClockWise;
2720 float sa = DEGREES(sar);
2721 float ea = DEGREES(ear);
2725 double xs = xc - radius;
2726 double ys = yc - radius;
2727 double width = radius*2;
2728 double height = radius*2;
2729 if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
2730 // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
2731 // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
2732 // circumference of this circle.
2735 if (!antiClockWise && (ea < sa)) {
2737 } else if (antiClockWise && (sa < ea)) {
2740 //### this is also due to switched coordinate system
2741 // we would end up with a 0 span instead of 360
2742 if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
2743 qFuzzyCompare(qAbs(span), 360))) {
2746 if (!m_path.elementCount())
2747 m_path.moveTo(xs, ys);
2752 QPointF currentPos = m_path.currentPosition();
2753 QPointF startPos = QPointF(xc + radius * qCos(sar),
2754 yc - radius * qSin(sar));
2755 if (currentPos != startPos)
2756 m_path.lineTo(startPos);
2759 m_path.arcTo(xs, ys, width, height, sa, span);
2762 int baseLineOffset(QSGContext2D::TextBaseLineType value, const QFontMetrics &metrics)
2766 case QSGContext2D::QSGContext2D::Top:
2768 case QSGContext2D::QSGContext2D::Alphabetic:
2769 case QSGContext2D::QSGContext2D::Middle:
2770 case QSGContext2D::QSGContext2D::Hanging:
2771 offset = metrics.ascent();
2773 case QSGContext2D::QSGContext2D::Bottom:
2774 offset = metrics.height();
2780 static int textAlignOffset(QSGContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
2783 if (value == QSGContext2D::Start)
2784 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QSGContext2D::Left : QSGContext2D::Right;
2785 else if (value == QSGContext2D::End)
2786 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QSGContext2D::Right: QSGContext2D::Left;
2788 case QSGContext2D::QSGContext2D::Center:
2789 offset = metrics.width(text)/2;
2791 case QSGContext2D::QSGContext2D::Right:
2792 offset = metrics.width(text);
2793 case QSGContext2D::QSGContext2D::Left:
2801 QImage QSGContext2D::createImage(const QUrl& url)
2803 return m_canvas->loadedImage(url);
2806 QPainterPath QSGContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
2808 const QFontMetrics metrics(state.font);
2809 int yoffset = baseLineOffset(static_cast<QSGContext2D::TextBaseLineType>(state.textBaseline), metrics);
2810 int xoffset = textAlignOffset(static_cast<QSGContext2D::TextAlignType>(state.textAlign), metrics, text);
2812 QPainterPath textPath;
2814 textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
2815 textPath = state.matrix.map(textPath);
2820 bool QSGContext2D::isPointInPath(qreal x, qreal y) const
2822 return m_path.contains(QPointF(x, y));
2825 QSGContext2D::QSGContext2D(QSGCanvasItem* item)
2827 , m_buffer(new QSGContext2DCommandBuffer)
2833 QSGContext2D::~QSGContext2D()
2837 v8::Handle<v8::Object> QSGContext2D::v8value() const
2842 QSGContext2DEngineData::QSGContext2DEngineData(QV8Engine *engine)
2844 v8::HandleScope handle_scope;
2845 v8::Context::Scope scope(engine->context());
2847 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
2848 ft->InstanceTemplate()->SetHasExternalResource(true);
2849 ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine));
2850 ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine));
2851 ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine));
2852 ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine));
2853 ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine));
2854 ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine));
2855 ft->PrototypeTemplate()->Set(v8::String::New("resetTransform"), V8FUNCTION(ctx2d_resetTransform, engine));
2856 ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine));
2857 ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine));
2858 ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine));
2859 ft->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, engine));
2860 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine));
2861 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine));
2862 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillRule"), ctx2d_fillRule, ctx2d_fillRule_set, v8::External::Wrap(engine));
2863 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine));
2864 ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
2865 ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
2866 ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
2867 ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
2868 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
2869 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
2870 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine));
2871 ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine));
2872 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine));
2873 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine));
2874 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine));
2875 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine));
2876 ft->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_set, v8::External::Wrap(engine));
2877 ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine));
2878 ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine));
2879 ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine));
2880 ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine));
2881 ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine));
2882 ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine));
2883 ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine));
2884 ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine));
2885 ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine));
2886 ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine));
2887 ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine));
2888 ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine));
2889 ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine));
2890 ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine));
2891 ft->PrototypeTemplate()->Set(v8::String::New("roundedRect"), V8FUNCTION(ctx2d_roundedRect, engine));
2892 ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
2893 ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine));
2894 ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine));
2895 ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine));
2896 ft->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
2897 ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
2898 ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, engine));
2899 ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine));
2900 ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine));
2901 ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine));
2902 ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine));
2903 ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine));
2904 ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine));
2905 ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine));
2906 ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine));
2907 ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine));
2908 ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine));
2910 constructorContext = qPersistentNew(ft->GetFunction());
2912 v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
2913 ftGradient->InstanceTemplate()->SetHasExternalResource(true);
2914 ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
2915 constructorGradient = qPersistentNew(ftGradient->GetFunction());
2917 v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
2918 ftPattern->InstanceTemplate()->SetHasExternalResource(true);
2919 constructorPattern = qPersistentNew(ftPattern->GetFunction());
2921 v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
2922 ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
2923 ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
2924 ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
2925 constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
2927 v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
2928 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
2929 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
2930 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
2931 ftImageData->PrototypeTemplate()->Set(v8::String::New("mirror"), V8FUNCTION(ctx2d_imageData_mirror, engine));
2932 ftImageData->PrototypeTemplate()->Set(v8::String::New("filter"), V8FUNCTION(ctx2d_imageData_filter, engine));
2933 ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
2934 constructorImageData = qPersistentNew(ftImageData->GetFunction());
2937 QSGContext2DEngineData::~QSGContext2DEngineData()
2939 qPersistentDispose(constructorContext);
2940 qPersistentDispose(constructorGradient);
2941 qPersistentDispose(constructorPattern);
2942 qPersistentDispose(constructorImageData);
2943 qPersistentDispose(constructorPixelArray);
2946 void QSGContext2D::popState()
2948 if (m_stateStack.isEmpty())
2951 QSGContext2D::State newState = m_stateStack.pop();
2953 if (state.matrix != newState.matrix)
2954 buffer()->updateMatrix(newState.matrix);
2956 if (newState.globalAlpha != state.globalAlpha)
2957 buffer()->setGlobalAlpha(newState.globalAlpha);
2959 if (newState.globalCompositeOperation != state.globalCompositeOperation)
2960 buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
2962 if (newState.fillStyle != state.fillStyle)
2963 buffer()->setFillStyle(newState.fillStyle);
2965 if (newState.strokeStyle != state.strokeStyle)
2966 buffer()->setStrokeStyle(newState.strokeStyle);
2968 if (newState.lineWidth != state.lineWidth)
2969 buffer()->setLineWidth(newState.lineWidth);
2971 if (newState.lineCap != state.lineCap)
2972 buffer()->setLineCap(newState.lineCap);
2974 if (newState.lineJoin != state.lineJoin)
2975 buffer()->setLineJoin(newState.lineJoin);
2977 if (newState.miterLimit != state.miterLimit)
2978 buffer()->setMiterLimit(newState.miterLimit);
2980 if (newState.clipPath != state.clipPath)
2981 buffer()->clip(newState.clipPath);
2983 if (newState.shadowBlur != state.shadowBlur)
2984 buffer()->setShadowBlur(newState.shadowBlur);
2986 if (newState.shadowColor != state.shadowColor)
2987 buffer()->setShadowColor(newState.shadowColor);
2989 if (newState.shadowOffsetX != state.shadowOffsetX)
2990 buffer()->setShadowOffsetX(newState.shadowOffsetX);
2992 if (newState.shadowOffsetY != state.shadowOffsetY)
2993 buffer()->setShadowOffsetY(newState.shadowOffsetY);
2997 void QSGContext2D::pushState()
2999 m_stateStack.push(state);
3002 void QSGContext2D::reset()
3004 QSGContext2D::State newState;
3005 newState.matrix = QTransform();
3007 QPainterPath defaultClipPath;
3008 defaultClipPath.addRect(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
3009 newState.clipPath = defaultClipPath;
3010 newState.clipPath.setFillRule(Qt::WindingFill);
3012 newState.strokeStyle = Qt::black;
3013 newState.fillStyle = Qt::black;
3014 newState.fillRule = Qt::WindingFill;
3015 newState.globalAlpha = 1.0;
3016 newState.lineWidth = 1;
3017 newState.lineCap = Qt::FlatCap;
3018 newState.lineJoin = Qt::MiterJoin;
3019 newState.miterLimit = 10;
3020 newState.shadowOffsetX = 0;
3021 newState.shadowOffsetY = 0;
3022 newState.shadowBlur = 0;
3023 newState.shadowColor = qRgba(0, 0, 0, 0);
3024 newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
3025 newState.font = QFont(QLatin1String("sans-serif"), 10);
3026 newState.textAlign = QSGContext2D::Start;
3027 newState.textBaseline = QSGContext2D::Alphabetic;
3030 m_stateStack.clear();
3031 m_stateStack.push(newState);
3035 void QSGContext2D::setV8Engine(QV8Engine *engine)
3037 v8::HandleScope handle_scope;
3038 v8::Context::Scope scope(engine->context());
3040 if (m_v8engine != engine) {
3041 m_v8engine = engine;
3043 qPersistentDispose(m_v8value);
3045 if (m_v8engine == 0)
3048 QSGContext2DEngineData *ed = engineData(engine);
3049 m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
3050 QV8Context2DResource *r = new QV8Context2DResource(engine);
3052 m_v8value->SetExternalResource(r);