summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Bache-Wiig <jbache@trolltech.com>2010-08-17 14:53:16 +0200
committerJens Bache-Wiig <jbache@trolltech.com>2010-08-17 14:53:16 +0200
commit9275865b29850b71d95ba5d10ce38954aa5d6e2d (patch)
treecfb18012c34eec6088ceae8ffec7c66f61bee237
Initial version
-rw-r--r--README3
-rw-r--r--examples/clock/clock.qml123
-rw-r--r--qmlcanvas.pro2
-rw-r--r--src/canvas.cpp65
-rw-r--r--src/canvas.h68
-rw-r--r--src/canvasplugin.cpp53
-rw-r--r--src/canvasplugin.h47
-rw-r--r--src/context2d.cpp794
-rw-r--r--src/context2d.h283
-rw-r--r--src/src.pro18
10 files changed, 1456 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..e597ac1
--- /dev/null
+++ b/README
@@ -0,0 +1,3 @@
+To try out the examples just do 'qmake' and 'make' in
+the root directory and run each example using the qmlviewer.
+
diff --git a/examples/clock/clock.qml b/examples/clock/clock.qml
new file mode 100644
index 0000000..a671d9c
--- /dev/null
+++ b/examples/clock/clock.qml
@@ -0,0 +1,123 @@
+import "../../Canvas"
+import Qt 4.7
+
+Rectangle {
+
+ width: 300; height: 200
+
+ Image {
+ id: bg
+ visible:false
+ source: "backdrop.png"
+ }
+
+ Canvas {
+ id: clock
+ width:200
+ height:200
+
+ Timer {
+ interval: 1000; running: true; repeat: true
+ onTriggered: clock.updateCanvas()
+ }
+
+ onPaint : {
+
+ var now = new Date();
+ ctx.save();
+ ctx.drawLine
+ ctx.clearRect(0,0,150,150);
+ ctx.translate(75,75);
+ ctx.scale(0.4,0.4);
+ ctx.rotate(-Math.PI/2);
+ ctx.strokeStyle = "black";
+ ctx.fillStyle = "white";
+ ctx.lineWidth = 8;
+ ctx.lineCap = "round";
+ var bg = ctx.createImage("backdrop.png");
+ ctx.drawImage(bg, 0, 0, 100, 100);
+
+ // Hour marks
+ ctx.save();
+ ctx.beginPath();
+ for (var i=0;i<12;i++){
+ ctx.rotate(Math.PI/6);
+ ctx.moveTo(100,0);
+ ctx.lineTo(120,0);
+ }
+ ctx.stroke();
+ ctx.restore();
+
+ // Minute marks
+ ctx.save();
+ ctx.lineWidth = 5;
+ ctx.beginPath();
+ for (i=0;i<60;i++){
+ if (i%5!=0) { // 5 minutes
+ ctx.moveTo(117,0);
+ ctx.lineTo(120,0);
+ }
+ ctx.rotate(Math.PI/30);
+ }
+ ctx.stroke();
+ ctx.restore();
+
+ var sec = now.getSeconds();
+ var min = now.getMinutes();
+ var hr = now.getHours();
+ hr = hr>=12 ? hr-12 : hr;
+
+ ctx.fillStyle = "black";
+
+ // write Hours
+ ctx.save();
+ ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec )
+ ctx.lineWidth = 14;
+ ctx.beginPath();
+ ctx.moveTo(-20,0);
+ ctx.lineTo(80,0);
+ ctx.stroke();
+ ctx.restore();
+
+ // write Minutes
+ ctx.save();
+ ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec )
+ ctx.lineWidth = 10;
+ ctx.beginPath();
+ ctx.moveTo(-28,0);
+ ctx.lineTo(112,0);
+ ctx.stroke();
+ ctx.restore();
+
+ // Write seconds
+ ctx.save();
+ ctx.rotate(sec * Math.PI/30);
+ ctx.strokeStyle = "#D40000";
+ ctx.fillStyle = "#D40000";
+ ctx.lineWidth = 6;
+ ctx.beginPath();
+ ctx.moveTo(-30,0);
+ ctx.lineTo(83,0);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(0,0,10,0,Math.PI*2,true);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(95,0,10,0,Math.PI*2,true);
+ ctx.stroke();
+ ctx.fillStyle = "#555";
+ ctx.arc(0,0,3,0,Math.PI*2,true);
+ ctx.fill();
+ ctx.restore();
+
+ ctx.beginPath();
+ ctx.lineWidth = 14;
+ ctx.strokeStyle = '#325FA2';
+ ctx.arc(0,0,142,0,Math.PI*2,true);
+ ctx.stroke();
+
+ ctx.restore(); }
+ }
+
+}
+
diff --git a/qmlcanvas.pro b/qmlcanvas.pro
new file mode 100644
index 0000000..65d9262
--- /dev/null
+++ b/qmlcanvas.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = src
diff --git a/src/canvas.cpp b/src/canvas.cpp
new file mode 100644
index 0000000..a657948
--- /dev/null
+++ b/src/canvas.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "canvas.h"
+
+#include <QPainter>
+
+Canvas::Canvas(QDeclarativeItem *parent)
+ : QDeclarativeItem(parent)
+{
+ setFlag(QGraphicsItem::ItemHasNoContents, false);
+ setCacheMode(QGraphicsItem::ItemCoordinateCache);
+ setSmooth(true);
+}
+
+void Canvas::updateCanvas()
+{
+ update();
+}
+
+void Canvas::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing, smooth());
+ Context2D context(this, painter);
+ emit paint(&context);
+ painter->restore();
+}
+
diff --git a/src/canvas.h b/src/canvas.h
new file mode 100644
index 0000000..c20f29f
--- /dev/null
+++ b/src/canvas.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DRAWABLEITEM_H
+#define DRAWABLEITEM_H
+
+#include <QDeclarativeItem>
+#include "context2d.h"
+
+class Context2D;
+
+class Canvas : public QDeclarativeItem
+{
+ Q_OBJECT
+
+public:
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
+
+ Canvas(QDeclarativeItem *parent = 0);
+
+public slots:
+ void updateCanvas();
+
+signals:
+ void paint(Context2D *ctx);
+
+private:
+ QPixmap m_cache;
+};
+
+#endif
+
diff --git a/src/canvasplugin.cpp b/src/canvasplugin.cpp
new file mode 100644
index 0000000..8a67d3d
--- /dev/null
+++ b/src/canvasplugin.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qdeclarative.h>
+#include "canvasplugin.h"
+#include "canvas.h"
+
+void CanvasPlugin::registerTypes(const char *uri)
+{
+ qDebug("test %s", uri);
+ qmlRegisterType<Canvas>(uri, 1, 0, "Canvas");
+ qmlRegisterType<Context2D>(uri, 1, 0, "Context2D");
+ qmlRegisterUncreatableType<CanvasImage>(uri, 1, 0, "CanvasImage", QString());
+ qmlRegisterUncreatableType<CanvasGradient>(uri, 1, 0, "Gradient", QString());
+}
+
+Q_EXPORT_PLUGIN2(canvasplugin, CanvasPlugin);
diff --git a/src/canvasplugin.h b/src/canvasplugin.h
new file mode 100644
index 0000000..b6edbba
--- /dev/null
+++ b/src/canvasplugin.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDeclarativeExtensionPlugin>
+
+ class CanvasPlugin : public QDeclarativeExtensionPlugin
+ {
+ Q_OBJECT
+ public:
+ void registerTypes(const char *uri);
+ };
diff --git a/src/context2d.cpp b/src/context2d.cpp
new file mode 100644
index 0000000..05713a2
--- /dev/null
+++ b/src/context2d.cpp
@@ -0,0 +1,794 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "context2d.h"
+#include <qdebug.h>
+#include <math.h>
+static const double Q_PI = 3.14159265358979323846; // pi
+
+#define DEGREES(t) ((t) * 180.0 / Q_PI)
+
+#define qClamp(val, min, max) qMin(qMax(val, min), max)
+static QList<qreal> parseNumbersList(QString::const_iterator &itr)
+{
+ QList<qreal> points;
+ QString temp;
+ while ((*itr).isSpace())
+ ++itr;
+ while ((*itr).isNumber() ||
+ (*itr) == '-' || (*itr) == '+' || (*itr) == '.') {
+ temp = QString();
+
+ if ((*itr) == '-')
+ temp += *itr++;
+ else if ((*itr) == '+')
+ temp += *itr++;
+ while ((*itr).isDigit())
+ temp += *itr++;
+ if ((*itr) == '.')
+ temp += *itr++;
+ while ((*itr).isDigit())
+ temp += *itr++;
+ while ((*itr).isSpace())
+ ++itr;
+ if ((*itr) == ',')
+ ++itr;
+ points.append(temp.toDouble());
+ //eat spaces
+ while ((*itr).isSpace())
+ ++itr;
+ }
+
+ return points;
+}
+
+QColor colorFromString(const QString &name)
+{
+ QString::const_iterator itr = name.constBegin();
+ QList<qreal> compo;
+ if (name.startsWith("rgba(")) {
+ ++itr; ++itr; ++itr; ++itr; ++itr;
+ compo = parseNumbersList(itr);
+ if (compo.size() != 4) {
+ return QColor();
+ }
+ //alpha seems to be always between 0-1
+ compo[3] *= 255;
+ return QColor((int)compo[0], (int)compo[1],
+ (int)compo[2], (int)compo[3]);
+ } else if (name.startsWith("rgb(")) {
+ ++itr; ++itr; ++itr; ++itr;
+ compo = parseNumbersList(itr);
+ if (compo.size() != 3) {
+ return QColor();
+ }
+ return QColor((int)qClamp(compo[0], qreal(0), qreal(255)),
+ (int)qClamp(compo[1], qreal(0), qreal(255)),
+ (int)qClamp(compo[2], qreal(0), qreal(255)));
+ } else {
+ //QRgb color;
+ //CSSParser::parseColor(name, color);
+ return QColor(name);
+ }
+}
+
+
+static QPainter::CompositionMode compositeOperatorFromString(const QString &compositeOperator)
+{
+ if ( compositeOperator == "source-over" ) {
+ return QPainter::CompositionMode_SourceOver;
+ } else if ( compositeOperator == "source-out" ) {
+ return QPainter::CompositionMode_SourceOut;
+ } else if ( compositeOperator == "source-in" ) {
+ return QPainter::CompositionMode_SourceIn;
+ } else if ( compositeOperator == "source-atop" ) {
+ return QPainter::CompositionMode_SourceAtop;
+ } else if ( compositeOperator == "destination-atop" ) {
+ return QPainter::CompositionMode_DestinationAtop;
+ } else if ( compositeOperator == "destination-in" ) {
+ return QPainter::CompositionMode_DestinationIn;
+ } else if ( compositeOperator == "destination-out" ) {
+ return QPainter::CompositionMode_DestinationOut;
+ } else if ( compositeOperator == "destination-over" ) {
+ return QPainter::CompositionMode_DestinationOver;
+ } else if ( compositeOperator == "darker" ) {
+ return QPainter::CompositionMode_SourceOver;
+ } else if ( compositeOperator == "lighter" ) {
+ return QPainter::CompositionMode_SourceOver;
+ } else if ( compositeOperator == "copy" ) {
+ return QPainter::CompositionMode_Source;
+ } else if ( compositeOperator == "xor" ) {
+ return QPainter::CompositionMode_Xor;
+ }
+
+ return QPainter::CompositionMode_SourceOver;
+}
+
+static QString compositeOperatorToString(QPainter::CompositionMode op)
+{
+ switch (op) {
+ case QPainter::CompositionMode_SourceOver:
+ return "source-over";
+ case QPainter::CompositionMode_DestinationOver:
+ return "destination-over";
+ case QPainter::CompositionMode_Clear:
+ return "clear";
+ case QPainter::CompositionMode_Source:
+ return "source";
+ case QPainter::CompositionMode_Destination:
+ return "destination";
+ case QPainter::CompositionMode_SourceIn:
+ return "source-in";
+ case QPainter::CompositionMode_DestinationIn:
+ return "destination-in";
+ case QPainter::CompositionMode_SourceOut:
+ return "source-out";
+ case QPainter::CompositionMode_DestinationOut:
+ return "destination-out";
+ case QPainter::CompositionMode_SourceAtop:
+ return "source-atop";
+ case QPainter::CompositionMode_DestinationAtop:
+ return "destination-atop";
+ case QPainter::CompositionMode_Xor:
+ return "xor";
+ case QPainter::CompositionMode_Plus:
+ return "plus";
+ case QPainter::CompositionMode_Multiply:
+ return "multiply";
+ case QPainter::CompositionMode_Screen:
+ return "screen";
+ case QPainter::CompositionMode_Overlay:
+ return "overlay";
+ case QPainter::CompositionMode_Darken:
+ return "darken";
+ case QPainter::CompositionMode_Lighten:
+ return "lighten";
+ case QPainter::CompositionMode_ColorDodge:
+ return "color-dodge";
+ case QPainter::CompositionMode_ColorBurn:
+ return "color-burn";
+ case QPainter::CompositionMode_HardLight:
+ return "hard-light";
+ case QPainter::CompositionMode_SoftLight:
+ return "soft-light";
+ case QPainter::CompositionMode_Difference:
+ return "difference";
+ case QPainter::CompositionMode_Exclusion:
+ return "exclusion";
+ default:
+ break;
+ }
+ return QString();
+}
+
+void Context2D::save()
+{
+ m_stateStack.push(m_state);
+}
+
+
+void Context2D::restore()
+{
+ if (!m_stateStack.isEmpty()) {
+ m_state = m_stateStack.pop();
+ m_state.flags = AllIsFullOfDirt;
+ }
+}
+
+
+void Context2D::scale(qreal x, qreal y)
+{
+ m_state.matrix.scale(x, y);
+ m_state.flags |= DirtyTransformationMatrix;
+}
+
+
+void Context2D::rotate(qreal angle)
+{
+ m_state.matrix.rotate(DEGREES(angle));
+ m_state.flags |= DirtyTransformationMatrix;
+}
+
+
+void Context2D::translate(qreal x, qreal y)
+{
+ m_state.matrix.translate(x, y);
+ m_state.flags |= DirtyTransformationMatrix;
+}
+
+
+void Context2D::transform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy)
+{
+ QMatrix mat(m11, m12,
+ m21, m22,
+ dx, dy);
+ m_state.matrix *= mat;
+ m_state.flags |= DirtyTransformationMatrix;
+}
+
+
+void Context2D::setTransform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy)
+{
+ QMatrix mat(m11, m12,
+ m21, m22,
+ dx, dy);
+ m_state.matrix = mat;
+ m_state.flags |= DirtyTransformationMatrix;
+}
+
+
+QString Context2D::globalCompositeOperation() const
+{
+ return compositeOperatorToString(m_state.globalCompositeOperation);
+}
+
+void Context2D::setGlobalCompositeOperation(const QString &op)
+{
+ QPainter::CompositionMode mode =
+ compositeOperatorFromString(op);
+ m_state.globalCompositeOperation = mode;
+ m_state.flags |= DirtyGlobalCompositeOperation;
+}
+
+QVariant Context2D::strokeStyle() const
+{
+ return m_state.strokeStyle;
+}
+
+void Context2D::setStrokeStyle(const QVariant &style)
+{
+ CanvasGradient * gradient= qobject_cast<CanvasGradient*>(style.value<QObject*>());
+ if (gradient) {
+ m_state.strokeStyle = gradient->value();
+ } else {
+ QColor color = colorFromString(style.toString());
+ m_state.strokeStyle = color;
+ }
+ m_state.flags |= DirtyStrokeStyle;
+}
+
+QVariant Context2D::fillStyle() const
+{
+ return m_state.fillStyle;
+}
+
+void Context2D::setFillStyle(const QVariant &style)
+{
+ CanvasGradient * gradient= qobject_cast<CanvasGradient*>(style.value<QObject*>());
+ if (gradient) {
+ m_state.fillStyle = gradient->value();
+ } else {
+ QColor color = colorFromString(style.toString());
+ m_state.fillStyle = color;
+ }
+ m_state.flags |= DirtyFillStyle;
+}
+
+qreal Context2D::globalAlpha() const
+{
+ return m_state.globalAlpha;
+}
+
+void Context2D::setGlobalAlpha(qreal alpha)
+{
+ m_state.globalAlpha = alpha;
+ m_state.flags |= DirtyGlobalAlpha;
+}
+
+CanvasImage *Context2D::createImage(const QString &url)
+{
+ return new CanvasImage(url);
+}
+
+CanvasGradient *Context2D::createLinearGradient(qreal x0, qreal y0,
+ qreal x1, qreal y1)
+{
+ QLinearGradient g(x0, y0, x1, y1);
+ return new CanvasGradient(g);
+}
+
+
+CanvasGradient *Context2D::createRadialGradient(qreal x0, qreal y0,
+ qreal r0, qreal x1,
+ qreal y1, qreal r1)
+{
+ QRadialGradient g(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
+ return new CanvasGradient(g);
+}
+
+qreal Context2D::lineWidth() const
+{
+ return m_state.lineWidth;
+}
+
+void Context2D::setLineWidth(qreal w)
+{
+ m_state.lineWidth = w;
+ m_state.flags |= DirtyLineWidth;
+}
+
+QString Context2D::lineCap() const
+{
+ switch (m_state.lineCap) {
+ case Qt::FlatCap:
+ return "butt";
+ case Qt::SquareCap:
+ return "square";
+ case Qt::RoundCap:
+ return "round";
+ default: ;
+ }
+ return QString();
+}
+
+void Context2D::setLineCap(const QString &capString)
+{
+ Qt::PenCapStyle style;
+ if (capString == "round")
+ style = Qt::RoundCap;
+ else if (capString == "square")
+ style = Qt::SquareCap;
+ else //if (capString == "butt")
+ style = Qt::FlatCap;
+ m_state.lineCap = style;
+ m_state.flags |= DirtyLineCap;
+}
+
+QString Context2D::lineJoin() const
+{
+ switch (m_state.lineJoin) {
+ case Qt::RoundJoin:
+ return "round";
+ case Qt::BevelJoin:
+ return "bevel";
+ case Qt::MiterJoin:
+ return "miter";
+ default: ;
+ }
+ return QString();
+}
+
+void Context2D::setLineJoin(const QString &joinString)
+{
+ Qt::PenJoinStyle style;
+ if (joinString == "round")
+ style = Qt::RoundJoin;
+ else if (joinString == "bevel")
+ style = Qt::BevelJoin;
+ else //if (joinString == "miter")
+ style = Qt::MiterJoin;
+ m_state.lineJoin = style;
+ m_state.flags |= DirtyLineJoin;
+}
+
+qreal Context2D::miterLimit() const
+{
+ return m_state.miterLimit;
+}
+
+void Context2D::setMiterLimit(qreal m)
+{
+ m_state.miterLimit = m;
+ m_state.flags |= DirtyMiterLimit;
+}
+
+void Context2D::setShadowOffsetX(qreal x)
+{
+ m_state.shadowOffsetX = x;
+ m_state.flags |= DirtyShadowOffsetX;
+}
+
+void Context2D::setShadowOffsetY(qreal y)
+{
+ m_state.shadowOffsetY = y;
+ m_state.flags |= DirtyShadowOffsetY;
+}
+
+void Context2D::setShadowBlur(qreal b)
+{
+ m_state.shadowBlur = b;
+ m_state.flags |= DirtyShadowBlur;
+}
+
+void Context2D::setShadowColor(const QString &str)
+{
+ m_state.shadowColor = colorFromString(str);
+ m_state.flags |= DirtyShadowColor;
+}
+
+qreal Context2D::shadowOffsetX() const
+{
+ return m_state.shadowOffsetX;
+}
+
+qreal Context2D::shadowOffsetY() const
+{
+ return m_state.shadowOffsetY;
+}
+
+
+qreal Context2D::shadowBlur() const
+{
+ return m_state.shadowBlur;
+}
+
+
+QString Context2D::shadowColor() const
+{
+ return m_state.shadowColor.name();
+}
+
+
+void Context2D::clearRect(qreal x, qreal y, qreal w, qreal h)
+{
+ beginPainting();
+ m_painter->save();
+ m_painter->setMatrix(m_state.matrix, false);
+ m_painter->setCompositionMode(QPainter::CompositionMode_Source);
+ m_painter->fillRect(QRectF(x, y, w, h), QColor(0, 0, 0, 0));
+ m_painter->restore();
+ scheduleChange();
+}
+
+void Context2D::fillRect(qreal x, qreal y, qreal w, qreal h)
+{
+ beginPainting();
+ m_painter->save();
+ m_painter->setMatrix(m_state.matrix, false);
+ m_painter->fillRect(QRectF(x, y, w, h), m_painter->brush());
+ m_painter->restore();
+ scheduleChange();
+}
+
+void Context2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
+{
+ QPainterPath path;
+ path.addRect(x, y, w, h);
+ beginPainting();
+ m_painter->save();
+ m_painter->setMatrix(m_state.matrix, false);
+ m_painter->strokePath(path, m_painter->pen());
+ m_painter->restore();
+ scheduleChange();
+}
+
+
+void Context2D::beginPath()
+{
+ m_path = QPainterPath();
+}
+
+
+void Context2D::closePath()
+{
+ m_path.closeSubpath();
+}
+
+
+void Context2D::moveTo(qreal x, qreal y)
+{
+ QPointF pt = m_state.matrix.map(QPointF(x, y));
+ m_path.moveTo(pt);
+}
+
+
+void Context2D::lineTo(qreal x, qreal y)
+{
+ QPointF pt = m_state.matrix.map(QPointF(x, y));
+ m_path.lineTo(pt);
+}
+
+
+void Context2D::quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y)
+{
+ QPointF cp = m_state.matrix.map(QPointF(cpx, cpy));
+ QPointF xy = m_state.matrix.map(QPointF(x, y));
+ m_path.quadTo(cp, xy);
+}
+
+
+void Context2D::bezierCurveTo(qreal cp1x, qreal cp1y,
+ qreal cp2x, qreal cp2y, qreal x, qreal y)
+{
+ QPointF cp1 = m_state.matrix.map(QPointF(cp1x, cp1y));
+ QPointF cp2 = m_state.matrix.map(QPointF(cp2x, cp2y));
+ QPointF end = m_state.matrix.map(QPointF(x, y));
+ m_path.cubicTo(cp1, cp2, end);
+}
+
+
+void Context2D::arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius)
+{
+ //FIXME: this is surely busted
+ QPointF st = m_state.matrix.map(QPointF(x1, y1));
+ QPointF end = m_state.matrix.map(QPointF(x2, y2));
+ m_path.arcTo(st.x(), st.y(),
+ end.x()-st.x(), end.y()-st.y(),
+ radius, 90);
+}
+
+
+void Context2D::rect(qreal x, qreal y, qreal w, qreal h)
+{
+ QPainterPath path; path.addRect(x, y, w, h);
+ path = m_state.matrix.map(path);
+ m_path.addPath(path);
+}
+
+void Context2D::arc(qreal xc, qreal yc, qreal radius,
+ qreal sar, qreal ear,
+ bool anticlockwise)
+{
+ //### HACK
+ // In Qt we don't switch the coordinate system for degrees
+ // and still use the 0,0 as bottom left for degrees so we need
+ // to switch
+ sar = -sar;
+ ear = -ear;
+ anticlockwise = !anticlockwise;
+ //end hack
+
+ float sa = DEGREES(sar);
+ float ea = DEGREES(ear);
+
+ double span = 0;
+
+ double xs = xc - radius;
+ double ys = yc - radius;
+ double width = radius*2;
+ double height = radius*2;
+
+ if (!anticlockwise && (ea < sa)) {
+ span += 360;
+ } else if (anticlockwise && (sa < ea)) {
+ span -= 360;
+ }
+
+ //### this is also due to switched coordinate system
+ // we would end up with a 0 span instead of 360
+ if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
+ qFuzzyCompare(qAbs(span), 360))) {
+ span += ea - sa;
+ }
+
+ QPainterPath path;
+ path.moveTo(QPointF(xc + radius * cos(sar),
+ yc - radius * sin(sar)));
+
+ path.arcTo(xs, ys, width, height, sa, span);
+ path = m_state.matrix.map(path);
+ m_path.addPath(path);
+}
+
+
+void Context2D::fill()
+{
+ beginPainting();
+ m_painter->fillPath(m_path, m_painter->brush());
+ scheduleChange();
+}
+
+
+void Context2D::stroke()
+{
+ beginPainting();
+ m_painter->save();
+ m_painter->setMatrix(m_state.matrix, false);
+ QPainterPath tmp = m_state.matrix.inverted().map(m_path);
+ m_painter->strokePath(tmp, m_painter->pen());
+ m_painter->restore();
+ scheduleChange();
+}
+
+
+void Context2D::clip()
+{
+ m_state.clipPath = m_path;
+ m_state.flags |= DirtyClippingRegion;
+}
+
+
+bool Context2D::isPointInPath(qreal x, qreal y) const
+{
+ return m_path.contains(QPointF(x, y));
+}
+
+
+ImageData Context2D::getImageData(qreal sx, qreal sy, qreal sw, qreal sh)
+{
+ Q_UNUSED(sx);
+ Q_UNUSED(sy);
+ Q_UNUSED(sw);
+ Q_UNUSED(sh);
+ return ImageData();
+}
+
+
+void Context2D::putImageData(ImageData image, qreal dx, qreal dy)
+{
+ Q_UNUSED(image);
+ Q_UNUSED(dx);
+ Q_UNUSED(dy);
+}
+
+Context2D::Context2D(QObject *parent, QPainter *painter)
+ : QObject(parent), m_changeTimerId(-1), m_painter(painter)
+{
+ reset();
+}
+
+const QImage &Context2D::endPainting()
+{
+ if (m_painter->isActive())
+ m_painter->end();
+ return m_image;
+}
+
+void Context2D::beginPainting()
+{
+
+ if (!m_painter->isActive()) {
+ // m_painter->begin(&m_image);
+ m_painter->setRenderHint(QPainter::Antialiasing);
+ if (!m_state.clipPath.isEmpty())
+ m_painter->setClipPath(m_state.clipPath);
+ m_painter->setBrush(m_state.fillStyle);
+ m_painter->setOpacity(m_state.globalAlpha);
+ QPen pen;
+ pen.setBrush(m_state.strokeStyle);
+ if (pen.style() == Qt::NoPen)
+ pen.setStyle(Qt::SolidLine);
+ pen.setCapStyle(m_state.lineCap);
+ pen.setJoinStyle(m_state.lineJoin);
+ pen.setWidthF(m_state.lineWidth);
+ pen.setMiterLimit(m_state.miterLimit);
+ m_painter->setPen(pen);
+ } else {
+ if ((m_state.flags & DirtyClippingRegion) && !m_state.clipPath.isEmpty())
+ m_painter->setClipPath(m_state.clipPath);
+ if (m_state.flags & DirtyFillStyle)
+ m_painter->setBrush(m_state.fillStyle);
+ if (m_state.flags & DirtyGlobalAlpha)
+ m_painter->setOpacity(m_state.globalAlpha);
+ if (m_state.flags & DirtyGlobalCompositeOperation)
+ m_painter->setCompositionMode(m_state.globalCompositeOperation);
+ if (m_state.flags & MDirtyPen) {
+ QPen pen = m_painter->pen();
+ if (m_state.flags & DirtyStrokeStyle)
+ pen.setBrush(m_state.strokeStyle);
+ if (m_state.flags & DirtyLineWidth)
+ pen.setWidthF(m_state.lineWidth);
+ if (m_state.flags & DirtyLineCap)
+ pen.setCapStyle(m_state.lineCap);
+ if (m_state.flags & DirtyLineJoin)
+ pen.setJoinStyle(m_state.lineJoin);
+ if (m_state.flags & DirtyMiterLimit)
+ pen.setMiterLimit(m_state.miterLimit);
+ m_painter->setPen(pen);
+ }
+ m_state.flags = 0;
+ }
+}
+
+void Context2D::clear()
+{
+ return;
+ endPainting();
+ m_image.fill(qRgba(0,0,0,0));
+ scheduleChange();
+}
+
+void Context2D::reset()
+{
+ m_stateStack.clear();
+ m_state.matrix = QMatrix();
+ m_state.clipPath = QPainterPath();
+ m_state.globalAlpha = 1.0;
+ m_state.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
+ m_state.strokeStyle = Qt::black;
+ m_state.fillStyle = Qt::black;
+ m_state.lineWidth = 1;
+ m_state.lineCap = Qt::FlatCap;
+ m_state.lineJoin = Qt::MiterJoin;
+ m_state.miterLimit = 10;
+ m_state.shadowOffsetX = 0;
+ m_state.shadowOffsetY = 0;
+ m_state.shadowBlur = 0;
+ m_state.shadowColor = qRgba(0, 0, 0, 0);
+ m_state.flags = AllIsFullOfDirt;
+ clear();
+}
+
+void Context2D::setSize(int width, int height)
+{
+ endPainting();
+ QImage newi(width, height, QImage::Format_ARGB32_Premultiplied);
+ newi.fill(qRgba(0,0,0,0));
+ QPainter p(&newi);
+ p.drawImage(0, 0, m_image);
+ p.end();
+ m_image = newi;
+ scheduleChange();
+}
+
+void Context2D::setSize(const QSize &size)
+{
+ setSize(size.width(), size.height());
+}
+
+QSize Context2D::size() const
+{
+ return m_image.size();
+}
+
+
+void Context2D::drawImage(const QVariant &var, qreal sx, qreal sy,
+ qreal sw = 0, qreal sh = 0)
+{
+ CanvasImage *image = qobject_cast<CanvasImage*>(var.value<QObject*>());
+ if (!image)
+ return;
+ beginPainting();
+ if (sw == sh)
+ m_painter->drawImage(QPointF(sx, sy), image->value());
+ else
+ m_painter->drawImage(QRectF(sx, sy, sw, sh), image->value());
+ scheduleChange();
+}
+
+
+void Context2D::scheduleChange()
+{
+ if (m_changeTimerId == -1)
+ m_changeTimerId = startTimer(0);
+}
+
+void Context2D::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() == m_changeTimerId) {
+ killTimer(m_changeTimerId);
+ m_changeTimerId = -1;
+ emit changed(endPainting());
+ } else {
+ QObject::timerEvent(e);
+ }
+}
+//! [2]
diff --git a/src/context2d.h b/src/context2d.h
new file mode 100644
index 0000000..ed76cd6
--- /dev/null
+++ b/src/context2d.h
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CONTEXT2D_H
+#define CONTEXT2D_H
+
+#include <QPainter>
+#include <QPainterPath>
+#include <QString>
+#include <QStack>
+#include <QMetaType>
+#include <QTimerEvent>
+#include <QVariant>
+#include <qdebug.h>
+
+QColor colorFromString(const QString &name);
+
+class CanvasGradient : public QObject
+{
+ Q_OBJECT
+public:
+ CanvasGradient(const QGradient &gradient) : m_gradient(gradient) {}
+
+public slots:
+ QGradient value() { return m_gradient; }
+ void addColorStop(float pos, const QString &color) { m_gradient.setColorAt(pos, colorFromString(color));}
+
+public:
+ QGradient m_gradient;
+};
+
+Q_DECLARE_METATYPE(CanvasGradient*)
+
+
+class CanvasImage: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString src READ src WRITE setSrc NOTIFY sourceChanged)
+ Q_PROPERTY(int width READ width)
+ Q_PROPERTY(int height READ height)
+
+public:
+ CanvasImage() {}
+ CanvasImage(const QString &url) : m_image(url), m_src(url) {}
+
+public slots:
+ int width() { return m_image.width(); }
+ int height() { return m_image.height(); }
+ QImage value() { return m_image; }
+ QString src() { return m_src; }
+ void setSrc(const QString &src) { m_src = src; m_image.load(src); emit sourceChanged();}
+signals:
+ void sourceChanged();
+
+private:
+ QImage m_image;
+ QString m_src;
+};
+
+Q_DECLARE_METATYPE(CanvasImage*)
+
+
+class ImageData {
+};
+
+class QContext2DCanvas;
+
+class Context2D : public QObject
+{
+ Q_OBJECT
+ // compositing
+ Q_PROPERTY(qreal globalAlpha READ globalAlpha WRITE setGlobalAlpha)
+ Q_PROPERTY(QString globalCompositeOperation READ globalCompositeOperation WRITE setGlobalCompositeOperation)
+ Q_PROPERTY(QVariant strokeStyle READ strokeStyle WRITE setStrokeStyle)
+ Q_PROPERTY(QVariant fillStyle READ fillStyle WRITE setFillStyle)
+ // line caps/joins
+ Q_PROPERTY(qreal lineWidth READ lineWidth WRITE setLineWidth)
+ Q_PROPERTY(QString lineCap READ lineCap WRITE setLineCap)
+ Q_PROPERTY(QString lineJoin READ lineJoin WRITE setLineJoin)
+ Q_PROPERTY(qreal miterLimit READ miterLimit WRITE setMiterLimit)
+ // shadows
+ Q_PROPERTY(qreal shadowOffsetX READ shadowOffsetX WRITE setShadowOffsetX)
+ Q_PROPERTY(qreal shadowOffsetY READ shadowOffsetY WRITE setShadowOffsetY)
+ Q_PROPERTY(qreal shadowBlur READ shadowBlur WRITE setShadowBlur)
+ Q_PROPERTY(QString shadowColor READ shadowColor WRITE setShadowColor)
+
+public:
+ Context2D(QObject *parent = 0, QPainter *painter = 0);
+ void setSize(int width, int height);
+ void setSize(const QSize &size);
+ QSize size() const;
+
+ void clear();
+ void reset();
+
+ // compositing
+ qreal globalAlpha() const; // (default 1.0)
+ QString globalCompositeOperation() const; // (default over)
+ QVariant strokeStyle() const; // (default black)
+ QVariant fillStyle() const; // (default black)
+
+ void setGlobalAlpha(qreal alpha);
+ void setGlobalCompositeOperation(const QString &op);
+ void setStrokeStyle(const QVariant &style);
+ void setFillStyle(const QVariant &style);
+
+ // line caps/joins
+ qreal lineWidth() const; // (default 1)
+ QString lineCap() const; // "butt", "round", "square" (default "butt")
+ QString lineJoin() const; // "round", "bevel", "miter" (default "miter")
+ qreal miterLimit() const; // (default 10)
+
+ void setLineWidth(qreal w);
+ void setLineCap(const QString &s);
+ void setLineJoin(const QString &s);
+ void setMiterLimit(qreal m);
+
+ // shadows
+ qreal shadowOffsetX() const; // (default 0)
+ qreal shadowOffsetY() const; // (default 0)
+ qreal shadowBlur() const; // (default 0)
+ QString shadowColor() const; // (default black)
+
+ void setShadowOffsetX(qreal x);
+ void setShadowOffsetY(qreal y);
+ void setShadowBlur(qreal b);
+ void setShadowColor(const QString &str);
+
+ //! [1]
+public slots:
+ void save(); // push state on state stack
+ void restore(); // pop state stack and restore state
+
+ void scale(qreal x, qreal y);
+ void rotate(qreal angle);
+ void translate(qreal x, qreal y);
+ void transform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy);
+ void setTransform(qreal m11, qreal m12, qreal m21, qreal m22,
+ qreal dx, qreal dy);
+
+ CanvasGradient *createLinearGradient(qreal x0, qreal y0,
+ qreal x1, qreal y1);
+ CanvasGradient *createRadialGradient(qreal x0, qreal y0,
+ qreal r0, qreal x1,
+ qreal y1, qreal r1);
+
+ // rects
+ void clearRect(qreal x, qreal y, qreal w, qreal h);
+ void fillRect(qreal x, qreal y, qreal w, qreal h);
+ void strokeRect(qreal x, qreal y, qreal w, qreal h);
+
+ // path API
+ void beginPath();
+ void closePath();
+ void moveTo(qreal x, qreal y);
+ void lineTo(qreal x, qreal y);
+ void quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y);
+ void bezierCurveTo(qreal cp1x, qreal cp1y,
+ qreal cp2x, qreal cp2y, qreal x, qreal y);
+ void arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius);
+ void rect(qreal x, qreal y, qreal w, qreal h);
+ void arc(qreal x, qreal y, qreal radius,
+ qreal startAngle, qreal endAngle,
+ bool anticlockwise);
+ void fill();
+ void stroke();
+ void clip();
+ bool isPointInPath(qreal x, qreal y) const;
+
+ CanvasImage *createImage(const QString &url);
+
+ // drawing images (no overloads due to QTBUG-11604)
+ void drawImage(const QVariant &var, qreal dx, qreal dy, qreal dw, qreal dh);
+
+ // pixel manipulation
+ ImageData getImageData(qreal sx, qreal sy, qreal sw, qreal sh);
+ void putImageData(ImageData image, qreal dx, qreal dy);
+
+signals:
+ void changed(const QImage &image);
+
+protected:
+ void timerEvent(QTimerEvent *e);
+
+private:
+ void beginPainting();
+ const QImage &endPainting();
+ void scheduleChange();
+
+ int m_changeTimerId;
+ QImage m_image;
+ QPainter *m_painter;
+ QPainterPath m_path;
+
+ enum DirtyFlag {
+ DirtyTransformationMatrix = 0x00001,
+ DirtyClippingRegion = 0x00002,
+ DirtyStrokeStyle = 0x00004,
+ DirtyFillStyle = 0x00008,
+ DirtyGlobalAlpha = 0x00010,
+ DirtyLineWidth = 0x00020,
+ DirtyLineCap = 0x00040,
+ DirtyLineJoin = 0x00080,
+ DirtyMiterLimit = 0x00100,
+ MDirtyPen = DirtyStrokeStyle
+ | DirtyLineWidth
+ | DirtyLineCap
+ | DirtyLineJoin
+ | DirtyMiterLimit,
+ DirtyShadowOffsetX = 0x00200,
+ DirtyShadowOffsetY = 0x00400,
+ DirtyShadowBlur = 0x00800,
+ DirtyShadowColor = 0x01000,
+ DirtyGlobalCompositeOperation = 0x2000,
+ DirtyFont = 0x04000,
+ DirtyTextAlign = 0x08000,
+ DirtyTextBaseline = 0x10000,
+ AllIsFullOfDirt = 0xfffff
+ };
+
+ struct State {
+ State() : flags(0) {}
+ QMatrix matrix;
+ QPainterPath clipPath;
+ QBrush strokeStyle;
+ QBrush fillStyle;
+ qreal globalAlpha;
+ qreal lineWidth;
+ Qt::PenCapStyle lineCap;
+ Qt::PenJoinStyle lineJoin;
+ qreal miterLimit;
+ qreal shadowOffsetX;
+ qreal shadowOffsetY;
+ qreal shadowBlur;
+ QColor shadowColor;
+ QPainter::CompositionMode globalCompositeOperation;
+ QFont font;
+ int textAlign;
+ int textBaseline;
+ int flags;
+ };
+ State m_state;
+ QStack<State> m_stateStack;
+};
+
+#endif
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 0000000..74f902f
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,18 @@
+ TEMPLATE = lib
+ CONFIG += qt plugin
+ QT += declarative
+ TARGET = canvasplugin
+
+ DESTDIR = ..\\Canvas
+ OBJECTS_DIR = tmp
+ MOC_DIR = tmp
+
+ HEADERS += context2d.h \
+ canvas.h \
+ canvasplugin.h
+
+ SOURCES += context2d.cpp \
+ canvas.cpp \
+ canvasplugin.cpp
+
+