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 static QImage qt_texture_to_image(QSGTexture* texture)
343 if (!texture || !texture->textureId())
345 QOpenGLFramebufferObjectFormat format;
346 format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
347 format.setInternalTextureFormat(GL_RGBA);
348 format.setMipmap(false);
349 QOpenGLFramebufferObject* fbo = new QOpenGLFramebufferObject(texture->textureSize(), format);
352 fbo->drawTexture(QPointF(0,0), texture->textureId(), GL_TEXTURE_2D);
354 return fbo->toImage();
357 static QSGTexture* qt_item_to_texture(QSGItem* item)
361 QSGShaderEffectTexture* texture = new QSGShaderEffectTexture(item);
362 texture->setItem(QSGItemPrivate::get(item)->itemNode());
363 texture->setLive(true);
365 QRectF sourceRect = QRectF(0, 0, item->width(), item->height());
367 texture->setRect(sourceRect);
368 QSize textureSize = QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height())));
369 texture->setSize(textureSize);
370 texture->setRecursive(false);
371 texture->setFormat(GL_RGBA);
372 texture->setHasMipmaps(false);
373 texture->markDirtyTexture();
374 texture->updateTexture();
378 static QImage qt_item_to_image(QSGItem* item) {
379 return qt_texture_to_image(qt_item_to_texture(item));
382 static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
384 if (compositeOperator == QLatin1String("source-over")) {
385 return QPainter::CompositionMode_SourceOver;
386 } else if (compositeOperator == QLatin1String("source-out")) {
387 return QPainter::CompositionMode_SourceOut;
388 } else if (compositeOperator == QLatin1String("source-in")) {
389 return QPainter::CompositionMode_SourceIn;
390 } else if (compositeOperator == QLatin1String("source-atop")) {
391 return QPainter::CompositionMode_SourceAtop;
392 } else if (compositeOperator == QLatin1String("destination-atop")) {
393 return QPainter::CompositionMode_DestinationAtop;
394 } else if (compositeOperator == QLatin1String("destination-in")) {
395 return QPainter::CompositionMode_DestinationIn;
396 } else if (compositeOperator == QLatin1String("destination-out")) {
397 return QPainter::CompositionMode_DestinationOut;
398 } else if (compositeOperator == QLatin1String("destination-over")) {
399 return QPainter::CompositionMode_DestinationOver;
400 } else if (compositeOperator == QLatin1String("lighter")) {
401 return QPainter::CompositionMode_Plus;
402 } else if (compositeOperator == QLatin1String("copy")) {
403 return QPainter::CompositionMode_Source;
404 } else if (compositeOperator == QLatin1String("xor")) {
405 return QPainter::CompositionMode_Xor;
406 } else if (compositeOperator == QLatin1String("qt-clear")) {
407 return QPainter::CompositionMode_Clear;
408 } else if (compositeOperator == QLatin1String("qt-destination")) {
409 return QPainter::CompositionMode_Destination;
410 } else if (compositeOperator == QLatin1String("qt-multiply")) {
411 return QPainter::CompositionMode_Multiply;
412 } else if (compositeOperator == QLatin1String("qt-screen")) {
413 return QPainter::CompositionMode_Screen;
414 } else if (compositeOperator == QLatin1String("qt-overlay")) {
415 return QPainter::CompositionMode_Overlay;
416 } else if (compositeOperator == QLatin1String("qt-darken")) {
417 return QPainter::CompositionMode_Darken;
418 } else if (compositeOperator == QLatin1String("qt-lighten")) {
419 return QPainter::CompositionMode_Lighten;
420 } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
421 return QPainter::CompositionMode_ColorDodge;
422 } else if (compositeOperator == QLatin1String("qt-color-burn")) {
423 return QPainter::CompositionMode_ColorBurn;
424 } else if (compositeOperator == QLatin1String("qt-hard-light")) {
425 return QPainter::CompositionMode_HardLight;
426 } else if (compositeOperator == QLatin1String("qt-soft-light")) {
427 return QPainter::CompositionMode_SoftLight;
428 } else if (compositeOperator == QLatin1String("qt-difference")) {
429 return QPainter::CompositionMode_Difference;
430 } else if (compositeOperator == QLatin1String("qt-exclusion")) {
431 return QPainter::CompositionMode_Exclusion;
433 return QPainter::CompositionMode_SourceOver;
436 static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
439 case QPainter::CompositionMode_SourceOver:
440 return QLatin1String("source-over");
441 case QPainter::CompositionMode_DestinationOver:
442 return QLatin1String("destination-over");
443 case QPainter::CompositionMode_Clear:
444 return QLatin1String("qt-clear");
445 case QPainter::CompositionMode_Source:
446 return QLatin1String("copy");
447 case QPainter::CompositionMode_Destination:
448 return QLatin1String("qt-destination");
449 case QPainter::CompositionMode_SourceIn:
450 return QLatin1String("source-in");
451 case QPainter::CompositionMode_DestinationIn:
452 return QLatin1String("destination-in");
453 case QPainter::CompositionMode_SourceOut:
454 return QLatin1String("source-out");
455 case QPainter::CompositionMode_DestinationOut:
456 return QLatin1String("destination-out");
457 case QPainter::CompositionMode_SourceAtop:
458 return QLatin1String("source-atop");
459 case QPainter::CompositionMode_DestinationAtop:
460 return QLatin1String("destination-atop");
461 case QPainter::CompositionMode_Xor:
462 return QLatin1String("xor");
463 case QPainter::CompositionMode_Plus:
464 return QLatin1String("lighter");
465 case QPainter::CompositionMode_Multiply:
466 return QLatin1String("qt-multiply");
467 case QPainter::CompositionMode_Screen:
468 return QLatin1String("qt-screen");
469 case QPainter::CompositionMode_Overlay:
470 return QLatin1String("qt-overlay");
471 case QPainter::CompositionMode_Darken:
472 return QLatin1String("qt-darken");
473 case QPainter::CompositionMode_Lighten:
474 return QLatin1String("qt-lighten");
475 case QPainter::CompositionMode_ColorDodge:
476 return QLatin1String("qt-color-dodge");
477 case QPainter::CompositionMode_ColorBurn:
478 return QLatin1String("qt-color-burn");
479 case QPainter::CompositionMode_HardLight:
480 return QLatin1String("qt-hard-light");
481 case QPainter::CompositionMode_SoftLight:
482 return QLatin1String("qt-soft-light");
483 case QPainter::CompositionMode_Difference:
484 return QLatin1String("qt-difference");
485 case QPainter::CompositionMode_Exclusion:
486 return QLatin1String("qt-exclusion");
494 static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
496 QSGContext2DEngineData *ed = engineData(engine);
497 v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
498 QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
499 if (image.isNull()) {
500 r->image = QImage(w, h, QImage::Format_ARGB32);
501 r->image.fill(Qt::transparent);
503 Q_ASSERT(image.width() == w && image.height() == h);
506 v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
507 pixelData->SetExternalResource(r);
509 imageData->SetInternalField(0, pixelData);
513 //static script functions
516 \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
517 Holds the canvas item that the context paints on.
519 static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
521 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
525 QV8Engine *engine = V8ENGINE_ACCESSOR();
527 return engine->newQObject(r->context->canvas());
531 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::restore()
532 Pops the top state on the stack, restoring the context to that state.
534 static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
536 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
539 r->context->popState();
544 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::reset()
545 Resets the context state and properties to the default values.
547 static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
549 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
557 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::save()
558 Pushes the current state onto the stack.
560 static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
562 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
565 r->context->pushState();
572 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::rotate(real angle)
573 Changes the transformation matrix to apply a rotation transformation with the given characteristics.
574 Note: The angle is in radians.
576 static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
578 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
582 if (args.Length() == 1) {
583 qreal angle = args[0]->NumberValue();
584 r->context->state.matrix.rotate(DEGREES(angle));
585 r->context->buffer()->updateMatrix(r->context->state.matrix);
592 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::scale(real x, real y)
593 Changes the transformation matrix to apply a scaling transformation with the given characteristics.
595 static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
597 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
601 if (args.Length() == 2) {
603 x = args[0]->NumberValue();
604 y = args[1]->NumberValue();
605 r->context->state.matrix.scale(x, y);
606 r->context->buffer()->updateMatrix(r->context->state.matrix);
613 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
614 Changes the transformation matrix to the matrix given by the arguments as described below.
616 \sa QtQuick2::Context2D::transform()
618 static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
620 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
624 if (args.Length() == 6) {
625 r->context->state.matrix = QTransform(args[0]->NumberValue(),
626 args[1]->NumberValue(),
627 args[2]->NumberValue(),
628 args[3]->NumberValue(),
629 args[4]->NumberValue(),
630 args[5]->NumberValue());
631 r->context->buffer()->updateMatrix(r->context->state.matrix);
638 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
639 Changes the transformation matrix to apply the matrix given by the arguments as described below.
641 \sa QtQuick2::Context2D::setTransform()
643 static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
645 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
649 if (args.Length() == 6) {
650 r->context->state.matrix *= QTransform(args[0]->NumberValue(),
651 args[1]->NumberValue(),
652 args[2]->NumberValue(),
653 args[3]->NumberValue(),
654 args[4]->NumberValue(),
655 args[5]->NumberValue());
656 r->context->buffer()->updateMatrix(r->context->state.matrix);
663 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::translate(real x, real y)
664 Changes the transformation matrix to apply a translation transformation with the given characteristics.
666 static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
668 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
672 if (args.Length() == 2) {
673 r->context->state.matrix.translate(args[0]->NumberValue(),
674 args[1]->NumberValue());
675 r->context->buffer()->updateMatrix(r->context->state.matrix);
683 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::resetTransform()
684 Reset the transformation matrix default value.
686 \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform()
688 static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
690 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
693 r->context->state.matrix = QTransform();
694 r->context->buffer()->updateMatrix(r->context->state.matrix);
701 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::shear(real sh, real sv )
702 Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
704 static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
706 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
709 r->context->state.matrix.shear(args[0]->NumberValue(),
710 args[1]->NumberValue());
711 r->context->buffer()->updateMatrix(r->context->state.matrix);
718 \qmlproperty real QtQuick2::Context2D::globalAlpha
719 Holds the the current alpha value applied to rendering operations.
720 The value must be in the range from 0.0 (fully transparent) to 1.0 (no additional transparency).
722 static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
724 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
727 return v8::Number::New(r->context->state.globalAlpha);
730 static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
732 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
733 CHECK_CONTEXT_SETTER(r)
735 qreal globalAlpha = value->NumberValue();
737 if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
738 r->context->state.globalAlpha = globalAlpha;
739 r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
744 \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
745 Holds the the current the current composition operation, from the list below:
747 \o source-atop - A atop B. Display the source image wherever both images are opaque.
748 Display the destination image wherever the destination image is opaque but the source image is transparent.
749 Display transparency elsewhere.
750 \o source-in - A in B. Display the source image wherever both the source image and destination image are opaque.
751 Display transparency elsewhere.
752 \o source-out - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
753 Display transparency elsewhere.
754 \o source-over - (default) A over B. Display the source image wherever the source image is opaque.
755 Display the destination image elsewhere.
756 \o destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
757 \o destination-in - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
758 \o destination-out - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
759 \o destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
760 \o lighter - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
761 \o copy - A (B is ignored). Display the source image instead of the destination image.
762 \o xor - A xor B. Exclusive OR of the source image and destination image.
765 static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
767 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
771 QV8Engine *engine = V8ENGINE_ACCESSOR();
773 return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
776 static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
778 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
779 CHECK_CONTEXT_SETTER(r)
781 QV8Engine *engine = V8ENGINE_ACCESSOR();
783 QPainter::CompositionMode cm = qt_composite_mode_from_string(engine->toString(value));
784 if (cm != r->context->state.globalCompositeOperation) {
785 r->context->state.globalCompositeOperation = cm;
786 r->context->buffer()->setGlobalCompositeOperation(cm);
792 \qmlproperty variant QtQuick2::Context2D::fillStyle
793 Holds the current style used for filling shapes.
794 The style can be either a string containing a CSS color, or a CanvasGradient or CanvasPattern object. Invalid values are ignored.
795 \sa QtQuick2::Context2D::createLinearGradient
796 \sa QtQuick2::Context2D::createRadialGradient
797 \sa QtQuick2::Context2D::createPattern
798 \sa QtQuick2::Context2D::strokeStyle
800 static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
802 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
805 return r->context->m_fillStyle;
808 static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
810 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
811 CHECK_CONTEXT_SETTER(r)
813 QV8Engine *engine = V8ENGINE_ACCESSOR();
815 r->context->m_fillStyle = value;
816 if (value->IsObject()) {
817 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
818 if (color.isValid()) {
819 r->context->state.fillStyle = color;
820 r->context->buffer()->setFillStyle(color);
822 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
823 if (style && style->brush != r->context->state.fillStyle) {
824 r->context->state.fillStyle = style->brush;
825 r->context->buffer()->setFillStyle(style->brush);
828 } else if (value->IsString()) {
829 QColor color = qt_color_from_string(engine->toString(value));
830 if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
831 r->context->state.fillStyle = QBrush(color);
832 r->context->buffer()->setFillStyle(r->context->state.fillStyle);
837 static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
839 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
841 QV8Engine *engine = V8ENGINE_ACCESSOR();
843 return engine->fromVariant(r->context->state.fillRule);
846 static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
848 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
849 CHECK_CONTEXT_SETTER(r)
851 QV8Engine *engine = V8ENGINE_ACCESSOR();
853 if ((value->IsString() && engine->toString(value) == "WindingFill")
854 ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
855 r->context->state.fillRule = Qt::WindingFill;
856 } else if ((value->IsString() && engine->toString(value) == "OddEvenFill")
857 ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
858 r->context->state.fillRule = Qt::OddEvenFill;
862 r->context->m_path.setFillRule(r->context->state.fillRule);
865 \qmlproperty variant QtQuick2::Context2D::strokeStyle
866 Holds the current color or style to use for the lines around shapes,
867 The style can be either a string containing a CSS color, or a CanvasGradient or CanvasPattern object. Invalid values are ignored.
868 \sa QtQuick2::Context2D::createLinearGradient
869 \sa QtQuick2::Context2D::createRadialGradient
870 \sa QtQuick2::Context2D::createPattern
871 \sa QtQuick2::Context2D::fillStyle
873 v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
875 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
879 return r->context->m_strokeStyle;
882 static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
884 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
885 CHECK_CONTEXT_SETTER(r)
887 QV8Engine *engine = V8ENGINE_ACCESSOR();
889 r->context->m_strokeStyle = value;
890 if (value->IsObject()) {
891 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
892 if (color.isValid()) {
893 r->context->state.fillStyle = color;
894 r->context->buffer()->setStrokeStyle(color);
896 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
897 if (style && style->brush != r->context->state.strokeStyle) {
898 r->context->state.strokeStyle = style->brush;
899 r->context->buffer()->setStrokeStyle(style->brush);
902 } else if (value->IsString()) {
903 QColor color = qt_color_from_string(engine->toString(value));
904 if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
905 r->context->state.strokeStyle = QBrush(color);
906 r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
912 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
913 Returns a CanvasGradient object that represents a linear gradient that paints along the line given by the coordinates
914 represented by the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
915 \sa QtQuick2::Context2D::createRadialGradient
916 \sa QtQuick2::Context2D::createPattern
917 \sa QtQuick2::Context2D::fillStyle
918 \sa QtQuick2::Context2D::strokeStyle
921 static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
923 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
927 QV8Engine *engine = V8ENGINE();
929 if (args.Length() == 4) {
930 //TODO:infinite or NaN, the method must raise a NOT_SUPPORTED_ERR
931 QSGContext2DEngineData *ed = engineData(engine);
932 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
933 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
934 r->brush = QLinearGradient(args[0]->NumberValue(),
935 args[1]->NumberValue(),
936 args[2]->NumberValue(),
937 args[3]->NumberValue());
938 gradient->SetExternalResource(r);
946 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
947 Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
948 origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
950 \sa QtQuick2::Context2D::createLinearGradient
951 \sa QtQuick2::Context2D::createPattern
952 \sa QtQuick2::Context2D::fillStyle
953 \sa QtQuick2::Context2D::strokeStyle
956 static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
958 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
962 QV8Engine *engine = V8ENGINE();
964 if (args.Length() == 6) {
965 QSGContext2DEngineData *ed = engineData(engine);
966 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
967 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
969 qreal x0 = args[0]->NumberValue();
970 qreal y0 = args[1]->NumberValue();
971 qreal r0 = args[2]->NumberValue();
972 qreal x1 = args[3]->NumberValue();
973 qreal y1 = args[4]->NumberValue();
974 qreal r1 = args[5]->NumberValue();
975 //TODO:infinite or NaN, a NOT_SUPPORTED_ERR exception must be raised.
976 //If either of r0 or r1 are negative, an INDEX_SIZE_ERR exception must be raised.
977 r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
978 gradient->SetExternalResource(r);
986 \qmlmethod variant createPattern(Image image, string repetition)
987 Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
989 The \a image parameter must be a valid Image item, if there is no image data, throws an INVALID_STATE_ERR exception.
991 The allowed values for \a repetition are:
994 \o "repeat" - both directions
995 \o "repeat-x - horizontal only
996 \o "repeat-y" - vertical only
997 \o "no-repeat" - neither
1000 If the repetition argument is empty or null, the value "repeat" is used.
1002 \sa QtQuick2::Context2D::strokeStyle
1003 \sa QtQuick2::Context2D::fillStyle
1005 static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
1007 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1011 QV8Engine *engine = V8ENGINE();
1013 if (args.Length() == 2) {
1014 QSGContext2DEngineData *ed = engineData(engine);
1015 v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
1016 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1020 QSGItem* item = qobject_cast<QSGItem*>(engine->toQObject(args[0]));
1022 img = qt_item_to_image(item);
1023 // if (img.isNull()) {
1024 // //exception: INVALID_STATE_ERR
1027 //exception: TYPE_MISMATCH_ERR
1030 QString repetition = engine->toString(args[1]);
1032 // if (repetition == "repeat" || repetition.isEmpty()) {
1034 // } else if (repetition == "repeat-x") {
1036 // } else if (repetition == "repeat-y") {
1038 // } else if (repetition == "no-repeat") {
1041 // //TODO: exception: SYNTAX_ERR
1044 pattern->SetExternalResource(r);
1052 \qmlproperty string QtQuick2::Context2D::lineCap
1053 Holds the the current line cap style.
1054 The possible line cap styles are:
1056 \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.
1057 \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.
1058 \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.
1060 Other values are ignored.
1062 v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
1064 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1068 QV8Engine *engine = V8ENGINE_ACCESSOR();
1069 switch (r->context->state.lineCap) {
1071 return engine->toString(QLatin1String("round"));
1073 return engine->toString(QLatin1String("butt"));
1075 return engine->toString(QLatin1String("square"));
1079 return engine->toString(QLatin1String("butt"));;
1082 static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1084 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1085 CHECK_CONTEXT_SETTER(r)
1087 QV8Engine *engine = V8ENGINE_ACCESSOR();
1089 QString lineCap = engine->toString(value);
1090 Qt::PenCapStyle cap;
1091 if (lineCap == QLatin1String("round"))
1093 else if (lineCap == QLatin1String("butt"))
1095 else if (lineCap == QLatin1String("square"))
1096 cap = Qt::SquareCap;
1098 if (cap != r->context->state.lineCap) {
1099 r->context->state.lineCap = cap;
1100 r->context->buffer()->setLineCap(cap);
1105 \qmlproperty string QtQuick2::Context2D::lineJoin
1106 Holds the the current line join style. A join exists at any point in a subpath
1107 shared by two consecutive lines. When a subpath is closed, then a join also exists
1108 at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
1110 The possible line join styles are:
1112 \o bevel - this is all that is rendered at joins.
1113 \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.
1114 \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.
1116 Other values are ignored.
1118 v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
1120 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1124 QV8Engine *engine = V8ENGINE_ACCESSOR();
1125 switch (r->context->state.lineJoin) {
1127 return engine->toString(QLatin1String("round"));
1129 return engine->toString(QLatin1String("bevel"));
1131 return engine->toString(QLatin1String("miter"));
1135 return engine->toString(QLatin1String("miter"));
1138 static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1140 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1141 CHECK_CONTEXT_SETTER(r)
1143 QV8Engine *engine = V8ENGINE_ACCESSOR();
1145 QString lineJoin = engine->toString(value);
1146 Qt::PenJoinStyle join;
1147 if (lineJoin == QLatin1String("round"))
1148 join = Qt::RoundJoin;
1149 else if (lineJoin == QLatin1String("bevel"))
1150 join = Qt::BevelJoin;
1151 else if (lineJoin == QLatin1String("miter"))
1152 join = Qt::MiterJoin;
1154 if (join != r->context->state.lineJoin) {
1155 r->context->state.lineJoin = join;
1156 r->context->buffer()->setLineJoin(join);
1161 \qmlproperty real QtQuick2::Context2D::lineWidth
1162 Holds the the current line width. Values that are not finite values greater than zero are ignored.
1164 v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
1166 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1170 return v8::Number::New(r->context->state.lineWidth);
1173 static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1175 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1176 CHECK_CONTEXT_SETTER(r)
1178 qreal w = value->NumberValue();
1180 if (w > 0 && w != r->context->state.lineWidth) {
1181 r->context->state.lineWidth = w;
1182 r->context->buffer()->setLineWidth(w);
1187 \qmlproperty real QtQuick2::Context2D::miterLimit
1188 Holds the current miter limit ratio.
1189 The default miter limit value is 10.0.
1191 v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
1193 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1197 return v8::Number::New(r->context->state.miterLimit);
1200 static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1202 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1203 CHECK_CONTEXT_SETTER(r)
1205 qreal ml = value->NumberValue();
1207 if (ml > 0 && ml != r->context->state.miterLimit) {
1208 r->context->state.miterLimit = ml;
1209 r->context->buffer()->setMiterLimit(ml);
1215 \qmlproperty real QtQuick2::Context2D::shadowBlur
1216 Holds the current level of blur applied to shadows
1218 v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
1220 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1224 return v8::Number::New(r->context->state.shadowBlur);
1227 static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1229 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1230 CHECK_CONTEXT_SETTER(r)
1231 qreal blur = value->NumberValue();
1233 if (blur > 0 && blur != r->context->state.shadowBlur) {
1234 r->context->state.shadowBlur = blur;
1235 r->context->buffer()->setShadowBlur(blur);
1240 \qmlproperty string QtQuick2::Context2D::shadowColor
1241 Holds the current shadow color.
1243 v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
1245 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1249 QV8Engine *engine = V8ENGINE_ACCESSOR();
1251 return engine->toString(r->context->state.shadowColor.name());
1254 static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1256 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1257 CHECK_CONTEXT_SETTER(r)
1259 QV8Engine *engine = V8ENGINE_ACCESSOR();
1261 QColor color = qt_color_from_string(engine->toString(value));
1263 if (color.isValid() && color != r->context->state.shadowColor) {
1264 r->context->state.shadowColor = color;
1265 r->context->buffer()->setShadowColor(color);
1271 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
1272 Holds the current shadow offset in the positive horizontal distance.
1274 \sa QtQuick2::Context2D::shadowOffsetY
1276 v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
1278 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1282 return v8::Number::New(r->context->state.shadowOffsetX);
1285 static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1287 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1288 CHECK_CONTEXT_SETTER(r)
1290 //TODO: check value:infinite or NaN
1291 qreal offsetX = value->NumberValue();
1292 if (offsetX != r->context->state.shadowOffsetX) {
1293 r->context->state.shadowOffsetX = offsetX;
1294 r->context->buffer()->setShadowOffsetX(offsetX);
1298 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
1299 Holds the current shadow offset in the positive vertical distance.
1301 \sa QtQuick2::Context2D::shadowOffsetX
1303 v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
1305 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1309 return v8::Number::New(r->context->state.shadowOffsetY);
1312 static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1314 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1315 CHECK_CONTEXT_SETTER(r)
1316 //TODO: check value:infinite or NaN
1317 qreal offsetY = value->NumberValue();
1318 if (offsetY != r->context->state.shadowOffsetY) {
1319 r->context->state.shadowOffsetY = offsetY;
1320 r->context->buffer()->setShadowOffsetY(offsetY);
1324 v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
1326 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1328 return r->context->m_v8path;
1331 static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1333 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1334 CHECK_CONTEXT_SETTER(r)
1335 QV8Engine *engine = V8ENGINE_ACCESSOR();
1337 r->context->beginPath();
1338 if (value->IsObject()) {
1339 QDeclarativePath* path = qobject_cast<QDeclarativePath*>(engine->toQObject(value));
1341 r->context->m_path = path->path();
1343 QString path = engine->toString(value->ToString());
1344 QDeclarativeSvgParser::parsePathDataFast(path, r->context->m_path);
1346 r->context->m_v8path = value;
1351 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
1352 Clears all pixels on the canvas in the given rectangle to transparent black.
1354 static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
1356 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1360 if (args.Length() == 4) {
1361 r->context->buffer()->clearRect(args[0]->NumberValue(),
1362 args[1]->NumberValue(),
1363 args[2]->NumberValue(),
1364 args[3]->NumberValue());
1370 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1371 Paint the specified rectangular area using the fillStyle.
1373 \sa QtQuick2::Context2D::fillStyle
1375 static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
1377 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1381 if (args.Length() == 4) {
1382 r->context->buffer()->fillRect(args[0]->NumberValue(),
1383 args[1]->NumberValue(),
1384 args[2]->NumberValue(),
1385 args[3]->NumberValue());
1392 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1393 Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
1394 and (if appropriate) miterLimit attributes.
1396 \sa QtQuick2::Context2D::strokeStyle
1397 \sa QtQuick2::Context2D::lineWidth
1398 \sa QtQuick2::Context2D::lineJoin
1399 \sa QtQuick2::Context2D::miterLimit
1401 static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
1403 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1407 if (args.Length() == 4) {
1408 r->context->buffer()->strokeRect(args[0]->NumberValue(),
1409 args[1]->NumberValue(),
1410 args[2]->NumberValue(),
1411 args[3]->NumberValue());
1417 // Complex shapes (paths) API
1419 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
1420 Adds points to the subpath such that the arc described by the circumference of
1421 the circle described by the arguments.
1423 See http://www.w3.org/TR/2dcontext/#dom-context-2d-arc for details.
1425 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
1427 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1430 if (args.Length() >= 5) {
1431 bool antiClockwise = false;
1433 if (args.Length() == 6)
1434 antiClockwise = args[5]->BooleanValue();
1436 qreal radius = args[2]->NumberValue();
1437 //Throws an INDEX_SIZE_ERR exception if the given radius is negative.
1438 r->context->arc(args[0]->NumberValue(),
1439 args[1]->NumberValue(),
1441 args[3]->NumberValue(),
1442 args[4]->NumberValue(),
1450 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
1452 Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
1453 See http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto for details.
1455 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
1457 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1461 if (args.Length() == 5) {
1462 r->context->arcTo(args[0]->NumberValue(),
1463 args[1]->NumberValue(),
1464 args[2]->NumberValue(),
1465 args[3]->NumberValue(),
1466 args[4]->NumberValue());
1473 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::beginPath()
1475 Resets the current path.
1477 static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
1479 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1483 r->context->beginPath();
1489 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
1491 Adds the given point to the current subpath, connected to the previous one by a cubic Bézier curve with the given control points.
1493 See http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto for details.
1495 static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
1497 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1501 if (args.Length() == 6) {
1502 r->context->bezierCurveTo(args[0]->NumberValue(),
1503 args[1]->NumberValue(),
1504 args[2]->NumberValue(),
1505 args[3]->NumberValue(),
1506 args[4]->NumberValue(),
1507 args[5]->NumberValue());
1514 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::clip()
1516 constrains the clipping region to the given path.
1518 See http://www.w3.org/TR/2dcontext/#dom-context-2d-clip for details.
1520 static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
1522 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1525 r->context->state.clipPath = r->context->m_path;
1526 r->context->buffer()->clip(r->context->state.clipPath);
1532 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::closePath()
1534 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.
1536 See http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath for details.
1538 static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
1540 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1544 r->context->closePath();
1550 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fill()
1552 Fills the subpaths with the current fill style.
1554 See http://www.w3.org/TR/2dcontext/#dom-context-2d-fill for details.
1556 \sa QtQuick2::Context2D::fillStyle
1558 static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
1560 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1563 r->context->buffer()->fill(r->context->m_path);
1569 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::lineTo(real x, real y)
1571 Adds the given point to the current subpath, connected to the previous one by a straight line.
1573 static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
1575 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1579 if (args.Length() == 2) {
1580 r->context->lineTo(args[0]->NumberValue(),
1581 args[1]->NumberValue());
1588 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::moveTo(real x, real y)
1590 Creates a new subpath with the given point.
1592 static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
1594 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1598 if (args.Length() == 2) {
1599 r->context->moveTo(args[0]->NumberValue(),
1600 args[1]->NumberValue());
1607 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
1609 Adds the given point to the current subpath, connected to the previous one by a quadratic Bézier curve with the given control point.
1611 See http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto for details.
1613 static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
1615 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1619 if (args.Length() == 4) {
1620 r->context->quadraticCurveTo(args[0]->NumberValue(),
1621 args[1]->NumberValue(),
1622 args[2]->NumberValue(),
1623 args[3]->NumberValue());
1630 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::rect(real x, real y, real w, real h)
1632 Adds a new closed subpath to the path, representing the given rectangle.
1634 See http://www.w3.org/TR/2dcontext/#dom-context-2d-rect for details.
1636 static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
1638 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1642 if (args.Length() == 4) {
1643 r->context->rect(args[0]->NumberValue(),
1644 args[1]->NumberValue(),
1645 args[2]->NumberValue(),
1646 args[3]->NumberValue());
1653 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::roundedRect(real x, real y, real w, real h, real xRadius, real yRadius)
1655 Adds the given rectangle rect with rounded corners to the path. The xRadius and yRadius arguments specify the radii of the
1656 ellipses defining the corners of the rounded rectangle.
1658 static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
1660 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1664 if (args.Length() == 6) {
1665 r->context->roundedRect(args[0]->NumberValue(),
1666 args[1]->NumberValue(),
1667 args[2]->NumberValue(),
1668 args[3]->NumberValue(),
1669 args[4]->NumberValue(),
1670 args[5]->NumberValue());
1677 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
1679 Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
1680 and adds it to the path as a closed subpath.
1682 The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
1684 static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
1686 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1690 if (args.Length() == 6) {
1691 r->context->ellipse(args[0]->NumberValue(),
1692 args[1]->NumberValue(),
1693 args[2]->NumberValue(),
1694 args[3]->NumberValue());
1701 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::text(string text, real x, real y)
1703 Adds the given \a text to the path as a set of closed subpaths created from the current context font supplied.
1704 The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (x, y).
1706 static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
1708 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1711 QV8Engine *engine = V8ENGINE();
1712 if (args.Length() == 3) {
1713 r->context->text(engine->toString(args[0]),
1714 args[1]->NumberValue(),
1715 args[2]->NumberValue());
1722 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::stroke()
1724 Strokes the subpaths with the current stroke style.
1726 See http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke for details.
1728 \sa QtQuick2::Context2D::strokeStyle
1730 static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
1732 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1736 r->context->buffer()->stroke(r->context->m_path);
1742 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::isPointInPath(real x, real y)
1744 Returns true if the given point is in the current path.
1746 See http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath for details.
1748 static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
1750 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1754 bool pointInPath = false;
1755 if (args.Length() == 2) {
1756 pointInPath = r->context->isPointInPath(args[0]->NumberValue(),
1757 args[1]->NumberValue());
1760 return v8::Boolean::New(pointInPath);
1763 static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
1765 V8THROW_ERROR("Context2D::drawFocusRing is not supported")
1769 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
1771 V8THROW_ERROR("Context2D::setCaretSelectionRect is not supported")
1775 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
1777 V8THROW_ERROR("Context2D::caretBlinkRate is not supported")
1783 \qmlproperty string QtQuick2::Context2D::font
1784 Holds the current font settings, default value is "10px sans-serif".
1786 See http://www.w3.org/TR/2dcontext/#dom-context-2d-font for details.
1788 v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
1790 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1793 QV8Engine *engine = V8ENGINE_ACCESSOR();
1795 return engine->toString(r->context->m_fontString);
1798 static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1800 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1801 CHECK_CONTEXT_SETTER(r)
1803 QV8Engine *engine = V8ENGINE_ACCESSOR();
1804 QString fs = engine->toString(value);
1805 if (fs != r->context->m_fontString) {
1806 r->context->m_fontString = fs;
1807 QFont font = qt_font_from_string(fs);
1808 r->context->state.font = font;
1813 \qmlproperty string QtQuick2::Context2D::textAlign
1815 Holds the current text alignment settings.
1816 The possible values are:
1824 Other values are ignored. The default is start.
1826 v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
1828 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1830 QV8Engine *engine = V8ENGINE_ACCESSOR();
1831 switch (r->context->state.textAlign) {
1832 case QSGContext2D::Start:
1833 return engine->toString(QLatin1String("start"));
1834 case QSGContext2D::End:
1835 return engine->toString(QLatin1String("end"));
1836 case QSGContext2D::Left:
1837 return engine->toString(QLatin1String("left"));
1838 case QSGContext2D::Right:
1839 return engine->toString(QLatin1String("right"));
1840 case QSGContext2D::Center:
1841 return engine->toString(QLatin1String("center"));
1845 return engine->toString(QLatin1String("start"));
1848 static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1850 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1851 CHECK_CONTEXT_SETTER(r)
1852 QV8Engine *engine = V8ENGINE_ACCESSOR();
1854 QString textAlign = engine->toString(value);
1856 QSGContext2D::TextAlignType ta;
1857 if (textAlign == QLatin1String("start"))
1858 ta = QSGContext2D::Start;
1859 else if (textAlign == QLatin1String("end"))
1860 ta = QSGContext2D::End;
1861 else if (textAlign == QLatin1String("left"))
1862 ta = QSGContext2D::Left;
1863 else if (textAlign == QLatin1String("right"))
1864 ta = QSGContext2D::Right;
1865 else if (textAlign == QLatin1String("center"))
1866 ta = QSGContext2D::Center;
1868 if (ta != r->context->state.textAlign) {
1869 r->context->state.textAlign = ta;
1874 \qmlproperty string QtQuick2::Context2D::textBaseline
1876 Holds the current baseline alignment settings.
1877 The possible values are:
1886 Other values are ignored. The default value is "alphabetic".
1887 See http://www.w3.org/TR/2dcontext/#dom-context-2d-textbaseline for details.
1889 v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
1891 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1894 QV8Engine *engine = V8ENGINE_ACCESSOR();
1895 switch (r->context->state.textBaseline) {
1896 case QSGContext2D::Alphabetic:
1897 return engine->toString(QLatin1String("alphabetic"));
1898 case QSGContext2D::Hanging:
1899 return engine->toString(QLatin1String("hanging"));
1900 case QSGContext2D::Top:
1901 return engine->toString(QLatin1String("top"));
1902 case QSGContext2D::Bottom:
1903 return engine->toString(QLatin1String("bottom"));
1904 case QSGContext2D::Middle:
1905 return engine->toString(QLatin1String("middle"));
1909 return engine->toString(QLatin1String("alphabetic"));
1912 static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1914 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1915 CHECK_CONTEXT_SETTER(r)
1916 QV8Engine *engine = V8ENGINE_ACCESSOR();
1917 QString textBaseline = engine->toString(value);
1919 QSGContext2D::TextBaseLineType tb;
1920 if (textBaseline == QLatin1String("alphabetic"))
1921 tb = QSGContext2D::Alphabetic;
1922 else if (textBaseline == QLatin1String("hanging"))
1923 tb = QSGContext2D::Hanging;
1924 else if (textBaseline == QLatin1String("top"))
1925 tb = QSGContext2D::Top;
1926 else if (textBaseline == QLatin1String("bottom"))
1927 tb = QSGContext2D::Bottom;
1928 else if (textBaseline == QLatin1String("middle"))
1929 tb = QSGContext2D::Middle;
1931 if (tb != r->context->state.textBaseline) {
1932 r->context->state.textBaseline = tb;
1937 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillText(text, x, y)
1938 Fills the given text at the given position.
1939 See http://www.w3.org/TR/2dcontext/#dom-context-2d-filltext for details.
1941 static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
1943 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1947 QV8Engine *engine = V8ENGINE();
1949 if (args.Length() == 3) {
1950 QPainterPath textPath = r->context->createTextGlyphs(args[1]->NumberValue(),
1951 args[2]->NumberValue(),
1952 engine->toString(args[0]));
1953 r->context->buffer()->fill(textPath);
1959 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::strokeText(text, x, y)
1960 Strokes the given text at the given position.
1961 See http://www.w3.org/TR/2dcontext/#dom-context-2d-stroketext for details.
1963 static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
1965 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1969 QV8Engine *engine = V8ENGINE();
1971 if (args.Length() == 3) {
1972 QPainterPath textPath = r->context->createTextGlyphs(args[1]->NumberValue(),
1973 args[2]->NumberValue(),
1974 engine->toString(args[0]));
1975 r->context->buffer()->stroke(textPath);
1981 \qmlclass QtQuick2::TextMetrics
1982 \inqmlmodule QtQuick 2
1984 \brief The Context2D TextMetrics interface.
1985 The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
1986 See http://www.w3.org/TR/2dcontext/#textmetrics for more details.
1988 \sa QtQuick2::Context2D::measureText
1989 \sa QtQuick2::TextMetrics::width
1993 \qmlproperty int QtQuick2::TextMetrics::width
1994 Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
1995 This property is read only.
1996 See http://www.w3.org/TR/2dcontext/#dom-textmetrics-width for more details.
2000 \qmlmethod variant QtQuick2::Context2D::measureText(text)
2001 Returns a TextMetrics object with the metrics of the given text in the current font.
2002 See http://www.w3.org/TR/2dcontext/#dom-context-2d-measuretext for details.
2004 static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
2006 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2010 QV8Engine *engine = V8ENGINE();
2012 if (args.Length() == 1) {
2013 QFontMetrics fm(r->context->state.font);
2014 uint width = fm.width(engine->toString(args[0]));
2015 v8::Local<v8::Object> tm = v8::Object::New();
2016 tm->Set(v8::String::New("width"), v8::Number::New(width));
2020 return v8::Undefined();
2025 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
2026 Draws the given \a image on the canvas at position (\a dx, \a dy).
2028 The \a image type can be an Image item or a image url. When given as Image
2029 type, if the image isn't fully loaded, will draw nothing. When given as url string,
2030 the context loads the image asynchorously and redraw the canvas when the image is loaded.
2032 See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
2035 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
2036 Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
2038 See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
2041 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
2042 Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
2043 onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
2044 See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
2046 static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
2048 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2052 QV8Engine *engine = V8ENGINE();
2054 //TODO: handle exceptions
2056 qreal sx, sy, sw, sh, dx, dy, dw, dh;
2058 if (args.Length() != 3 && args.Length() != 5 && args.Length() != 9) {
2065 if (args[0]->IsString()) {
2066 image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2067 } /*else if (args[0]->IsObject()) {
2068 QSGImage* imageItem = qobject_cast<QSGImage*>(engine->toQObject(args[0]->ToObject()));
2070 image = imageItem->pixmap().toImage();
2076 if (args.Length() == 3) {
2077 dx = args[1]->NumberValue();
2078 dy = args[2]->NumberValue();
2081 sw = image.isNull()? -1 : image.width();
2082 sh = image.isNull()? -1 : image.height();
2085 } else if (args.Length() == 5) {
2088 sw = image.isNull()? -1 : image.width();
2089 sh = image.isNull()? -1 : image.height();
2090 dx = args[1]->NumberValue();
2091 dy = args[2]->NumberValue();
2092 dw = args[3]->NumberValue();
2093 dh = args[4]->NumberValue();
2094 } else if (args.Length() == 9) {
2095 sx = args[1]->NumberValue();
2096 sy = args[2]->NumberValue();
2097 sw = args[3]->NumberValue();
2098 sh = args[4]->NumberValue();
2099 dx = args[5]->NumberValue();
2100 dy = args[6]->NumberValue();
2101 dw = args[7]->NumberValue();
2102 dh = args[8]->NumberValue();
2108 r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
2113 // pixel manipulation
2115 \qmlclass QtQuick2::CanvasImageData
2119 \qmlproperty QtQuick2::CanvasImageData::width
2120 Holds the actual width dimension of the data in the ImageData object, in device pixels.
2122 v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
2124 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2126 return v8::Integer::New(0);
2127 return v8::Integer::New(r->image.width());
2131 \qmlproperty QtQuick2::CanvasImageData::height
2132 Holds the actual height dimension of the data in the ImageData object, in device pixels.
2134 v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
2136 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2138 return v8::Integer::New(0);
2140 return v8::Integer::New(r->image.height());
2144 \qmlproperty QtQuick2::CanvasImageData::data
2145 Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
2147 v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
2149 return args.This()->GetInternalField(0);
2152 static v8::Handle<v8::Value> ctx2d_imageData_mirror(const v8::Arguments &args)
2154 bool horizontal = false, vertical = true;
2155 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2159 return v8::Undefined();
2162 if (args.Length() > 2) {
2164 return v8::Undefined();
2167 if (args.Length() == 1) {
2168 horizontal = args[0]->BooleanValue();
2169 } else if (args.Length() == 2) {
2170 horizontal = args[0]->BooleanValue();
2171 vertical = args[1]->BooleanValue();
2175 // blur the alpha channel
2176 if (state.shadowBlur > 0) {
2177 QImage blurred(shadowImg.size(), QImage::Format_ARGB32);
2179 QPainter blurPainter(&blurred);
2180 qt_blurImage(&blurPainter, shadowImg, state.shadowBlur, false, true);
2182 shadowImg = blurred;
2186 r->image = r->image.mirrored(horizontal, vertical);
2191 static v8::Handle<v8::Value> ctx2d_imageData_filter(const v8::Arguments &args)
2193 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2197 return v8::Undefined();
2200 if (args.Length() >= 1) {
2201 int filterFlag = args[0]->IntegerValue();
2202 switch(filterFlag) {
2203 case QSGCanvasItem::GrayScale :
2205 for (int y = 0; y < r->image.height(); ++y) {
2206 QRgb *row = (QRgb*)r->image.scanLine(y);
2207 for (int x = 0; x < r->image.width(); ++x) {
2208 unsigned char* rgb = ((unsigned char*)&row[x]);
2209 rgb[0] = rgb[1] = rgb[2] = qGray(rgb[0], rgb[1], rgb[2]);
2214 case QSGCanvasItem::Threshold :
2216 int threshold = 127;
2217 if (args.Length() > 1)
2218 threshold = args[1]->IntegerValue();
2220 for (int y = 0; y < r->image.height(); ++y) {
2221 QRgb *row = (QRgb*)r->image.scanLine(y);
2222 for (int x = 0; x < r->image.width(); ++x) {
2223 unsigned char* rgb = ((unsigned char*)&row[x]);
2224 unsigned char v = qGray(rgb[0], rgb[1], rgb[2]) >= threshold ? 255 : 0;
2225 rgb[0] = rgb[1] = rgb[2] = v;
2230 case QSGCanvasItem::Brightness :
2233 if (args.Length() > 1)
2234 adjustment = args[1]->IntegerValue();
2236 for (int y = 0; y < r->image.height(); ++y) {
2237 QRgb *row = (QRgb*)r->image.scanLine(y);
2238 for (int x = 0; x < r->image.width(); ++x) {
2239 ((unsigned char*)&row[x])[0] += adjustment;
2240 ((unsigned char*)&row[x])[1] += adjustment;
2241 ((unsigned char*)&row[x])[2] += adjustment;
2246 case QSGCanvasItem::Invert :
2248 r->image.invertPixels();
2251 case QSGCanvasItem::Blur :
2253 QImage blurred(r->image.size(), QImage::Format_ARGB32);
2255 if (args.Length() > 1)
2256 blur = args[1]->NumberValue();
2258 blurred.fill(Qt::transparent);
2259 QPainter blurPainter(&blurred);
2261 qt_blurImage(&blurPainter, r->image, blur, true, false);
2267 case QSGCanvasItem::Opaque :
2269 for (int y = 0; y < r->image.height(); ++y) {
2270 QRgb *row = (QRgb*)r->image.scanLine(y);
2271 for (int x = 0; x < r->image.width(); ++x) {
2272 ((unsigned char*)&row[x])[3] = 255;
2277 case QSGCanvasItem::Convolute :
2279 if (args.Length() > 1 && args[1]->IsArray()) {
2280 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(args[1]);
2281 QVector<int> weights;
2282 for (uint32_t i = 0; i < array->Length(); ++i)
2283 weights.append(array->Get(i)->NumberValue());
2284 int sides = qRound(qSqrt(weights.size()));
2285 int half = qFloor(sides/2);
2287 QImage image = QImage(r->image.size(), QImage::Format_ARGB32);
2288 int w = r->image.width();
2289 int h = r->image.height();
2290 for (int y = 0; y < image.height(); ++y) {
2291 QRgb *dRow = (QRgb*)image.scanLine(y);
2292 for (int x = 0; x < image.width(); ++x) {
2293 unsigned char* dRgb = ((unsigned char*)&dRow[x]);
2294 unsigned char red=0, green=0, blue=0, alpha=0;
2298 for (int cy=0; cy<sides; cy++) {
2299 for (int cx=0; cx<sides; cx++) {
2300 int scy = sy + cy - half;
2301 int scx = sx + cx - half;
2302 if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
2303 QRgb *sRow = (QRgb*)(r->image.scanLine(scy));
2304 unsigned char* sRgb = ((unsigned char*)&sRow[scx]);
2305 int wt = weights[cy*sides+cx];
2306 red += sRgb[0] * wt;
2307 green += sRgb[1] * wt;
2308 blue += sRgb[2] * wt;
2309 alpha += sRgb[3] * wt;
2333 \qmlclass QtQuick2::CanvasPixelArray
2334 The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
2335 See http://www.w3.org/TR/2dcontext/#canvaspixelarray for more details.
2339 \qmlproperty QtQuick2::CanvasPixelArray::length
2340 The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
2341 The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
2343 v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
2345 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2346 if (!r || r->image.isNull()) return v8::Undefined();
2348 return v8::Integer::New(r->image.width() * r->image.height() * 4);
2351 v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
2353 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2355 if (r && index && index < r->image.width() * r->image.height() * 4) {
2356 const int w = r->image.width();
2357 const int h = r->image.height();
2358 const int row = (index / 4) / w;
2359 const int col = (index / 4) % w;
2360 const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
2362 switch (index % 4) {
2364 return v8::Integer::New(qRed(*pixel));
2366 return v8::Integer::New(qGreen(*pixel));
2368 return v8::Integer::New(qBlue(*pixel));
2370 return v8::Integer::New(qAlpha(*pixel));
2373 return v8::Undefined();
2376 v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
2378 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
2380 const int v = value->Uint32Value();
2381 if (r && index > 0 && index < r->image.width() * r->image.height() * 4 && v > 0 && v <= 255) {
2382 const int w = r->image.width();
2383 const int h = r->image.height();
2384 const int row = (index / 4) / w;
2385 const int col = (index / 4) % w;
2387 QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
2389 switch (index % 4) {
2391 *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
2394 *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
2397 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
2400 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
2404 return v8::Undefined();
2407 \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
2408 Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
2411 \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
2412 Creates a CanvasImageData object with the same dimensions as the argument.
2415 \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
2416 Creates a CanvasImageData object with the given image loaded from \a imageUrl.
2417 Note:The \a imageUrl must be already loaded before this function call, if not, an empty
2418 CanvasImageData obect will be returned.
2420 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
2422 static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
2424 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2428 QV8Engine *engine = V8ENGINE();
2430 if (args.Length() == 1) {
2431 if (args[0]->IsObject()) {
2432 v8::Local<v8::Object> imgData = args[0]->ToObject();
2433 QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
2435 qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
2436 qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
2437 return qt_create_image_data(w, h, engine, QImage());
2439 } else if (args[0]->IsString()) {
2440 QImage image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2441 return qt_create_image_data(image.width(), image.height(), engine, image);
2443 } else if (args.Length() == 2) {
2444 qreal w = args[0]->NumberValue();
2445 qreal h = args[1]->NumberValue();
2447 return qt_create_image_data(w, h, engine, QImage());
2449 return v8::Undefined();
2453 \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
2454 Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
2456 static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
2458 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2461 QV8Engine *engine = V8ENGINE();
2462 if (args.Length() == 4) {
2463 qreal x = args[0]->NumberValue();
2464 qreal y = args[1]->NumberValue();
2465 qreal w = args[2]->NumberValue();
2466 qreal h = args[3]->NumberValue();
2467 QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
2468 if (image.format() != QImage::Format_ARGB32)
2469 image = image.convertToFormat(QImage::Format_ARGB32);
2470 v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
2478 \qmlmethod QtQuick2::Context2D putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
2479 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.
2481 static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
2483 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2485 if (args.Length() != 3 && args.Length() != 7)
2486 return v8::Undefined();
2488 if (args[0]->IsNull() || !args[0]->IsObject()) {
2489 V8THROW_ERROR("Context2D::putImageData, the image data type mismatch");
2491 qreal dx = args[1]->NumberValue();
2492 qreal dy = args[2]->NumberValue();
2493 qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
2495 v8::Local<v8::Object> imageData = args[0]->ToObject();
2496 QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
2498 w = imageData->Get(v8::String::New("width"))->NumberValue();
2499 h = imageData->Get(v8::String::New("height"))->NumberValue();
2501 if (args.Length() == 7) {
2502 dirtyX = args[3]->NumberValue();
2503 dirtyY = args[4]->NumberValue();
2504 dirtyWidth = args[5]->NumberValue();
2505 dirtyHeight = args[6]->NumberValue();
2506 if (dirtyWidth < 0) {
2507 dirtyX = dirtyX+dirtyWidth;
2508 dirtyWidth = -dirtyWidth;
2511 if (dirtyHeight < 0) {
2512 dirtyY = dirtyY+dirtyHeight;
2513 dirtyHeight = -dirtyHeight;
2517 dirtyWidth = dirtyWidth+dirtyX;
2522 dirtyHeight = dirtyHeight+dirtyY;
2526 if (dirtyX+dirtyWidth > w) {
2527 dirtyWidth = w - dirtyX;
2530 if (dirtyY+dirtyHeight > h) {
2531 dirtyHeight = h - dirtyY;
2534 if (dirtyWidth <=0 || dirtyHeight <= 0)
2543 QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2544 r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
2550 \qmlclass QtQuick2::CanvasGradient
2551 \inqmlmodule QtQuick 2
2553 \brief The Context2D opaque CanvasGradient interface.
2557 \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
2558 Adds a color stop with the given color to the gradient at the given offset.
2559 0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
2561 static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
2563 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
2565 V8THROW_ERROR("Not a CanvasGradient object");
2567 QV8Engine *engine = V8ENGINE();
2569 if (args.Length() == 2) {
2571 if (!style->brush.gradient())
2572 V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
2573 QGradient gradient = *(style->brush.gradient());
2574 qreal pos = args[0]->NumberValue();
2575 QColor color = qt_color_from_string(engine->toString(args[1]));
2576 if (pos < 0.0 || pos > 1.0) {
2577 //Throws an INDEX_SIZE_ERR exception
2578 V8THROW_ERROR("CanvasGradient: parameter offset out of range");
2581 if (color.isValid()) {
2582 gradient.setColorAt(pos, color);
2584 //Throws a SYNTAX_ERR exception
2585 V8THROW_ERROR("CanvasGradient: parameter color is not a valid color string");
2587 style->brush = gradient;
2594 void QSGContext2D::beginPath()
2596 m_path = QPainterPath();
2597 m_path.setFillRule(state.fillRule);
2600 void QSGContext2D::closePath()
2602 if (m_path.isEmpty())
2605 QRectF boundRect = m_path.boundingRect();
2606 if (boundRect.width() || boundRect.height())
2607 m_path.closeSubpath();
2610 void QSGContext2D::moveTo( qreal x, qreal y)
2612 m_path.moveTo(state.matrix.map(QPointF(x, y)));
2615 void QSGContext2D::lineTo( qreal x, qreal y)
2617 m_path.lineTo(state.matrix.map(QPointF(x, y)));
2620 void QSGContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
2623 m_path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
2624 state.matrix.map(QPointF(x, y)));
2627 void QSGContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
2628 qreal cp2x, qreal cp2y,
2631 m_path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
2632 state.matrix.map(QPointF(cp2x, cp2y)),
2633 state.matrix.map(QPointF(x, y)));
2636 void QSGContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
2638 QPointF p0(m_path.currentPosition());
2640 QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
2641 QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
2642 float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
2643 float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
2645 double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
2647 // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
2648 // We could have used areCollinear() here, but since we're reusing
2649 // the variables computed above later on we keep this logic.
2650 if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
2655 float tangent = radius / tan(acos(cos_phi) / 2);
2656 float factor_p1p0 = tangent / p1p0_length;
2657 QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
2659 QPointF orth_p1p0(p1p0.y(), -p1p0.x());
2660 float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
2661 float factor_ra = radius / orth_p1p0_length;
2663 // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
2664 double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
2665 if (cos_alpha < 0.f)
2666 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
2668 QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
2670 // calculate angles for addArc
2671 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
2672 float sa = acos(orth_p1p0.x() / orth_p1p0_length);
2673 if (orth_p1p0.y() < 0.f)
2676 // anticlockwise logic
2677 bool anticlockwise = false;
2679 float factor_p1p2 = tangent / p1p2_length;
2680 QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
2681 QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
2682 float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
2683 float ea = acos(orth_p1p2.x() / orth_p1p2_length);
2684 if (orth_p1p2.y() < 0)
2686 if ((sa > ea) && ((sa - ea) < Q_PI))
2687 anticlockwise = true;
2688 if ((sa < ea) && ((ea - sa) > Q_PI))
2689 anticlockwise = true;
2691 arc(p.x(), p.y(), radius, sa, ea, anticlockwise, false);
2694 void QSGContext2D::arcTo(qreal x1, qreal y1,
2698 QPointF st = state.matrix.map(QPointF(x1, y1));
2699 QPointF end = state.matrix.map(QPointF(x2, y2));
2701 if (!m_path.elementCount()) {
2703 } else if (st == m_path.currentPosition() || st == end || !radius) {
2706 addArcTo(st, end, radius);
2710 void QSGContext2D::rect(qreal x, qreal y,
2713 m_path.addPolygon(state.matrix.map(QRectF(x, y, w, h)));
2716 void QSGContext2D::roundedRect(qreal x, qreal y,
2721 path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
2722 m_path.addPath(state.matrix.map(path));
2725 void QSGContext2D::ellipse(qreal x, qreal y,
2729 path.addEllipse(x, y, w, h);
2730 m_path.addPath(state.matrix.map(path));
2733 void QSGContext2D::text(const QString& str, qreal x, qreal y)
2736 path.addText(x, y, state.font, str);
2737 m_path.addPath(state.matrix.map(path));
2740 void QSGContext2D::arc(qreal xc,
2750 QPointF point = state.matrix.map(QPointF(xc, yc));
2756 // In Qt we don't switch the coordinate system for degrees
2757 // and still use the 0,0 as bottom left for degrees so we need
2761 antiClockWise = !antiClockWise;
2764 float sa = DEGREES(sar);
2765 float ea = DEGREES(ear);
2769 double xs = xc - radius;
2770 double ys = yc - radius;
2771 double width = radius*2;
2772 double height = radius*2;
2773 if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
2774 // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
2775 // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
2776 // circumference of this circle.
2779 if (!antiClockWise && (ea < sa)) {
2781 } else if (antiClockWise && (sa < ea)) {
2784 //### this is also due to switched coordinate system
2785 // we would end up with a 0 span instead of 360
2786 if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
2787 qFuzzyCompare(qAbs(span), 360))) {
2790 if (!m_path.elementCount())
2791 m_path.moveTo(xs, ys);
2796 QPointF currentPos = m_path.currentPosition();
2797 QPointF startPos = QPointF(xc + radius * qCos(sar),
2798 yc - radius * qSin(sar));
2799 if (currentPos != startPos)
2800 m_path.lineTo(startPos);
2803 m_path.arcTo(xs, ys, width, height, sa, span);
2806 int baseLineOffset(QSGContext2D::TextBaseLineType value, const QFontMetrics &metrics)
2810 case QSGContext2D::QSGContext2D::Top:
2812 case QSGContext2D::QSGContext2D::Alphabetic:
2813 case QSGContext2D::QSGContext2D::Middle:
2814 case QSGContext2D::QSGContext2D::Hanging:
2815 offset = metrics.ascent();
2817 case QSGContext2D::QSGContext2D::Bottom:
2818 offset = metrics.height();
2824 static int textAlignOffset(QSGContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
2827 if (value == QSGContext2D::Start)
2828 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QSGContext2D::Left : QSGContext2D::Right;
2829 else if (value == QSGContext2D::End)
2830 value = QGuiApplication::layoutDirection() == Qt::LeftToRight ? QSGContext2D::Right: QSGContext2D::Left;
2832 case QSGContext2D::QSGContext2D::Center:
2833 offset = metrics.width(text)/2;
2835 case QSGContext2D::QSGContext2D::Right:
2836 offset = metrics.width(text);
2837 case QSGContext2D::QSGContext2D::Left:
2845 QImage QSGContext2D::createImage(const QUrl& url)
2847 return m_canvas->loadedImage(url);
2850 QPainterPath QSGContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
2852 const QFontMetrics metrics(state.font);
2853 int yoffset = baseLineOffset(static_cast<QSGContext2D::TextBaseLineType>(state.textBaseline), metrics);
2854 int xoffset = textAlignOffset(static_cast<QSGContext2D::TextAlignType>(state.textAlign), metrics, text);
2856 QPainterPath textPath;
2858 textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
2859 textPath = state.matrix.map(textPath);
2864 bool QSGContext2D::isPointInPath(qreal x, qreal y) const
2866 return m_path.contains(QPointF(x, y));
2869 QSGContext2D::QSGContext2D(QSGCanvasItem* item)
2871 , m_buffer(new QSGContext2DCommandBuffer)
2877 QSGContext2D::~QSGContext2D()
2881 v8::Handle<v8::Object> QSGContext2D::v8value() const
2886 QSGContext2DEngineData::QSGContext2DEngineData(QV8Engine *engine)
2888 v8::HandleScope handle_scope;
2889 v8::Context::Scope scope(engine->context());
2891 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
2892 ft->InstanceTemplate()->SetHasExternalResource(true);
2893 ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine));
2894 ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine));
2895 ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine));
2896 ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine));
2897 ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine));
2898 ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine));
2899 ft->PrototypeTemplate()->Set(v8::String::New("resetTransform"), V8FUNCTION(ctx2d_resetTransform, engine));
2900 ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine));
2901 ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine));
2902 ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine));
2903 ft->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, engine));
2904 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine));
2905 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine));
2906 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillRule"), ctx2d_fillRule, ctx2d_fillRule_set, v8::External::Wrap(engine));
2907 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine));
2908 ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
2909 ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
2910 ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
2911 ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
2912 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
2913 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
2914 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine));
2915 ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine));
2916 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine));
2917 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine));
2918 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine));
2919 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine));
2920 ft->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_set, v8::External::Wrap(engine));
2921 ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine));
2922 ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine));
2923 ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine));
2924 ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine));
2925 ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine));
2926 ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine));
2927 ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine));
2928 ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine));
2929 ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine));
2930 ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine));
2931 ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine));
2932 ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine));
2933 ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine));
2934 ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine));
2935 ft->PrototypeTemplate()->Set(v8::String::New("roundedRect "), V8FUNCTION(ctx2d_roundedRect, engine));
2936 ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
2937 ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine));
2938 ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine));
2939 ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine));
2940 ft->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
2941 ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
2942 ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, engine));
2943 ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine));
2944 ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine));
2945 ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine));
2946 ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine));
2947 ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine));
2948 ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine));
2949 ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine));
2950 ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine));
2951 ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine));
2952 ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine));
2954 constructorContext = qPersistentNew(ft->GetFunction());
2956 v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
2957 ftGradient->InstanceTemplate()->SetHasExternalResource(true);
2958 ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
2959 constructorGradient = qPersistentNew(ftGradient->GetFunction());
2961 v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
2962 ftPattern->InstanceTemplate()->SetHasExternalResource(true);
2963 constructorPattern = qPersistentNew(ftPattern->GetFunction());
2965 v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
2966 ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
2967 ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
2968 ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
2969 constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
2971 v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
2972 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
2973 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
2974 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
2975 ftImageData->PrototypeTemplate()->Set(v8::String::New("mirror"), V8FUNCTION(ctx2d_imageData_mirror, engine));
2976 ftImageData->PrototypeTemplate()->Set(v8::String::New("filter"), V8FUNCTION(ctx2d_imageData_filter, engine));
2977 ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
2978 constructorImageData = qPersistentNew(ftImageData->GetFunction());
2981 QSGContext2DEngineData::~QSGContext2DEngineData()
2983 qPersistentDispose(constructorContext);
2984 qPersistentDispose(constructorGradient);
2985 qPersistentDispose(constructorPattern);
2986 qPersistentDispose(constructorImageData);
2987 qPersistentDispose(constructorPixelArray);
2990 void QSGContext2D::popState()
2992 if (m_stateStack.isEmpty())
2995 QSGContext2D::State newState = m_stateStack.pop();
2997 if (state.matrix != newState.matrix)
2998 buffer()->updateMatrix(newState.matrix);
3000 if (newState.globalAlpha != state.globalAlpha)
3001 buffer()->setGlobalAlpha(newState.globalAlpha);
3003 if (newState.globalCompositeOperation != state.globalCompositeOperation)
3004 buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
3006 if (newState.fillStyle != state.fillStyle)
3007 buffer()->setFillStyle(newState.fillStyle);
3009 if (newState.strokeStyle != state.strokeStyle)
3010 buffer()->setStrokeStyle(newState.strokeStyle);
3012 if (newState.lineWidth != state.lineWidth)
3013 buffer()->setLineWidth(newState.lineWidth);
3015 if (newState.lineCap != state.lineCap)
3016 buffer()->setLineCap(newState.lineCap);
3018 if (newState.lineJoin != state.lineJoin)
3019 buffer()->setLineJoin(newState.lineJoin);
3021 if (newState.miterLimit != state.miterLimit)
3022 buffer()->setMiterLimit(newState.miterLimit);
3024 if (newState.clipPath != state.clipPath)
3025 buffer()->clip(newState.clipPath);
3027 if (newState.shadowBlur != state.shadowBlur)
3028 buffer()->setShadowBlur(newState.shadowBlur);
3030 if (newState.shadowColor != state.shadowColor)
3031 buffer()->setShadowColor(newState.shadowColor);
3033 if (newState.shadowOffsetX != state.shadowOffsetX)
3034 buffer()->setShadowOffsetX(newState.shadowOffsetX);
3036 if (newState.shadowOffsetY != state.shadowOffsetY)
3037 buffer()->setShadowOffsetY(newState.shadowOffsetY);
3041 void QSGContext2D::pushState()
3043 m_stateStack.push(state);
3046 void QSGContext2D::reset()
3048 QSGContext2D::State newState;
3049 newState.matrix = QTransform();
3051 QPainterPath defaultClipPath;
3052 defaultClipPath.addRect(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
3053 newState.clipPath = defaultClipPath;
3054 newState.clipPath.setFillRule(Qt::WindingFill);
3056 newState.strokeStyle = Qt::black;
3057 newState.fillStyle = Qt::black;
3058 newState.fillRule = Qt::WindingFill;
3059 newState.globalAlpha = 1.0;
3060 newState.lineWidth = 1;
3061 newState.lineCap = Qt::FlatCap;
3062 newState.lineJoin = Qt::MiterJoin;
3063 newState.miterLimit = 10;
3064 newState.shadowOffsetX = 0;
3065 newState.shadowOffsetY = 0;
3066 newState.shadowBlur = 0;
3067 newState.shadowColor = qRgba(0, 0, 0, 0);
3068 newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
3069 newState.font = QFont(QLatin1String("sans-serif"), 10);
3070 newState.textAlign = QSGContext2D::Start;
3071 newState.textBaseline = QSGContext2D::Alphabetic;
3074 m_stateStack.clear();
3075 m_stateStack.push(newState);
3079 void QSGContext2D::setV8Engine(QV8Engine *engine)
3081 v8::HandleScope handle_scope;
3082 v8::Context::Scope scope(engine->context());
3084 if (m_v8engine != engine) {
3085 m_v8engine = engine;
3087 qPersistentDispose(m_v8value);
3089 if (m_v8engine == 0)
3092 QSGContext2DEngineData *ed = engineData(engine);
3093 m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
3094 QV8Context2DResource *r = new QV8Context2DResource(engine);
3096 m_v8value->SetExternalResource(r);