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"
48 #include <QtCore/qdebug.h>
49 #include "private/qsgcontext_p.h"
50 #include "private/qdeclarativesvgparser_p.h"
51 #include "private/qdeclarativepath_p.h"
53 #include "private/qsgimage_p_p.h"
55 #include <qdeclarativeinfo.h>
56 #include <QtCore/qmath.h>
57 #include "qv8engine_p.h"
59 #include <QtOpenGL/QGLFramebufferObjectFormat>
60 #include <QtOpenGL/QGLFramebufferObject>
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 #define DEGREES(t) ((t) * 180.0 / Q_PI)
73 #define qClamp(val, min, max) qMin(qMax(val, min), max)
75 #define CHECK_CONTEXT(r) if (!r || !r->context || !r->context->buffer()) \
76 V8THROW_ERROR("Not a Context2D object");
78 #define CHECK_CONTEXT_SETTER(r) if (!r || !r->context || !r->context->buffer()) \
79 V8THROW_ERROR_SETTER("Not a Context2D object");
81 static inline int extractInt(const char **name)
84 bool negative = false;
86 //eat leading whitespace
87 while (isspace(*name[0]))
90 if (*name[0] == '-') {
93 } /*else if (name[0] == '+')
97 while (isdigit(*name[0])) {
98 result = result * 10 + (*name[0] - '0');
104 //handle optional percentage
106 result *= qreal(255)/100; //### floor or round?
108 //eat trailing whitespace
109 while (isspace(*name[0]))
115 static bool qt_get_rgb(const QString &string, QRgb *rgb)
117 const char *name = string.toLatin1().constData();
118 int len = qstrlen(name);
123 bool handleAlpha = false;
131 if (name[3] == 'a') {
135 } else if (name[3] != '(')
144 result = extractInt(&name);
145 if (name[0] == ',') {
152 result = extractInt(&name);
153 if (name[0] == ',') {
159 char nextChar = handleAlpha ? ',' : ')';
162 result = extractInt(&name);
163 if (name[0] == nextChar) {
171 result = extractInt(&name);
172 if (name[0] == ')') {
173 a = result * 255; //map 0-1 to 0-255
182 *rgb = qRgba(qClamp(r,0,255), qClamp(g,0,255), qClamp(b,0,255), qClamp(a,0,255));
186 //### unify with qt_get_rgb?
187 static bool qt_get_hsl(const QString &string, QColor *color)
189 const char *name = string.toLatin1().constData();
190 int len = qstrlen(name);
195 bool handleAlpha = false;
203 if (name[3] == 'a') {
207 } else if (name[3] != '(')
216 result = extractInt(&name);
217 if (name[0] == ',') {
224 result = extractInt(&name);
225 if (name[0] == ',') {
231 char nextChar = handleAlpha ? ',' : ')';
234 result = extractInt(&name);
235 if (name[0] == nextChar) {
243 result = extractInt(&name);
244 if (name[0] == ')') {
245 a = result * 255; //map 0-1 to 0-255
254 *color = QColor::fromHsl(qClamp(h,0,255), qClamp(s,0,255), qClamp(l,0,255), qClamp(a,0,255));
258 //### optimize further
259 QColor qt_color_from_string(const QString &name)
261 if (name.startsWith(QLatin1String("rgb"))) {
263 if (qt_get_rgb(name, &rgb))
265 } else if (name.startsWith(QLatin1String("hsl"))) {
267 if (qt_get_hsl(name, &color))
274 QFont qt_font_from_string(const QString& fontString) {
276 // ### this is simplified and incomplete
277 // ### TODO:get code from Qt webkit
278 QStringList tokens = fontString.split(QLatin1String(" "));
279 foreach (const QString &token, tokens) {
280 if (token == QLatin1String("italic"))
281 font.setItalic(true);
282 else if (token == QLatin1String("bold"))
284 else if (token.endsWith(QLatin1String("px"))) {
285 QString number = token;
286 number.remove(QLatin1String("px"));
287 //font.setPointSizeF(number.trimmed().toFloat());
288 font.setPixelSize(number.trimmed().toInt());
290 font.setFamily(token);
298 class QSGContext2DEngineData : public QV8Engine::Deletable
301 QSGContext2DEngineData(QV8Engine *engine);
302 ~QSGContext2DEngineData();
304 v8::Persistent<v8::Function> constructorContext;
305 v8::Persistent<v8::Function> constructorGradient;
306 v8::Persistent<v8::Function> constructorPattern;
307 v8::Persistent<v8::Function> constructorPixelArray;
308 v8::Persistent<v8::Function> constructorImageData;
310 V8_DEFINE_EXTENSION(QSGContext2DEngineData, engineData);
314 class QV8Context2DResource : public QV8ObjectResource
316 V8_RESOURCE_TYPE(Context2DType)
318 QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
319 QSGContext2D* context;
322 class QV8Context2DStyleResource : public QV8ObjectResource
324 V8_RESOURCE_TYPE(Context2DStyleType)
326 QV8Context2DStyleResource(QV8Engine *e) : QV8ObjectResource(e) {}
330 class QV8Context2DPixelArrayResource : public QV8ObjectResource
332 V8_RESOURCE_TYPE(Context2DPixelArrayType)
334 QV8Context2DPixelArrayResource(QV8Engine *e) : QV8ObjectResource(e) {}
339 static QImage qt_texture_to_image(QSGTexture* texture)
341 if (!texture || !texture->textureId())
343 QGLFramebufferObjectFormat format;
344 format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
345 format.setInternalTextureFormat(GL_RGBA);
346 format.setMipmap(false);
347 QGLFramebufferObject* fbo = new QGLFramebufferObject(texture->textureSize(), format);
348 fbo->drawTexture(QPointF(0,0), texture->textureId(), GL_TEXTURE_2D);
349 return fbo->toImage();
352 static QSGTexture* qt_item_to_texture(QSGItem* item)
356 QSGShaderEffectTexture* texture = new QSGShaderEffectTexture(item);
357 texture->setItem(QSGItemPrivate::get(item)->itemNode());
358 texture->setLive(true);
360 QRectF sourceRect = QRectF(0, 0, item->width(), item->height());
362 texture->setRect(sourceRect);
363 QSize textureSize = QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height())));
364 texture->setSize(textureSize);
365 texture->setRecursive(false);
366 texture->setFormat(GL_RGBA);
367 texture->setHasMipmaps(false);
368 texture->markDirtyTexture();
369 texture->updateTexture();
373 static QImage qt_item_to_image(QSGItem* item) {
374 return qt_texture_to_image(qt_item_to_texture(item));
377 static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
379 if (compositeOperator == QLatin1String("source-over")) {
380 return QPainter::CompositionMode_SourceOver;
381 } else if (compositeOperator == QLatin1String("source-out")) {
382 return QPainter::CompositionMode_SourceOut;
383 } else if (compositeOperator == QLatin1String("source-in")) {
384 return QPainter::CompositionMode_SourceIn;
385 } else if (compositeOperator == QLatin1String("source-atop")) {
386 return QPainter::CompositionMode_SourceAtop;
387 } else if (compositeOperator == QLatin1String("destination-atop")) {
388 return QPainter::CompositionMode_DestinationAtop;
389 } else if (compositeOperator == QLatin1String("destination-in")) {
390 return QPainter::CompositionMode_DestinationIn;
391 } else if (compositeOperator == QLatin1String("destination-out")) {
392 return QPainter::CompositionMode_DestinationOut;
393 } else if (compositeOperator == QLatin1String("destination-over")) {
394 return QPainter::CompositionMode_DestinationOver;
395 } else if (compositeOperator == QLatin1String("lighter")) {
396 return QPainter::CompositionMode_Plus;
397 } else if (compositeOperator == QLatin1String("copy")) {
398 return QPainter::CompositionMode_Source;
399 } else if (compositeOperator == QLatin1String("xor")) {
400 return QPainter::CompositionMode_Xor;
401 } else if (compositeOperator == QLatin1String("qt-clear")) {
402 return QPainter::CompositionMode_Clear;
403 } else if (compositeOperator == QLatin1String("qt-destination")) {
404 return QPainter::CompositionMode_Destination;
405 } else if (compositeOperator == QLatin1String("qt-multiply")) {
406 return QPainter::CompositionMode_Multiply;
407 } else if (compositeOperator == QLatin1String("qt-screen")) {
408 return QPainter::CompositionMode_Screen;
409 } else if (compositeOperator == QLatin1String("qt-overlay")) {
410 return QPainter::CompositionMode_Overlay;
411 } else if (compositeOperator == QLatin1String("qt-darken")) {
412 return QPainter::CompositionMode_Darken;
413 } else if (compositeOperator == QLatin1String("qt-lighten")) {
414 return QPainter::CompositionMode_Lighten;
415 } else if (compositeOperator == QLatin1String("qt-color-dodge")) {
416 return QPainter::CompositionMode_ColorDodge;
417 } else if (compositeOperator == QLatin1String("qt-color-burn")) {
418 return QPainter::CompositionMode_ColorBurn;
419 } else if (compositeOperator == QLatin1String("qt-hard-light")) {
420 return QPainter::CompositionMode_HardLight;
421 } else if (compositeOperator == QLatin1String("qt-soft-light")) {
422 return QPainter::CompositionMode_SoftLight;
423 } else if (compositeOperator == QLatin1String("qt-difference")) {
424 return QPainter::CompositionMode_Difference;
425 } else if (compositeOperator == QLatin1String("qt-exclusion")) {
426 return QPainter::CompositionMode_Exclusion;
428 return QPainter::CompositionMode_SourceOver;
431 static QString qt_composite_mode_to_string(QPainter::CompositionMode op)
434 case QPainter::CompositionMode_SourceOver:
435 return QLatin1String("source-over");
436 case QPainter::CompositionMode_DestinationOver:
437 return QLatin1String("destination-over");
438 case QPainter::CompositionMode_Clear:
439 return QLatin1String("qt-clear");
440 case QPainter::CompositionMode_Source:
441 return QLatin1String("copy");
442 case QPainter::CompositionMode_Destination:
443 return QLatin1String("qt-destination");
444 case QPainter::CompositionMode_SourceIn:
445 return QLatin1String("source-in");
446 case QPainter::CompositionMode_DestinationIn:
447 return QLatin1String("destination-in");
448 case QPainter::CompositionMode_SourceOut:
449 return QLatin1String("source-out");
450 case QPainter::CompositionMode_DestinationOut:
451 return QLatin1String("destination-out");
452 case QPainter::CompositionMode_SourceAtop:
453 return QLatin1String("source-atop");
454 case QPainter::CompositionMode_DestinationAtop:
455 return QLatin1String("destination-atop");
456 case QPainter::CompositionMode_Xor:
457 return QLatin1String("xor");
458 case QPainter::CompositionMode_Plus:
459 return QLatin1String("lighter");
460 case QPainter::CompositionMode_Multiply:
461 return QLatin1String("qt-multiply");
462 case QPainter::CompositionMode_Screen:
463 return QLatin1String("qt-screen");
464 case QPainter::CompositionMode_Overlay:
465 return QLatin1String("qt-overlay");
466 case QPainter::CompositionMode_Darken:
467 return QLatin1String("qt-darken");
468 case QPainter::CompositionMode_Lighten:
469 return QLatin1String("qt-lighten");
470 case QPainter::CompositionMode_ColorDodge:
471 return QLatin1String("qt-color-dodge");
472 case QPainter::CompositionMode_ColorBurn:
473 return QLatin1String("qt-color-burn");
474 case QPainter::CompositionMode_HardLight:
475 return QLatin1String("qt-hard-light");
476 case QPainter::CompositionMode_SoftLight:
477 return QLatin1String("qt-soft-light");
478 case QPainter::CompositionMode_Difference:
479 return QLatin1String("qt-difference");
480 case QPainter::CompositionMode_Exclusion:
481 return QLatin1String("qt-exclusion");
489 static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* engine, const QImage& image)
491 QSGContext2DEngineData *ed = engineData(engine);
492 v8::Local<v8::Object> imageData = ed->constructorImageData->NewInstance();
493 QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
494 if (image.isNull()) {
495 r->image = QImage(w, h, QImage::Format_ARGB32);
496 r->image.fill(Qt::transparent);
498 Q_ASSERT(image.width() == w && image.height() == h);
501 v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
502 pixelData->SetExternalResource(r);
504 imageData->SetInternalField(0, pixelData);
508 //static script functions
511 \qmlproperty QtQuick2::Canvas QtQuick2::Context2D::canvas
512 Holds the canvas item that the context paints on.
514 static v8::Handle<v8::Value> ctx2d_canvas(v8::Local<v8::String>, const v8::AccessorInfo &info)
516 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
520 QV8Engine *engine = V8ENGINE_ACCESSOR();
522 return engine->newQObject(r->context->canvas());
526 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::restore()
527 Pops the top state on the stack, restoring the context to that state.
529 static v8::Handle<v8::Value> ctx2d_restore(const v8::Arguments &args)
531 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
534 r->context->popState();
539 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::reset()
540 Resets the context state and properties to the default values.
542 static v8::Handle<v8::Value> ctx2d_reset(const v8::Arguments &args)
544 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
552 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::save()
553 Pushes the current state onto the stack.
555 static v8::Handle<v8::Value> ctx2d_save(const v8::Arguments &args)
557 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
560 r->context->pushState();
567 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::rotate(real angle)
568 Changes the transformation matrix to apply a rotation transformation with the given characteristics.
569 Note: The angle is in radians.
571 static v8::Handle<v8::Value> ctx2d_rotate(const v8::Arguments &args)
573 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
577 if (args.Length() == 1) {
578 qreal angle = args[0]->NumberValue();
579 r->context->state.matrix.rotate(DEGREES(angle));
580 r->context->buffer()->updateMatrix(r->context->state.matrix);
587 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::scale(real x, real y)
588 Changes the transformation matrix to apply a scaling transformation with the given characteristics.
590 static v8::Handle<v8::Value> ctx2d_scale(const v8::Arguments &args)
592 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
596 if (args.Length() == 2) {
598 x = args[0]->NumberValue();
599 y = args[1]->NumberValue();
600 r->context->state.matrix.scale(x, y);
601 r->context->buffer()->updateMatrix(r->context->state.matrix);
608 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::setTransform(real a, real b, real c, real d, real e, real f)
609 Changes the transformation matrix to the matrix given by the arguments as described below.
611 \sa QtQuick2::Context2D::transform()
613 static v8::Handle<v8::Value> ctx2d_setTransform(const v8::Arguments &args)
615 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
619 if (args.Length() == 6) {
620 r->context->state.matrix = QTransform(args[0]->NumberValue(),
621 args[1]->NumberValue(),
622 args[2]->NumberValue(),
623 args[3]->NumberValue(),
624 args[4]->NumberValue(),
625 args[5]->NumberValue());
626 r->context->buffer()->updateMatrix(r->context->state.matrix);
633 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::transform(real a, real b, real c, real d, real e, real f)
634 Changes the transformation matrix to apply the matrix given by the arguments as described below.
636 \sa QtQuick2::Context2D::setTransform()
638 static v8::Handle<v8::Value> ctx2d_transform(const v8::Arguments &args)
640 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
644 if (args.Length() == 6) {
645 r->context->state.matrix *= QTransform(args[0]->NumberValue(),
646 args[1]->NumberValue(),
647 args[2]->NumberValue(),
648 args[3]->NumberValue(),
649 args[4]->NumberValue(),
650 args[5]->NumberValue());
651 r->context->buffer()->updateMatrix(r->context->state.matrix);
658 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::translate(real x, real y)
659 Changes the transformation matrix to apply a translation transformation with the given characteristics.
661 static v8::Handle<v8::Value> ctx2d_translate(const v8::Arguments &args)
663 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
667 if (args.Length() == 2) {
668 r->context->state.matrix.translate(args[0]->NumberValue(),
669 args[1]->NumberValue());
670 r->context->buffer()->updateMatrix(r->context->state.matrix);
678 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::resetTransform()
679 Reset the transformation matrix default value.
681 \sa QtQuick2::Context2D::transform(), QtQuick2::Context2D::setTransform()
683 static v8::Handle<v8::Value> ctx2d_resetTransform(const v8::Arguments &args)
685 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
688 r->context->state.matrix = QTransform();
689 r->context->buffer()->updateMatrix(r->context->state.matrix);
696 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::shear(real sh, real sv )
697 Shear the transformation matrix with \a sh in horizontal direction and \a sv in vertical direction.
699 static v8::Handle<v8::Value> ctx2d_shear(const v8::Arguments &args)
701 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
704 r->context->state.matrix.shear(args[0]->NumberValue(),
705 args[1]->NumberValue());
706 r->context->buffer()->updateMatrix(r->context->state.matrix);
713 \qmlproperty real QtQuick2::Context2D::globalAlpha
714 Holds the the current alpha value applied to rendering operations.
715 The value must be in the range from 0.0 (fully transparent) to 1.0 (no additional transparency).
717 static v8::Handle<v8::Value> ctx2d_globalAlpha(v8::Local<v8::String>, const v8::AccessorInfo &info)
719 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
723 return v8::Number::New(r->context->state.globalAlpha);
726 static void ctx2d_globalAlpha_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
728 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
729 CHECK_CONTEXT_SETTER(r)
731 qreal globalAlpha = value->NumberValue();
733 if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->context->state.globalAlpha != globalAlpha) {
734 r->context->state.globalAlpha = globalAlpha;
735 r->context->buffer()->setGlobalAlpha(r->context->state.globalAlpha);
740 \qmlproperty string QtQuick2::Context2D::globalCompositeOperation
741 Holds the the current the current composition operation, from the list below:
743 \o source-atop - A atop B. Display the source image wherever both images are opaque.
744 Display the destination image wherever the destination image is opaque but the source image is transparent.
745 Display transparency elsewhere.
746 \o source-in - A in B. Display the source image wherever both the source image and destination image are opaque.
747 Display transparency elsewhere.
748 \o source-out - A out B. Display the source image wherever the source image is opaque and the destination image is transparent.
749 Display transparency elsewhere.
750 \o source-over - (default) A over B. Display the source image wherever the source image is opaque.
751 Display the destination image elsewhere.
752 \o destination-atop - B atop A. Same as source-atop but using the destination image instead of the source image and vice versa.
753 \o destination-in - B in A. Same as source-in but using the destination image instead of the source image and vice versa.
754 \o destination-out - B out A. Same as source-out but using the destination image instead of the source image and vice versa.
755 \o destination-over - B over A. Same as source-over but using the destination image instead of the source image and vice versa.
756 \o lighter - A plus B. Display the sum of the source image and destination image, with color values approaching 255 (100%) as a limit.
757 \o copy - A (B is ignored). Display the source image instead of the destination image.
758 \o xor - A xor B. Exclusive OR of the source image and destination image.
761 static v8::Handle<v8::Value> ctx2d_globalCompositeOperation(v8::Local<v8::String>, const v8::AccessorInfo &info)
763 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
767 QV8Engine *engine = V8ENGINE_ACCESSOR();
769 return engine->toString(qt_composite_mode_to_string(r->context->state.globalCompositeOperation));
772 static void ctx2d_globalCompositeOperation_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
774 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
775 CHECK_CONTEXT_SETTER(r)
777 QV8Engine *engine = V8ENGINE_ACCESSOR();
779 QPainter::CompositionMode cm = qt_composite_mode_from_string(engine->toString(value));
780 if (cm != r->context->state.globalCompositeOperation) {
781 r->context->state.globalCompositeOperation = cm;
782 r->context->buffer()->setGlobalCompositeOperation(cm);
788 \qmlproperty variant QtQuick2::Context2D::fillStyle
789 Holds the current style used for filling shapes.
790 The style can be either a string containing a CSS color, or a CanvasGradient or CanvasPattern object. Invalid values are ignored.
791 \sa QtQuick2::Context2D::createLinearGradient
792 \sa QtQuick2::Context2D::createRadialGradient
793 \sa QtQuick2::Context2D::createPattern
794 \sa QtQuick2::Context2D::strokeStyle
796 static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
798 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
801 return r->context->m_fillStyle;
804 static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
806 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
807 CHECK_CONTEXT_SETTER(r)
809 QV8Engine *engine = V8ENGINE_ACCESSOR();
811 r->context->m_fillStyle = value;
812 if (value->IsObject()) {
813 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
814 if (color.isValid()) {
815 r->context->state.fillStyle = color;
816 r->context->buffer()->setFillStyle(color);
818 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
819 if (style && style->brush != r->context->state.fillStyle) {
820 r->context->state.fillStyle = style->brush;
821 r->context->buffer()->setFillStyle(style->brush);
824 } else if (value->IsString()) {
825 QColor color = qt_color_from_string(engine->toString(value));
826 if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
827 r->context->state.fillStyle = QBrush(color);
828 r->context->buffer()->setFillStyle(r->context->state.fillStyle);
833 static v8::Handle<v8::Value> ctx2d_fillRule(v8::Local<v8::String>, const v8::AccessorInfo &info)
835 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
837 QV8Engine *engine = V8ENGINE_ACCESSOR();
839 return engine->fromVariant(r->context->state.fillRule);
842 static void ctx2d_fillRule_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
844 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
845 CHECK_CONTEXT_SETTER(r)
847 QV8Engine *engine = V8ENGINE_ACCESSOR();
849 if ((value->IsString() && engine->toString(value) == "WindingFill")
850 ||(value->IsNumber() && value->NumberValue() == Qt::WindingFill)) {
851 r->context->state.fillRule = Qt::WindingFill;
852 } else if ((value->IsString() && engine->toString(value) == "OddEvenFill")
853 ||(value->IsNumber() && value->NumberValue() == Qt::OddEvenFill)) {
854 r->context->state.fillRule = Qt::OddEvenFill;
858 r->context->m_path.setFillRule(r->context->state.fillRule);
861 \qmlproperty variant QtQuick2::Context2D::strokeStyle
862 Holds the current color or style to use for the lines around shapes,
863 The style can be either a string containing a CSS color, or a CanvasGradient or CanvasPattern object. Invalid values are ignored.
864 \sa QtQuick2::Context2D::createLinearGradient
865 \sa QtQuick2::Context2D::createRadialGradient
866 \sa QtQuick2::Context2D::createPattern
867 \sa QtQuick2::Context2D::fillStyle
869 v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::AccessorInfo &info)
871 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
875 return r->context->m_strokeStyle;
878 static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
880 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
881 CHECK_CONTEXT_SETTER(r)
883 QV8Engine *engine = V8ENGINE_ACCESSOR();
885 r->context->m_strokeStyle = value;
886 if (value->IsObject()) {
887 QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
888 if (color.isValid()) {
889 r->context->state.fillStyle = color;
890 r->context->buffer()->setStrokeStyle(color);
892 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
893 if (style && style->brush != r->context->state.strokeStyle) {
894 r->context->state.strokeStyle = style->brush;
895 r->context->buffer()->setStrokeStyle(style->brush);
898 } else if (value->IsString()) {
899 QColor color = qt_color_from_string(engine->toString(value));
900 if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
901 r->context->state.strokeStyle = QBrush(color);
902 r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
908 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::createLinearGradient(real x0, real y0, real x1, real y1)
909 Returns a CanvasGradient object that represents a linear gradient that paints along the line given by the coordinates
910 represented by the start point (\a x0, \a y0) and the end point (\a x1, \a y1).
911 \sa QtQuick2::Context2D::createRadialGradient
912 \sa QtQuick2::Context2D::createPattern
913 \sa QtQuick2::Context2D::fillStyle
914 \sa QtQuick2::Context2D::strokeStyle
917 static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &args)
919 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
923 QV8Engine *engine = V8ENGINE();
925 if (args.Length() == 4) {
926 //TODO:infinite or NaN, the method must raise a NOT_SUPPORTED_ERR
927 QSGContext2DEngineData *ed = engineData(engine);
928 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
929 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
930 r->brush = QLinearGradient(args[0]->NumberValue(),
931 args[1]->NumberValue(),
932 args[2]->NumberValue(),
933 args[3]->NumberValue());
934 gradient->SetExternalResource(r);
942 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1)
943 Returns a CanvasGradient object that represents a radial gradient that paints along the cone given by the start circle with
944 origin (x0, y0) and radius r0, and the end circle with origin (x1, y1) and radius r1.
946 \sa QtQuick2::Context2D::createLinearGradient
947 \sa QtQuick2::Context2D::createPattern
948 \sa QtQuick2::Context2D::fillStyle
949 \sa QtQuick2::Context2D::strokeStyle
952 static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &args)
954 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
958 QV8Engine *engine = V8ENGINE();
960 if (args.Length() == 6) {
961 QSGContext2DEngineData *ed = engineData(engine);
962 v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
963 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
965 qreal x0 = args[0]->NumberValue();
966 qreal y0 = args[1]->NumberValue();
967 qreal r0 = args[2]->NumberValue();
968 qreal x1 = args[3]->NumberValue();
969 qreal y1 = args[4]->NumberValue();
970 qreal r1 = args[5]->NumberValue();
971 //TODO:infinite or NaN, a NOT_SUPPORTED_ERR exception must be raised.
972 //If either of r0 or r1 are negative, an INDEX_SIZE_ERR exception must be raised.
973 r->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
974 gradient->SetExternalResource(r);
982 \qmlmethod variant createPattern(Image image, string repetition)
983 Returns a CanvasPattern object that uses the given image and repeats in the direction(s) given by the repetition argument.
985 The \a image parameter must be a valid Image item, if there is no image data, throws an INVALID_STATE_ERR exception.
987 The allowed values for \a repetition are:
990 \o "repeat" - both directions
991 \o "repeat-x - horizontal only
992 \o "repeat-y" - vertical only
993 \o "no-repeat" - neither
996 If the repetition argument is empty or null, the value "repeat" is used.
998 \sa QtQuick2::Context2D::strokeStyle
999 \sa QtQuick2::Context2D::fillStyle
1001 static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
1003 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1007 QV8Engine *engine = V8ENGINE();
1009 if (args.Length() == 2) {
1010 QSGContext2DEngineData *ed = engineData(engine);
1011 v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
1012 QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
1016 QSGItem* item = qobject_cast<QSGItem*>(engine->toQObject(args[0]));
1018 img = qt_item_to_image(item);
1019 // if (img.isNull()) {
1020 // //exception: INVALID_STATE_ERR
1023 //exception: TYPE_MISMATCH_ERR
1026 QString repetition = engine->toString(args[1]);
1028 // if (repetition == "repeat" || repetition.isEmpty()) {
1030 // } else if (repetition == "repeat-x") {
1032 // } else if (repetition == "repeat-y") {
1034 // } else if (repetition == "no-repeat") {
1037 // //TODO: exception: SYNTAX_ERR
1040 pattern->SetExternalResource(r);
1048 \qmlproperty string QtQuick2::Context2D::lineCap
1049 Holds the the current line cap style.
1050 The possible line cap styles are:
1052 \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.
1053 \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.
1054 \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.
1056 Other values are ignored.
1058 v8::Handle<v8::Value> ctx2d_lineCap(v8::Local<v8::String>, const v8::AccessorInfo &info)
1060 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1064 QV8Engine *engine = V8ENGINE_ACCESSOR();
1065 switch (r->context->state.lineCap) {
1067 return engine->toString(QLatin1String("round"));
1069 return engine->toString(QLatin1String("butt"));
1071 return engine->toString(QLatin1String("square"));
1075 return engine->toString(QLatin1String("butt"));;
1078 static void ctx2d_lineCap_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1080 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1081 CHECK_CONTEXT_SETTER(r)
1083 QV8Engine *engine = V8ENGINE_ACCESSOR();
1085 QString lineCap = engine->toString(value);
1086 Qt::PenCapStyle cap;
1087 if (lineCap == QLatin1String("round"))
1089 else if (lineCap == QLatin1String("butt"))
1091 else if (lineCap == QLatin1String("square"))
1092 cap = Qt::SquareCap;
1094 if (cap != r->context->state.lineCap) {
1095 r->context->state.lineCap = cap;
1096 r->context->buffer()->setLineCap(cap);
1101 \qmlproperty string QtQuick2::Context2D::lineJoin
1102 Holds the the current line join style. A join exists at any point in a subpath
1103 shared by two consecutive lines. When a subpath is closed, then a join also exists
1104 at its first point (equivalent to its last point) connecting the first and last lines in the subpath.
1106 The possible line join styles are:
1108 \o bevel - this is all that is rendered at joins.
1109 \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.
1110 \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.
1112 Other values are ignored.
1114 v8::Handle<v8::Value> ctx2d_lineJoin(v8::Local<v8::String>, const v8::AccessorInfo &info)
1116 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1120 QV8Engine *engine = V8ENGINE_ACCESSOR();
1121 switch (r->context->state.lineJoin) {
1123 return engine->toString(QLatin1String("round"));
1125 return engine->toString(QLatin1String("bevel"));
1127 return engine->toString(QLatin1String("miter"));
1131 return engine->toString(QLatin1String("miter"));
1134 static void ctx2d_lineJoin_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1136 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1137 CHECK_CONTEXT_SETTER(r)
1139 QV8Engine *engine = V8ENGINE_ACCESSOR();
1141 QString lineJoin = engine->toString(value);
1142 Qt::PenJoinStyle join;
1143 if (lineJoin == QLatin1String("round"))
1144 join = Qt::RoundJoin;
1145 else if (lineJoin == QLatin1String("bevel"))
1146 join = Qt::BevelJoin;
1147 else if (lineJoin == QLatin1String("miter"))
1148 join = Qt::MiterJoin;
1150 if (join != r->context->state.lineJoin) {
1151 r->context->state.lineJoin = join;
1152 r->context->buffer()->setLineJoin(join);
1157 \qmlproperty real QtQuick2::Context2D::lineWidth
1158 Holds the the current line width. Values that are not finite values greater than zero are ignored.
1160 v8::Handle<v8::Value> ctx2d_lineWidth(v8::Local<v8::String>, const v8::AccessorInfo &info)
1162 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1166 return v8::Number::New(r->context->state.lineWidth);
1169 static void ctx2d_lineWidth_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1171 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1172 CHECK_CONTEXT_SETTER(r)
1174 qreal w = value->NumberValue();
1176 if (w > 0 && w != r->context->state.lineWidth) {
1177 r->context->state.lineWidth = w;
1178 r->context->buffer()->setLineWidth(w);
1183 \qmlproperty real QtQuick2::Context2D::miterLimit
1184 Holds the current miter limit ratio.
1185 The default miter limit value is 10.0.
1187 v8::Handle<v8::Value> ctx2d_miterLimit(v8::Local<v8::String>, const v8::AccessorInfo &info)
1189 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1193 return v8::Number::New(r->context->state.miterLimit);
1196 static void ctx2d_miterLimit_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1198 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1199 CHECK_CONTEXT_SETTER(r)
1201 qreal ml = value->NumberValue();
1203 if (ml > 0 && ml != r->context->state.miterLimit) {
1204 r->context->state.miterLimit = ml;
1205 r->context->buffer()->setMiterLimit(ml);
1211 \qmlproperty real QtQuick2::Context2D::shadowBlur
1212 Holds the current level of blur applied to shadows
1214 v8::Handle<v8::Value> ctx2d_shadowBlur(v8::Local<v8::String>, const v8::AccessorInfo &info)
1216 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1220 return v8::Number::New(r->context->state.shadowBlur);
1223 static void ctx2d_shadowBlur_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1225 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1226 CHECK_CONTEXT_SETTER(r)
1227 qreal blur = value->NumberValue();
1229 if (blur > 0 && blur != r->context->state.shadowBlur) {
1230 r->context->state.shadowBlur = blur;
1231 r->context->buffer()->setShadowBlur(blur);
1236 \qmlproperty string QtQuick2::Context2D::shadowColor
1237 Holds the current shadow color.
1239 v8::Handle<v8::Value> ctx2d_shadowColor(v8::Local<v8::String>, const v8::AccessorInfo &info)
1241 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1245 QV8Engine *engine = V8ENGINE_ACCESSOR();
1247 return engine->toString(r->context->state.shadowColor.name());
1250 static void ctx2d_shadowColor_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1252 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1253 CHECK_CONTEXT_SETTER(r)
1255 QV8Engine *engine = V8ENGINE_ACCESSOR();
1257 QColor color = qt_color_from_string(engine->toString(value));
1259 if (color.isValid() && color != r->context->state.shadowColor) {
1260 r->context->state.shadowColor = color;
1261 r->context->buffer()->setShadowColor(color);
1267 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetX
1268 Holds the current shadow offset in the positive horizontal distance.
1270 \sa QtQuick2::Context2D::shadowOffsetY
1272 v8::Handle<v8::Value> ctx2d_shadowOffsetX(v8::Local<v8::String>, const v8::AccessorInfo &info)
1274 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1278 return v8::Number::New(r->context->state.shadowOffsetX);
1281 static void ctx2d_shadowOffsetX_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1283 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1284 CHECK_CONTEXT_SETTER(r)
1286 //TODO: check value:infinite or NaN
1287 qreal offsetX = value->NumberValue();
1288 if (offsetX != r->context->state.shadowOffsetX) {
1289 r->context->state.shadowOffsetX = offsetX;
1290 r->context->buffer()->setShadowOffsetX(offsetX);
1294 \qmlproperty qreal QtQuick2::Context2D::shadowOffsetY
1295 Holds the current shadow offset in the positive vertical distance.
1297 \sa QtQuick2::Context2D::shadowOffsetX
1299 v8::Handle<v8::Value> ctx2d_shadowOffsetY(v8::Local<v8::String>, const v8::AccessorInfo &info)
1301 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1305 return v8::Number::New(r->context->state.shadowOffsetY);
1308 static void ctx2d_shadowOffsetY_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1310 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1311 CHECK_CONTEXT_SETTER(r)
1312 //TODO: check value:infinite or NaN
1313 qreal offsetY = value->NumberValue();
1314 if (offsetY != r->context->state.shadowOffsetY) {
1315 r->context->state.shadowOffsetY = offsetY;
1316 r->context->buffer()->setShadowOffsetY(offsetY);
1320 v8::Handle<v8::Value> ctx2d_path(v8::Local<v8::String>, const v8::AccessorInfo &info)
1322 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1324 return r->context->m_v8path;
1327 static void ctx2d_path_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1329 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1330 CHECK_CONTEXT_SETTER(r)
1331 QV8Engine *engine = V8ENGINE_ACCESSOR();
1333 r->context->beginPath();
1334 if (value->IsObject()) {
1335 QDeclarativePath* path = qobject_cast<QDeclarativePath*>(engine->toQObject(value));
1337 r->context->m_path = path->path();
1339 QString path = engine->toString(value->ToString());
1340 QDeclarativeSvgParser::parsePathDataFast(path, r->context->m_path);
1342 r->context->m_v8path = value;
1347 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::clearRect(real x, real y, real w, real h)
1348 Clears all pixels on the canvas in the given rectangle to transparent black.
1350 static v8::Handle<v8::Value> ctx2d_clearRect(const v8::Arguments &args)
1352 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1356 if (args.Length() == 4) {
1357 r->context->buffer()->clearRect(args[0]->NumberValue(),
1358 args[1]->NumberValue(),
1359 args[2]->NumberValue(),
1360 args[3]->NumberValue());
1366 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1367 Paint the specified rectangular area using the fillStyle.
1369 \sa QtQuick2::Context2D::fillStyle
1371 static v8::Handle<v8::Value> ctx2d_fillRect(const v8::Arguments &args)
1373 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1377 if (args.Length() == 4) {
1378 r->context->buffer()->fillRect(args[0]->NumberValue(),
1379 args[1]->NumberValue(),
1380 args[2]->NumberValue(),
1381 args[3]->NumberValue());
1388 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillRect(real x, real y, real w, real h)
1389 Stroke the specified rectangle's path using the strokeStyle, lineWidth, lineJoin,
1390 and (if appropriate) miterLimit attributes.
1392 \sa QtQuick2::Context2D::strokeStyle
1393 \sa QtQuick2::Context2D::lineWidth
1394 \sa QtQuick2::Context2D::lineJoin
1395 \sa QtQuick2::Context2D::miterLimit
1397 static v8::Handle<v8::Value> ctx2d_strokeRect(const v8::Arguments &args)
1399 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1403 if (args.Length() == 4) {
1404 r->context->buffer()->strokeRect(args[0]->NumberValue(),
1405 args[1]->NumberValue(),
1406 args[2]->NumberValue(),
1407 args[3]->NumberValue());
1413 // Complex shapes (paths) API
1415 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
1416 Adds points to the subpath such that the arc described by the circumference of
1417 the circle described by the arguments.
1419 See http://www.w3.org/TR/2dcontext/#dom-context-2d-arc for details.
1421 static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
1423 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1426 if (args.Length() >= 5) {
1427 bool antiClockwise = false;
1429 if (args.Length() == 6)
1430 antiClockwise = args[5]->BooleanValue();
1432 qreal radius = args[2]->NumberValue();
1433 //Throws an INDEX_SIZE_ERR exception if the given radius is negative.
1434 r->context->arc(args[0]->NumberValue(),
1435 args[1]->NumberValue(),
1437 args[3]->NumberValue(),
1438 args[4]->NumberValue(),
1446 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::arcTo(real x1, real y1, real x2, real y2, real radius)
1448 Adds an arc with the given control points and radius to the current subpath, connected to the previous point by a straight line.
1449 See http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto for details.
1451 static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
1453 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1457 if (args.Length() == 5) {
1458 r->context->arcTo(args[0]->NumberValue(),
1459 args[1]->NumberValue(),
1460 args[2]->NumberValue(),
1461 args[3]->NumberValue(),
1462 args[4]->NumberValue());
1469 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::beginPath()
1471 Resets the current path.
1473 static v8::Handle<v8::Value> ctx2d_beginPath(const v8::Arguments &args)
1475 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1479 r->context->beginPath();
1485 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::bezierCurveTo(real cp1x, real cp1y, real cp2x, real cp2y, real x, real y)
1487 Adds the given point to the current subpath, connected to the previous one by a cubic Bézier curve with the given control points.
1489 See http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto for details.
1491 static v8::Handle<v8::Value> ctx2d_bezierCurveTo(const v8::Arguments &args)
1493 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1497 if (args.Length() == 6) {
1498 r->context->bezierCurveTo(args[0]->NumberValue(),
1499 args[1]->NumberValue(),
1500 args[2]->NumberValue(),
1501 args[3]->NumberValue(),
1502 args[4]->NumberValue(),
1503 args[5]->NumberValue());
1510 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::clip()
1512 constrains the clipping region to the given path.
1514 See http://www.w3.org/TR/2dcontext/#dom-context-2d-clip for details.
1516 static v8::Handle<v8::Value> ctx2d_clip(const v8::Arguments &args)
1518 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1521 r->context->state.clipPath = r->context->m_path;
1522 r->context->buffer()->clip(r->context->state.clipPath);
1528 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::closePath()
1530 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.
1532 See http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath for details.
1534 static v8::Handle<v8::Value> ctx2d_closePath(const v8::Arguments &args)
1536 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1540 r->context->closePath();
1546 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fill()
1548 Fills the subpaths with the current fill style.
1550 See http://www.w3.org/TR/2dcontext/#dom-context-2d-fill for details.
1552 \sa QtQuick2::Context2D::fillStyle
1554 static v8::Handle<v8::Value> ctx2d_fill(const v8::Arguments &args)
1556 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1559 r->context->buffer()->fill(r->context->m_path);
1565 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::lineTo(real x, real y)
1567 Adds the given point to the current subpath, connected to the previous one by a straight line.
1569 static v8::Handle<v8::Value> ctx2d_lineTo(const v8::Arguments &args)
1571 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1575 if (args.Length() == 2) {
1576 r->context->lineTo(args[0]->NumberValue(),
1577 args[1]->NumberValue());
1584 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::moveTo(real x, real y)
1586 Creates a new subpath with the given point.
1588 static v8::Handle<v8::Value> ctx2d_moveTo(const v8::Arguments &args)
1590 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1594 if (args.Length() == 2) {
1595 r->context->moveTo(args[0]->NumberValue(),
1596 args[1]->NumberValue());
1603 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::quadraticCurveTo(real cpx, real cpy, real x, real y)
1605 Adds the given point to the current subpath, connected to the previous one by a quadratic Bézier curve with the given control point.
1607 See http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto for details.
1609 static v8::Handle<v8::Value> ctx2d_quadraticCurveTo(const v8::Arguments &args)
1611 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1615 if (args.Length() == 4) {
1616 r->context->quadraticCurveTo(args[0]->NumberValue(),
1617 args[1]->NumberValue(),
1618 args[2]->NumberValue(),
1619 args[3]->NumberValue());
1626 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::rect(real x, real y, real w, real h)
1628 Adds a new closed subpath to the path, representing the given rectangle.
1630 See http://www.w3.org/TR/2dcontext/#dom-context-2d-rect for details.
1632 static v8::Handle<v8::Value> ctx2d_rect(const v8::Arguments &args)
1634 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1638 if (args.Length() == 4) {
1639 r->context->rect(args[0]->NumberValue(),
1640 args[1]->NumberValue(),
1641 args[2]->NumberValue(),
1642 args[3]->NumberValue());
1649 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::roundedRect(real x, real y, real w, real h, real xRadius, real yRadius)
1651 Adds the given rectangle rect with rounded corners to the path. The xRadius and yRadius arguments specify the radii of the
1652 ellipses defining the corners of the rounded rectangle.
1654 static v8::Handle<v8::Value> ctx2d_roundedRect(const v8::Arguments &args)
1656 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1660 if (args.Length() == 6) {
1661 r->context->roundedRect(args[0]->NumberValue(),
1662 args[1]->NumberValue(),
1663 args[2]->NumberValue(),
1664 args[3]->NumberValue(),
1665 args[4]->NumberValue(),
1666 args[5]->NumberValue());
1673 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::ellipse(real x, real y, real w, real h)
1675 Creates an ellipse within the bounding rectangle defined by its top-left corner at (\a x, \ y), width \a w and height \a h,
1676 and adds it to the path as a closed subpath.
1678 The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
1680 static v8::Handle<v8::Value> ctx2d_ellipse(const v8::Arguments &args)
1682 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1686 if (args.Length() == 6) {
1687 r->context->ellipse(args[0]->NumberValue(),
1688 args[1]->NumberValue(),
1689 args[2]->NumberValue(),
1690 args[3]->NumberValue());
1697 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::text(string text, real x, real y)
1699 Adds the given \a text to the path as a set of closed subpaths created from the current context font supplied.
1700 The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (x, y).
1702 static v8::Handle<v8::Value> ctx2d_text(const v8::Arguments &args)
1704 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1707 QV8Engine *engine = V8ENGINE();
1708 if (args.Length() == 3) {
1709 r->context->text(engine->toString(args[0]),
1710 args[1]->NumberValue(),
1711 args[2]->NumberValue());
1718 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::stroke()
1720 Strokes the subpaths with the current stroke style.
1722 See http://www.w3.org/TR/2dcontext/#dom-context-2d-stroke for details.
1724 \sa QtQuick2::Context2D::strokeStyle
1726 static v8::Handle<v8::Value> ctx2d_stroke(const v8::Arguments &args)
1728 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1732 r->context->buffer()->stroke(r->context->m_path);
1738 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::isPointInPath(real x, real y)
1740 Returns true if the given point is in the current path.
1742 See http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath for details.
1744 static v8::Handle<v8::Value> ctx2d_isPointInPath(const v8::Arguments &args)
1746 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1750 bool pointInPath = false;
1751 if (args.Length() == 2) {
1752 pointInPath = r->context->isPointInPath(args[0]->NumberValue(),
1753 args[1]->NumberValue());
1756 return v8::Boolean::New(pointInPath);
1759 static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
1761 V8THROW_ERROR("Context2D::drawFocusRing is not supported")
1765 static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
1767 V8THROW_ERROR("Context2D::setCaretSelectionRect is not supported")
1771 static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
1773 V8THROW_ERROR("Context2D::caretBlinkRate is not supported")
1779 \qmlproperty string QtQuick2::Context2D::font
1780 Holds the current font settings, default value is "10px sans-serif".
1782 See http://www.w3.org/TR/2dcontext/#dom-context-2d-font for details.
1784 v8::Handle<v8::Value> ctx2d_font(v8::Local<v8::String>, const v8::AccessorInfo &info)
1786 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1789 QV8Engine *engine = V8ENGINE_ACCESSOR();
1791 return engine->toString(r->context->m_fontString);
1794 static void ctx2d_font_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1796 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1797 CHECK_CONTEXT_SETTER(r)
1799 QV8Engine *engine = V8ENGINE_ACCESSOR();
1800 QString fs = engine->toString(value);
1801 if (fs != r->context->m_fontString) {
1802 r->context->m_fontString = fs;
1803 QFont font = qt_font_from_string(fs);
1804 r->context->state.font = font;
1809 \qmlproperty string QtQuick2::Context2D::textAlign
1811 Holds the current text alignment settings.
1812 The possible values are:
1820 Other values are ignored. The default is start.
1822 v8::Handle<v8::Value> ctx2d_textAlign(v8::Local<v8::String>, const v8::AccessorInfo &info)
1824 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1826 QV8Engine *engine = V8ENGINE_ACCESSOR();
1827 switch (r->context->state.textAlign) {
1828 case QSGContext2D::Start:
1829 return engine->toString(QLatin1String("start"));
1830 case QSGContext2D::End:
1831 return engine->toString(QLatin1String("end"));
1832 case QSGContext2D::Left:
1833 return engine->toString(QLatin1String("left"));
1834 case QSGContext2D::Right:
1835 return engine->toString(QLatin1String("right"));
1836 case QSGContext2D::Center:
1837 return engine->toString(QLatin1String("center"));
1841 return engine->toString(QLatin1String("start"));
1844 static void ctx2d_textAlign_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1846 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1847 CHECK_CONTEXT_SETTER(r)
1848 QV8Engine *engine = V8ENGINE_ACCESSOR();
1850 QString textAlign = engine->toString(value);
1852 QSGContext2D::TextAlignType ta;
1853 if (textAlign == QLatin1String("start"))
1854 ta = QSGContext2D::Start;
1855 else if (textAlign == QLatin1String("end"))
1856 ta = QSGContext2D::End;
1857 else if (textAlign == QLatin1String("left"))
1858 ta = QSGContext2D::Left;
1859 else if (textAlign == QLatin1String("right"))
1860 ta = QSGContext2D::Right;
1861 else if (textAlign == QLatin1String("center"))
1862 ta = QSGContext2D::Center;
1864 if (ta != r->context->state.textAlign) {
1865 r->context->state.textAlign = ta;
1870 \qmlproperty string QtQuick2::Context2D::textBaseline
1872 Holds the current baseline alignment settings.
1873 The possible values are:
1882 Other values are ignored. The default value is "alphabetic".
1883 See http://www.w3.org/TR/2dcontext/#dom-context-2d-textbaseline for details.
1885 v8::Handle<v8::Value> ctx2d_textBaseline(v8::Local<v8::String>, const v8::AccessorInfo &info)
1887 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1890 QV8Engine *engine = V8ENGINE_ACCESSOR();
1891 switch (r->context->state.textBaseline) {
1892 case QSGContext2D::Alphabetic:
1893 return engine->toString(QLatin1String("alphabetic"));
1894 case QSGContext2D::Hanging:
1895 return engine->toString(QLatin1String("hanging"));
1896 case QSGContext2D::Top:
1897 return engine->toString(QLatin1String("top"));
1898 case QSGContext2D::Bottom:
1899 return engine->toString(QLatin1String("bottom"));
1900 case QSGContext2D::Middle:
1901 return engine->toString(QLatin1String("middle"));
1905 return engine->toString(QLatin1String("alphabetic"));
1908 static void ctx2d_textBaseline_set(v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
1910 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
1911 CHECK_CONTEXT_SETTER(r)
1912 QV8Engine *engine = V8ENGINE_ACCESSOR();
1913 QString textBaseline = engine->toString(value);
1915 QSGContext2D::TextBaseLineType tb;
1916 if (textBaseline == QLatin1String("alphabetic"))
1917 tb = QSGContext2D::Alphabetic;
1918 else if (textBaseline == QLatin1String("hanging"))
1919 tb = QSGContext2D::Hanging;
1920 else if (textBaseline == QLatin1String("top"))
1921 tb = QSGContext2D::Top;
1922 else if (textBaseline == QLatin1String("bottom"))
1923 tb = QSGContext2D::Bottom;
1924 else if (textBaseline == QLatin1String("middle"))
1925 tb = QSGContext2D::Middle;
1927 if (tb != r->context->state.textBaseline) {
1928 r->context->state.textBaseline = tb;
1933 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::fillText(text, x, y)
1934 Fills the given text at the given position.
1935 See http://www.w3.org/TR/2dcontext/#dom-context-2d-filltext for details.
1937 static v8::Handle<v8::Value> ctx2d_fillText(const v8::Arguments &args)
1939 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1943 QV8Engine *engine = V8ENGINE();
1945 if (args.Length() == 3) {
1946 QPainterPath textPath = r->context->createTextGlyphs(args[1]->NumberValue(),
1947 args[2]->NumberValue(),
1948 engine->toString(args[0]));
1949 r->context->buffer()->fill(textPath);
1955 \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::strokeText(text, x, y)
1956 Strokes the given text at the given position.
1957 See http://www.w3.org/TR/2dcontext/#dom-context-2d-stroketext for details.
1959 static v8::Handle<v8::Value> ctx2d_strokeText(const v8::Arguments &args)
1961 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
1965 QV8Engine *engine = V8ENGINE();
1967 if (args.Length() == 3) {
1968 QPainterPath textPath = r->context->createTextGlyphs(args[1]->NumberValue(),
1969 args[2]->NumberValue(),
1970 engine->toString(args[0]));
1971 r->context->buffer()->stroke(textPath);
1977 \qmlclass QtQuick2::TextMetrics
1978 \inqmlmodule QtQuick 2
1980 \brief The Context2D TextMetrics interface.
1981 The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
1982 See http://www.w3.org/TR/2dcontext/#textmetrics for more details.
1984 \sa QtQuick2::Context2D::measureText
1985 \sa QtQuick2::TextMetrics::width
1989 \qmlproperty int QtQuick2::TextMetrics::width
1990 Holds the advance width of the text that was passed to the QtQuick2::Context2D::measureText() method.
1991 This property is read only.
1992 See http://www.w3.org/TR/2dcontext/#dom-textmetrics-width for more details.
1996 \qmlmethod variant QtQuick2::Context2D::measureText(text)
1997 Returns a TextMetrics object with the metrics of the given text in the current font.
1998 See http://www.w3.org/TR/2dcontext/#dom-context-2d-measuretext for details.
2000 static v8::Handle<v8::Value> ctx2d_measureText(const v8::Arguments &args)
2002 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2006 QV8Engine *engine = V8ENGINE();
2008 if (args.Length() == 1) {
2009 QFontMetrics fm(r->context->state.font);
2010 uint width = fm.width(engine->toString(args[0]));
2011 v8::Local<v8::Object> tm = v8::Object::New();
2012 tm->Set(v8::String::New("width"), v8::Number::New(width));
2016 return v8::Undefined();
2021 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy)
2022 Draws the given \a image on the canvas at position (\a dx, \a dy).
2024 The \a image type can be an Image item or a image url. When given as Image
2025 type, if the image isn't fully loaded, will draw nothing. When given as url string,
2026 the context loads the image asynchorously and redraw the canvas when the image is loaded.
2028 See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
2031 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real dx, real dy, real dw, real dh)
2032 Draws the given item as \a image onto the canvas at point (\a dx, \a dy) and with width \a dw,
2034 See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
2037 \qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
2038 Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
2039 onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
2040 See http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage for more details.
2042 static v8::Handle<v8::Value> ctx2d_drawImage(const v8::Arguments &args)
2044 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2048 QV8Engine *engine = V8ENGINE();
2050 //TODO: handle exceptions
2052 qreal sx, sy, sw, sh, dx, dy, dw, dh;
2054 if (args.Length() != 3 && args.Length() != 5 && args.Length() != 9) {
2061 if (args[0]->IsString()) {
2062 image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2063 } /*else if (args[0]->IsObject()) {
2064 QSGImage* imageItem = qobject_cast<QSGImage*>(engine->toQObject(args[0]->ToObject()));
2066 image = imageItem->pixmap().toImage();
2072 if (args.Length() == 3) {
2073 dx = args[1]->NumberValue();
2074 dy = args[2]->NumberValue();
2077 sw = image.isNull()? -1 : image.width();
2078 sh = image.isNull()? -1 : image.height();
2081 } else if (args.Length() == 5) {
2084 sw = image.isNull()? -1 : image.width();
2085 sh = image.isNull()? -1 : image.height();
2086 dx = args[1]->NumberValue();
2087 dy = args[2]->NumberValue();
2088 dw = args[3]->NumberValue();
2089 dh = args[4]->NumberValue();
2090 } else if (args.Length() == 9) {
2091 sx = args[1]->NumberValue();
2092 sy = args[2]->NumberValue();
2093 sw = args[3]->NumberValue();
2094 sh = args[4]->NumberValue();
2095 dx = args[5]->NumberValue();
2096 dy = args[6]->NumberValue();
2097 dw = args[7]->NumberValue();
2098 dh = args[8]->NumberValue();
2104 r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
2109 // pixel manipulation
2111 \qmlclass QtQuick2::CanvasImageData
2115 \qmlproperty QtQuick2::CanvasImageData::width
2116 Holds the actual width dimension of the data in the ImageData object, in device pixels.
2118 v8::Handle<v8::Value> ctx2d_imageData_width(v8::Local<v8::String>, const v8::AccessorInfo &args)
2120 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2122 return v8::Integer::New(0);
2123 return v8::Integer::New(r->image.width());
2127 \qmlproperty QtQuick2::CanvasImageData::height
2128 Holds the actual height dimension of the data in the ImageData object, in device pixels.
2130 v8::Handle<v8::Value> ctx2d_imageData_height(v8::Local<v8::String>, const v8::AccessorInfo &args)
2132 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2134 return v8::Integer::New(0);
2136 return v8::Integer::New(r->image.height());
2140 \qmlproperty QtQuick2::CanvasImageData::data
2141 Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
2143 v8::Handle<v8::Value> ctx2d_imageData_data(v8::Local<v8::String>, const v8::AccessorInfo &args)
2145 return args.This()->GetInternalField(0);
2148 static v8::Handle<v8::Value> ctx2d_imageData_mirror(const v8::Arguments &args)
2150 bool horizontal = false, vertical = true;
2151 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2155 return v8::Undefined();
2158 if (args.Length() > 2) {
2160 return v8::Undefined();
2163 if (args.Length() == 1) {
2164 horizontal = args[0]->BooleanValue();
2165 } else if (args.Length() == 2) {
2166 horizontal = args[0]->BooleanValue();
2167 vertical = args[1]->BooleanValue();
2170 r->image = r->image.mirrored(horizontal, vertical);
2175 static v8::Handle<v8::Value> ctx2d_imageData_filter(const v8::Arguments &args)
2177 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This()->GetInternalField(0)->ToObject());
2181 return v8::Undefined();
2184 if (args.Length() >= 1) {
2185 int filterFlag = args[0]->IntegerValue();
2186 switch(filterFlag) {
2187 case QSGCanvasItem::GrayScale :
2189 for (int y = 0; y < r->image.height(); ++y) {
2190 QRgb *row = (QRgb*)r->image.scanLine(y);
2191 for (int x = 0; x < r->image.width(); ++x) {
2192 unsigned char* rgb = ((unsigned char*)&row[x]);
2193 rgb[0] = rgb[1] = rgb[2] = qGray(rgb[0], rgb[1], rgb[2]);
2198 case QSGCanvasItem::Threshold :
2200 int threshold = 127;
2201 if (args.Length() > 1)
2202 threshold = args[1]->IntegerValue();
2204 for (int y = 0; y < r->image.height(); ++y) {
2205 QRgb *row = (QRgb*)r->image.scanLine(y);
2206 for (int x = 0; x < r->image.width(); ++x) {
2207 unsigned char* rgb = ((unsigned char*)&row[x]);
2208 unsigned char v = qGray(rgb[0], rgb[1], rgb[2]) >= threshold ? 255 : 0;
2209 rgb[0] = rgb[1] = rgb[2] = v;
2214 case QSGCanvasItem::Brightness :
2217 if (args.Length() > 1)
2218 adjustment = 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*)&row[x])[0] += adjustment;
2224 ((unsigned char*)&row[x])[1] += adjustment;
2225 ((unsigned char*)&row[x])[2] += adjustment;
2230 case QSGCanvasItem::Invert :
2232 r->image.invertPixels();
2235 case QSGCanvasItem::Blur :
2237 QImage blurred(r->image.size(), QImage::Format_ARGB32);
2239 if (args.Length() > 1)
2240 blur = args[1]->NumberValue();
2242 blurred.fill(Qt::transparent);
2243 QPainter blurPainter(&blurred);
2244 qt_blurImage(&blurPainter, r->image, blur, true, false);
2249 case QSGCanvasItem::Opaque :
2251 for (int y = 0; y < r->image.height(); ++y) {
2252 QRgb *row = (QRgb*)r->image.scanLine(y);
2253 for (int x = 0; x < r->image.width(); ++x) {
2254 ((unsigned char*)&row[x])[3] = 255;
2259 case QSGCanvasItem::Convolute :
2261 if (args.Length() > 1 && args[1]->IsArray()) {
2262 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(args[1]);
2263 QVector<int> weights;
2264 for (uint32_t i = 0; i < array->Length(); ++i)
2265 weights.append(array->Get(i)->NumberValue());
2266 int sides = qRound(qSqrt(weights.size()));
2267 int half = qFloor(sides/2);
2269 QImage image = QImage(r->image.size(), QImage::Format_ARGB32);
2270 int w = r->image.width();
2271 int h = r->image.height();
2272 for (int y = 0; y < image.height(); ++y) {
2273 QRgb *dRow = (QRgb*)image.scanLine(y);
2274 for (int x = 0; x < image.width(); ++x) {
2275 unsigned char* dRgb = ((unsigned char*)&dRow[x]);
2276 unsigned char red=0, green=0, blue=0, alpha=0;
2280 for (int cy=0; cy<sides; cy++) {
2281 for (int cx=0; cx<sides; cx++) {
2282 int scy = sy + cy - half;
2283 int scx = sx + cx - half;
2284 if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
2285 QRgb *sRow = (QRgb*)(r->image.scanLine(scy));
2286 unsigned char* sRgb = ((unsigned char*)&sRow[scx]);
2287 int wt = weights[cy*sides+cx];
2288 red += sRgb[0] * wt;
2289 green += sRgb[1] * wt;
2290 blue += sRgb[2] * wt;
2291 alpha += sRgb[3] * wt;
2315 \qmlclass QtQuick2::CanvasPixelArray
2316 The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
2317 See http://www.w3.org/TR/2dcontext/#canvaspixelarray for more details.
2321 \qmlproperty QtQuick2::CanvasPixelArray::length
2322 The CanvasPixelArray object represents h×w×4 integers which w and h comes from CanvasImageData.
2323 The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
2325 v8::Handle<v8::Value> ctx2d_pixelArray_length(v8::Local<v8::String>, const v8::AccessorInfo &args)
2327 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2328 if (!r || r->image.isNull()) return v8::Undefined();
2330 return v8::Integer::New(r->image.width() * r->image.height() * 4);
2333 v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::AccessorInfo& args)
2335 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
2337 if (r && index && index < r->image.width() * r->image.height() * 4) {
2338 const int w = r->image.width();
2339 const int h = r->image.height();
2340 const int row = (index / 4) / w;
2341 const int col = (index / 4) % w;
2342 const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
2344 switch (index % 4) {
2346 return v8::Integer::New(qRed(*pixel));
2348 return v8::Integer::New(qGreen(*pixel));
2350 return v8::Integer::New(qBlue(*pixel));
2352 return v8::Integer::New(qAlpha(*pixel));
2355 return v8::Undefined();
2358 v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
2360 QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
2362 const int v = value->Uint32Value();
2363 if (r && index > 0 && index < r->image.width() * r->image.height() * 4 && v > 0 && v <= 255) {
2364 const int w = r->image.width();
2365 const int h = r->image.height();
2366 const int row = (index / 4) / w;
2367 const int col = (index / 4) % w;
2369 QRgb* pixel = reinterpret_cast<QRgb*>(r->image.scanLine(row));
2371 switch (index % 4) {
2373 *pixel = qRgba(v, qGreen(*pixel), qBlue(*pixel), qAlpha(*pixel));
2376 *pixel = qRgba(qRed(*pixel), v, qBlue(*pixel), qAlpha(*pixel));
2379 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), v, qAlpha(*pixel));
2382 *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v);
2386 return v8::Undefined();
2389 \qmlmethod QtQuick2::CanvasImageData createImageData(real sw, real sh)
2390 Creates a CanvasImageData object with the given dimensions(\a sw, \a sh).
2393 \qmlmethod QtQuick2::CanvasImageData createImageData(QtQuick2::CanvasImageData imageData)
2394 Creates a CanvasImageData object with the same dimensions as the argument.
2397 \qmlmethod QtQuick2::CanvasImageData createImageData(Url imageUrl)
2398 Creates a CanvasImageData object with the given image loaded from \a imageUrl.
2399 Note:The \a imageUrl must be already loaded before this function call, if not, an empty
2400 CanvasImageData obect will be returned.
2402 \sa QtQuick2::Canvas::loadImage, QtQuick2::Canvas::unloadImage, QtQuick2::Canvas::isImageLoaded
2404 static v8::Handle<v8::Value> ctx2d_createImageData(const v8::Arguments &args)
2406 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2410 QV8Engine *engine = V8ENGINE();
2412 if (args.Length() == 1) {
2413 if (args[0]->IsObject()) {
2414 v8::Local<v8::Object> imgData = args[0]->ToObject();
2415 QV8Context2DPixelArrayResource *pa = v8_resource_cast<QV8Context2DPixelArrayResource>(imgData->GetInternalField(0)->ToObject());
2417 qreal w = imgData->Get(v8::String::New("width"))->NumberValue();
2418 qreal h = imgData->Get(v8::String::New("height"))->NumberValue();
2419 return qt_create_image_data(w, h, engine, QImage());
2421 } else if (args[0]->IsString()) {
2422 QImage image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
2423 return qt_create_image_data(image.width(), image.height(), engine, image);
2425 } else if (args.Length() == 2) {
2426 qreal w = args[0]->NumberValue();
2427 qreal h = args[1]->NumberValue();
2429 return qt_create_image_data(w, h, engine, QImage());
2431 return v8::Undefined();
2435 \qmlmethod QtQuick2::CanvasImageData getImageData(real sx, real sy, real sw, real sh)
2436 Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
2438 static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
2440 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2443 QV8Engine *engine = V8ENGINE();
2444 if (args.Length() == 4) {
2445 qreal x = args[0]->NumberValue();
2446 qreal y = args[1]->NumberValue();
2447 qreal w = args[2]->NumberValue();
2448 qreal h = args[3]->NumberValue();
2449 QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
2450 if (image.format() != QImage::Format_ARGB32)
2451 image = image.convertToFormat(QImage::Format_ARGB32);
2452 v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
2460 \qmlmethod QtQuick2::Context2D putImageData(QtQuick2::CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
2461 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.
2463 static v8::Handle<v8::Value> ctx2d_putImageData(const v8::Arguments &args)
2465 QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
2467 if (args.Length() != 3 && args.Length() != 7)
2468 return v8::Undefined();
2470 if (args[0]->IsNull() || !args[0]->IsObject()) {
2471 V8THROW_ERROR("Context2D::putImageData, the image data type mismatch");
2473 qreal dx = args[1]->NumberValue();
2474 qreal dy = args[2]->NumberValue();
2475 qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
2477 v8::Local<v8::Object> imageData = args[0]->ToObject();
2478 QV8Context2DPixelArrayResource *pixelArray = v8_resource_cast<QV8Context2DPixelArrayResource>(imageData->Get(v8::String::New("data"))->ToObject());
2480 w = imageData->Get(v8::String::New("width"))->NumberValue();
2481 h = imageData->Get(v8::String::New("height"))->NumberValue();
2483 if (args.Length() == 7) {
2484 dirtyX = args[3]->NumberValue();
2485 dirtyY = args[4]->NumberValue();
2486 dirtyWidth = args[5]->NumberValue();
2487 dirtyHeight = args[6]->NumberValue();
2488 if (dirtyWidth < 0) {
2489 dirtyX = dirtyX+dirtyWidth;
2490 dirtyWidth = -dirtyWidth;
2493 if (dirtyHeight < 0) {
2494 dirtyY = dirtyY+dirtyHeight;
2495 dirtyHeight = -dirtyHeight;
2499 dirtyWidth = dirtyWidth+dirtyX;
2504 dirtyHeight = dirtyHeight+dirtyY;
2508 if (dirtyX+dirtyWidth > w) {
2509 dirtyWidth = w - dirtyX;
2512 if (dirtyY+dirtyHeight > h) {
2513 dirtyHeight = h - dirtyY;
2516 if (dirtyWidth <=0 || dirtyHeight <= 0)
2525 QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
2526 r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
2532 \qmlclass QtQuick2::CanvasGradient
2533 \inqmlmodule QtQuick 2
2535 \brief The Context2D opaque CanvasGradient interface.
2539 \qmlmethod QtQuick2::CanvasGradient QtQuick2::CanvasGradient::addColorStop(real offsetof, string color)
2540 Adds a color stop with the given color to the gradient at the given offset.
2541 0.0 is the offset at one end of the gradient, 1.0 is the offset at the other end.
2543 static v8::Handle<v8::Value> ctx2d_gradient_addColorStop(const v8::Arguments &args)
2545 QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(args.This());
2547 V8THROW_ERROR("Not a CanvasGradient object");
2549 QV8Engine *engine = V8ENGINE();
2551 if (args.Length() == 2) {
2553 if (!style->brush.gradient())
2554 V8THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
2555 QGradient gradient = *(style->brush.gradient());
2556 qreal pos = args[0]->NumberValue();
2557 QColor color = qt_color_from_string(engine->toString(args[1]));
2558 if (pos < 0.0 || pos > 1.0) {
2559 //Throws an INDEX_SIZE_ERR exception
2560 V8THROW_ERROR("CanvasGradient: parameter offset out of range");
2563 if (color.isValid()) {
2564 gradient.setColorAt(pos, color);
2566 //Throws a SYNTAX_ERR exception
2567 V8THROW_ERROR("CanvasGradient: parameter color is not a valid color string");
2569 style->brush = gradient;
2576 void QSGContext2D::beginPath()
2578 m_path = QPainterPath();
2579 m_path.setFillRule(state.fillRule);
2582 void QSGContext2D::closePath()
2584 if (m_path.isEmpty())
2587 QRectF boundRect = m_path.boundingRect();
2588 if (boundRect.width() || boundRect.height())
2589 m_path.closeSubpath();
2592 void QSGContext2D::moveTo( qreal x, qreal y)
2594 m_path.moveTo(state.matrix.map(QPointF(x, y)));
2597 void QSGContext2D::lineTo( qreal x, qreal y)
2599 m_path.lineTo(state.matrix.map(QPointF(x, y)));
2602 void QSGContext2D::quadraticCurveTo(qreal cpx, qreal cpy,
2605 m_path.quadTo(state.matrix.map(QPointF(cpx, cpy)),
2606 state.matrix.map(QPointF(x, y)));
2609 void QSGContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
2610 qreal cp2x, qreal cp2y,
2613 m_path.cubicTo(state.matrix.map(QPointF(cp1x, cp1y)),
2614 state.matrix.map(QPointF(cp2x, cp2y)),
2615 state.matrix.map(QPointF(x, y)));
2618 void QSGContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
2620 QPointF p0(m_path.currentPosition());
2622 QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
2623 QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
2624 float p1p0_length = qSqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
2625 float p1p2_length = qSqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
2627 double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
2629 // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
2630 // We could have used areCollinear() here, but since we're reusing
2631 // the variables computed above later on we keep this logic.
2632 if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
2637 float tangent = radius / tan(acos(cos_phi) / 2);
2638 float factor_p1p0 = tangent / p1p0_length;
2639 QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
2641 QPointF orth_p1p0(p1p0.y(), -p1p0.x());
2642 float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
2643 float factor_ra = radius / orth_p1p0_length;
2645 // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
2646 double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
2647 if (cos_alpha < 0.f)
2648 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
2650 QPointF p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
2652 // calculate angles for addArc
2653 orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
2654 float sa = acos(orth_p1p0.x() / orth_p1p0_length);
2655 if (orth_p1p0.y() < 0.f)
2658 // anticlockwise logic
2659 bool anticlockwise = false;
2661 float factor_p1p2 = tangent / p1p2_length;
2662 QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
2663 QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
2664 float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
2665 float ea = acos(orth_p1p2.x() / orth_p1p2_length);
2666 if (orth_p1p2.y() < 0)
2668 if ((sa > ea) && ((sa - ea) < Q_PI))
2669 anticlockwise = true;
2670 if ((sa < ea) && ((ea - sa) > Q_PI))
2671 anticlockwise = true;
2673 arc(p.x(), p.y(), radius, sa, ea, anticlockwise, false);
2676 void QSGContext2D::arcTo(qreal x1, qreal y1,
2680 QPointF st = state.matrix.map(QPointF(x1, y1));
2681 QPointF end = state.matrix.map(QPointF(x2, y2));
2683 if (!m_path.elementCount()) {
2685 } else if (st == m_path.currentPosition() || st == end || !radius) {
2688 addArcTo(st, end, radius);
2692 void QSGContext2D::rect(qreal x, qreal y,
2695 m_path.addPolygon(state.matrix.map(QRectF(x, y, w, h)));
2698 void QSGContext2D::roundedRect(qreal x, qreal y,
2703 path.addRoundedRect(QRectF(x, y, w, h), xr, yr, Qt::AbsoluteSize);
2704 m_path.addPath(state.matrix.map(path));
2707 void QSGContext2D::ellipse(qreal x, qreal y,
2711 path.addEllipse(x, y, w, h);
2712 m_path.addPath(state.matrix.map(path));
2715 void QSGContext2D::text(const QString& str, qreal x, qreal y)
2718 path.addText(x, y, state.font, str);
2719 m_path.addPath(state.matrix.map(path));
2722 void QSGContext2D::arc(qreal xc,
2732 QPointF point = state.matrix.map(QPointF(xc, yc));
2738 // In Qt we don't switch the coordinate system for degrees
2739 // and still use the 0,0 as bottom left for degrees so we need
2743 antiClockWise = !antiClockWise;
2746 float sa = DEGREES(sar);
2747 float ea = DEGREES(ear);
2751 double xs = xc - radius;
2752 double ys = yc - radius;
2753 double width = radius*2;
2754 double height = radius*2;
2755 if ((!antiClockWise && (ea - sa >= 360)) || (antiClockWise && (sa - ea >= 360)))
2756 // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
2757 // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
2758 // circumference of this circle.
2761 if (!antiClockWise && (ea < sa)) {
2763 } else if (antiClockWise && (sa < ea)) {
2766 //### this is also due to switched coordinate system
2767 // we would end up with a 0 span instead of 360
2768 if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
2769 qFuzzyCompare(qAbs(span), 360))) {
2772 if (!m_path.elementCount())
2773 m_path.moveTo(xs, ys);
2778 QPointF currentPos = m_path.currentPosition();
2779 QPointF startPos = QPointF(xc + radius * qCos(sar),
2780 yc - radius * qSin(sar));
2781 if (currentPos != startPos)
2782 m_path.lineTo(startPos);
2785 m_path.arcTo(xs, ys, width, height, sa, span);
2788 int baseLineOffset(QSGContext2D::TextBaseLineType value, const QFontMetrics &metrics)
2792 case QSGContext2D::QSGContext2D::Top:
2794 case QSGContext2D::QSGContext2D::Alphabetic:
2795 case QSGContext2D::QSGContext2D::Middle:
2796 case QSGContext2D::QSGContext2D::Hanging:
2797 offset = metrics.ascent();
2799 case QSGContext2D::QSGContext2D::Bottom:
2800 offset = metrics.height();
2806 static int textAlignOffset(QSGContext2D::TextAlignType value, const QFontMetrics &metrics, const QString &text)
2809 if (value == QSGContext2D::Start)
2810 value = QApplication::layoutDirection() == Qt::LeftToRight ? QSGContext2D::Left : QSGContext2D::Right;
2811 else if (value == QSGContext2D::End)
2812 value = QApplication::layoutDirection() == Qt::LeftToRight ? QSGContext2D::Right: QSGContext2D::Left;
2814 case QSGContext2D::QSGContext2D::Center:
2815 offset = metrics.width(text)/2;
2817 case QSGContext2D::QSGContext2D::Right:
2818 offset = metrics.width(text);
2819 case QSGContext2D::QSGContext2D::Left:
2827 QImage QSGContext2D::createImage(const QUrl& url)
2829 return m_canvas->loadedImage(url);
2832 QPainterPath QSGContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
2834 const QFontMetrics metrics(state.font);
2835 int yoffset = baseLineOffset(static_cast<QSGContext2D::TextBaseLineType>(state.textBaseline), metrics);
2836 int xoffset = textAlignOffset(static_cast<QSGContext2D::TextAlignType>(state.textAlign), metrics, text);
2838 QPainterPath textPath;
2840 textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
2841 textPath = state.matrix.map(textPath);
2846 bool QSGContext2D::isPointInPath(qreal x, qreal y) const
2848 return m_path.contains(QPointF(x, y));
2851 QSGContext2D::QSGContext2D(QSGCanvasItem* item)
2853 , m_buffer(new QSGContext2DCommandBuffer)
2859 QSGContext2D::~QSGContext2D()
2863 v8::Handle<v8::Object> QSGContext2D::v8value() const
2868 QSGContext2DEngineData::QSGContext2DEngineData(QV8Engine *engine)
2870 v8::HandleScope handle_scope;
2871 v8::Context::Scope scope(engine->context());
2873 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
2874 ft->InstanceTemplate()->SetHasExternalResource(true);
2875 ft->PrototypeTemplate()->SetAccessor(v8::String::New("canvas"), ctx2d_canvas, 0, v8::External::Wrap(engine));
2876 ft->PrototypeTemplate()->Set(v8::String::New("restore"), V8FUNCTION(ctx2d_restore, engine));
2877 ft->PrototypeTemplate()->Set(v8::String::New("reset"), V8FUNCTION(ctx2d_reset, engine));
2878 ft->PrototypeTemplate()->Set(v8::String::New("save"), V8FUNCTION(ctx2d_save, engine));
2879 ft->PrototypeTemplate()->Set(v8::String::New("rotate"), V8FUNCTION(ctx2d_rotate, engine));
2880 ft->PrototypeTemplate()->Set(v8::String::New("scale"), V8FUNCTION(ctx2d_scale, engine));
2881 ft->PrototypeTemplate()->Set(v8::String::New("resetTransform"), V8FUNCTION(ctx2d_resetTransform, engine));
2882 ft->PrototypeTemplate()->Set(v8::String::New("setTransform"), V8FUNCTION(ctx2d_setTransform, engine));
2883 ft->PrototypeTemplate()->Set(v8::String::New("transform"), V8FUNCTION(ctx2d_transform, engine));
2884 ft->PrototypeTemplate()->Set(v8::String::New("translate"), V8FUNCTION(ctx2d_translate, engine));
2885 ft->PrototypeTemplate()->Set(v8::String::New("shear"), V8FUNCTION(ctx2d_shear, engine));
2886 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalAlpha"), ctx2d_globalAlpha, ctx2d_globalAlpha_set, v8::External::Wrap(engine));
2887 ft->InstanceTemplate()->SetAccessor(v8::String::New("globalCompositeOperation"), ctx2d_globalCompositeOperation, ctx2d_globalCompositeOperation_set, v8::External::Wrap(engine));
2888 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillRule"), ctx2d_fillRule, ctx2d_fillRule_set, v8::External::Wrap(engine));
2889 ft->InstanceTemplate()->SetAccessor(v8::String::New("fillStyle"), ctx2d_fillStyle, ctx2d_fillStyle_set, v8::External::Wrap(engine));
2890 ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
2891 ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
2892 ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
2893 ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
2894 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
2895 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
2896 ft->InstanceTemplate()->SetAccessor(v8::String::New("lineWidth"), ctx2d_lineWidth, ctx2d_lineWidth_set, v8::External::Wrap(engine));
2897 ft->InstanceTemplate()->SetAccessor(v8::String::New("miterLimit"), ctx2d_miterLimit, ctx2d_miterLimit_set, v8::External::Wrap(engine));
2898 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowBlur"), ctx2d_shadowBlur, ctx2d_shadowBlur_set, v8::External::Wrap(engine));
2899 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowColor"), ctx2d_shadowColor, ctx2d_shadowColor_set, v8::External::Wrap(engine));
2900 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetX"), ctx2d_shadowOffsetX, ctx2d_shadowOffsetX_set, v8::External::Wrap(engine));
2901 ft->InstanceTemplate()->SetAccessor(v8::String::New("shadowOffsetY"), ctx2d_shadowOffsetY, ctx2d_shadowOffsetY_set, v8::External::Wrap(engine));
2902 ft->InstanceTemplate()->SetAccessor(v8::String::New("path"), ctx2d_path, ctx2d_path_set, v8::External::Wrap(engine));
2903 ft->PrototypeTemplate()->Set(v8::String::New("clearRect"), V8FUNCTION(ctx2d_clearRect, engine));
2904 ft->PrototypeTemplate()->Set(v8::String::New("fillRect"), V8FUNCTION(ctx2d_fillRect, engine));
2905 ft->PrototypeTemplate()->Set(v8::String::New("strokeRect"), V8FUNCTION(ctx2d_strokeRect, engine));
2906 ft->PrototypeTemplate()->Set(v8::String::New("arc"), V8FUNCTION(ctx2d_arc, engine));
2907 ft->PrototypeTemplate()->Set(v8::String::New("arcTo"), V8FUNCTION(ctx2d_arcTo, engine));
2908 ft->PrototypeTemplate()->Set(v8::String::New("beginPath"), V8FUNCTION(ctx2d_beginPath, engine));
2909 ft->PrototypeTemplate()->Set(v8::String::New("bezierCurveTo"), V8FUNCTION(ctx2d_bezierCurveTo, engine));
2910 ft->PrototypeTemplate()->Set(v8::String::New("clip"), V8FUNCTION(ctx2d_clip, engine));
2911 ft->PrototypeTemplate()->Set(v8::String::New("closePath"), V8FUNCTION(ctx2d_closePath, engine));
2912 ft->PrototypeTemplate()->Set(v8::String::New("fill"), V8FUNCTION(ctx2d_fill, engine));
2913 ft->PrototypeTemplate()->Set(v8::String::New("lineTo"), V8FUNCTION(ctx2d_lineTo, engine));
2914 ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine));
2915 ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine));
2916 ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine));
2917 ft->PrototypeTemplate()->Set(v8::String::New("roundedRect "), V8FUNCTION(ctx2d_roundedRect, engine));
2918 ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine));
2919 ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine));
2920 ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine));
2921 ft->PrototypeTemplate()->Set(v8::String::New("isPointInPath"), V8FUNCTION(ctx2d_isPointInPath, engine));
2922 ft->PrototypeTemplate()->Set(v8::String::New("drawFocusRing"), V8FUNCTION(ctx2d_drawFocusRing, engine));
2923 ft->PrototypeTemplate()->Set(v8::String::New("caretBlinkRate"), V8FUNCTION(ctx2d_caretBlinkRate, engine));
2924 ft->PrototypeTemplate()->Set(v8::String::New("setCaretSelectionRect"), V8FUNCTION(ctx2d_setCaretSelectionRect, engine));
2925 ft->InstanceTemplate()->SetAccessor(v8::String::New("font"), ctx2d_font, ctx2d_font_set, v8::External::Wrap(engine));
2926 ft->InstanceTemplate()->SetAccessor(v8::String::New("textAlign"), ctx2d_textAlign, ctx2d_textAlign_set, v8::External::Wrap(engine));
2927 ft->InstanceTemplate()->SetAccessor(v8::String::New("textBaseline"), ctx2d_textBaseline, ctx2d_textBaseline_set, v8::External::Wrap(engine));
2928 ft->PrototypeTemplate()->Set(v8::String::New("fillText"), V8FUNCTION(ctx2d_fillText, engine));
2929 ft->PrototypeTemplate()->Set(v8::String::New("measureText"), V8FUNCTION(ctx2d_measureText, engine));
2930 ft->PrototypeTemplate()->Set(v8::String::New("strokeText"), V8FUNCTION(ctx2d_strokeText, engine));
2931 ft->PrototypeTemplate()->Set(v8::String::New("drawImage"), V8FUNCTION(ctx2d_drawImage, engine));
2932 ft->PrototypeTemplate()->Set(v8::String::New("createImageData"), V8FUNCTION(ctx2d_createImageData, engine));
2933 ft->PrototypeTemplate()->Set(v8::String::New("getImageData"), V8FUNCTION(ctx2d_getImageData, engine));
2934 ft->PrototypeTemplate()->Set(v8::String::New("putImageData"), V8FUNCTION(ctx2d_putImageData, engine));
2936 constructorContext = qPersistentNew(ft->GetFunction());
2938 v8::Local<v8::FunctionTemplate> ftGradient = v8::FunctionTemplate::New();
2939 ftGradient->InstanceTemplate()->SetHasExternalResource(true);
2940 ftGradient->PrototypeTemplate()->Set(v8::String::New("addColorStop"), V8FUNCTION(ctx2d_gradient_addColorStop, engine));
2941 constructorGradient = qPersistentNew(ftGradient->GetFunction());
2943 v8::Local<v8::FunctionTemplate> ftPattern = v8::FunctionTemplate::New();
2944 ftPattern->InstanceTemplate()->SetHasExternalResource(true);
2945 constructorPattern = qPersistentNew(ftPattern->GetFunction());
2947 v8::Local<v8::FunctionTemplate> ftPixelArray = v8::FunctionTemplate::New();
2948 ftPixelArray->InstanceTemplate()->SetHasExternalResource(true);
2949 ftPixelArray->InstanceTemplate()->SetAccessor(v8::String::New("length"), ctx2d_pixelArray_length, 0, v8::External::Wrap(engine));
2950 ftPixelArray->InstanceTemplate()->SetIndexedPropertyHandler(ctx2d_pixelArray_indexed, ctx2d_pixelArray_indexed_set, 0, 0, 0, v8::External::Wrap(engine));
2951 constructorPixelArray = qPersistentNew(ftPixelArray->GetFunction());
2953 v8::Local<v8::FunctionTemplate> ftImageData = v8::FunctionTemplate::New();
2954 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("width"), ctx2d_imageData_width, 0, v8::External::Wrap(engine));
2955 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("height"), ctx2d_imageData_height, 0, v8::External::Wrap(engine));
2956 ftImageData->InstanceTemplate()->SetAccessor(v8::String::New("data"), ctx2d_imageData_data, 0, v8::External::Wrap(engine));
2957 ftImageData->PrototypeTemplate()->Set(v8::String::New("mirror"), V8FUNCTION(ctx2d_imageData_mirror, engine));
2958 ftImageData->PrototypeTemplate()->Set(v8::String::New("filter"), V8FUNCTION(ctx2d_imageData_filter, engine));
2959 ftImageData->InstanceTemplate()->SetInternalFieldCount(1);
2960 constructorImageData = qPersistentNew(ftImageData->GetFunction());
2963 QSGContext2DEngineData::~QSGContext2DEngineData()
2965 qPersistentDispose(constructorContext);
2966 qPersistentDispose(constructorGradient);
2967 qPersistentDispose(constructorPattern);
2968 qPersistentDispose(constructorImageData);
2969 qPersistentDispose(constructorPixelArray);
2972 void QSGContext2D::popState()
2974 if (m_stateStack.isEmpty())
2977 QSGContext2D::State newState = m_stateStack.pop();
2979 if (state.matrix != newState.matrix)
2980 buffer()->updateMatrix(newState.matrix);
2982 if (newState.globalAlpha != state.globalAlpha)
2983 buffer()->setGlobalAlpha(newState.globalAlpha);
2985 if (newState.globalCompositeOperation != state.globalCompositeOperation)
2986 buffer()->setGlobalCompositeOperation(newState.globalCompositeOperation);
2988 if (newState.fillStyle != state.fillStyle)
2989 buffer()->setFillStyle(newState.fillStyle);
2991 if (newState.strokeStyle != state.strokeStyle)
2992 buffer()->setStrokeStyle(newState.strokeStyle);
2994 if (newState.lineWidth != state.lineWidth)
2995 buffer()->setLineWidth(newState.lineWidth);
2997 if (newState.lineCap != state.lineCap)
2998 buffer()->setLineCap(newState.lineCap);
3000 if (newState.lineJoin != state.lineJoin)
3001 buffer()->setLineJoin(newState.lineJoin);
3003 if (newState.miterLimit != state.miterLimit)
3004 buffer()->setMiterLimit(newState.miterLimit);
3006 if (newState.clipPath != state.clipPath)
3007 buffer()->clip(newState.clipPath);
3009 if (newState.shadowBlur != state.shadowBlur)
3010 buffer()->setShadowBlur(newState.shadowBlur);
3012 if (newState.shadowColor != state.shadowColor)
3013 buffer()->setShadowColor(newState.shadowColor);
3015 if (newState.shadowOffsetX != state.shadowOffsetX)
3016 buffer()->setShadowOffsetX(newState.shadowOffsetX);
3018 if (newState.shadowOffsetY != state.shadowOffsetY)
3019 buffer()->setShadowOffsetY(newState.shadowOffsetY);
3023 void QSGContext2D::pushState()
3025 m_stateStack.push(state);
3028 void QSGContext2D::reset()
3030 QSGContext2D::State newState;
3031 newState.matrix = QTransform();
3033 QPainterPath defaultClipPath;
3034 defaultClipPath.addRect(0, 0, m_canvas->canvasSize().width(), m_canvas->canvasSize().height());
3035 newState.clipPath = defaultClipPath;
3036 newState.clipPath.setFillRule(Qt::WindingFill);
3038 newState.strokeStyle = Qt::black;
3039 newState.fillStyle = Qt::black;
3040 newState.fillRule = Qt::WindingFill;
3041 newState.globalAlpha = 1.0;
3042 newState.lineWidth = 1;
3043 newState.lineCap = Qt::FlatCap;
3044 newState.lineJoin = Qt::MiterJoin;
3045 newState.miterLimit = 10;
3046 newState.shadowOffsetX = 0;
3047 newState.shadowOffsetY = 0;
3048 newState.shadowBlur = 0;
3049 newState.shadowColor = qRgba(0, 0, 0, 0);
3050 newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
3051 newState.font = QFont(QLatin1String("sans-serif"), 10);
3052 newState.textAlign = QSGContext2D::Start;
3053 newState.textBaseline = QSGContext2D::Alphabetic;
3056 m_stateStack.clear();
3057 m_stateStack.push(newState);
3061 void QSGContext2D::setV8Engine(QV8Engine *engine)
3063 v8::HandleScope handle_scope;
3064 v8::Context::Scope scope(engine->context());
3066 if (m_v8engine != engine) {
3067 m_v8engine = engine;
3069 qPersistentDispose(m_v8value);
3071 if (m_v8engine == 0)
3074 QSGContext2DEngineData *ed = engineData(engine);
3075 m_v8value = qPersistentNew(ed->constructorContext->NewInstance());
3076 QV8Context2DResource *r = new QV8Context2DResource(engine);
3078 m_v8value->SetExternalResource(r);