aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharles Yin <yinyunqiao@gmail.com>2011-09-22 20:01:29 +1000
committerQt by Nokia <qt-info@nokia.com>2011-09-30 10:37:05 +0200
commit8f69461c480e10424401e95b16b507eec3e28e54 (patch)
tree58e13d4c7a470485ab5e14642a55bc35bd0ae2c3
parent20fb62f6040ad8415828092a2b09bd374433505f (diff)
tests for canvas and a few bug fixes
Change-Id: Icbbc7f2a0fe3b908963ce18afef51e25ea0170a0 Reviewed-on: http://codereview.qt-project.org/5805 Reviewed-by: Charles Yin <charles.yin@nokia.com>
-rw-r--r--examples/declarative/canvas/bezierCurve/bezierCurve.qml2
-rw-r--r--examples/declarative/canvas/quadraticCurveTo/quadraticCurveTo.qml2
-rw-r--r--examples/declarative/canvas/roundedrect/roundedrect.qml2
-rw-r--r--examples/declarative/canvas/smile/smile.qml2
-rw-r--r--examples/declarative/canvas/squircle/squircle.qml2
-rw-r--r--examples/declarative/canvas/tiger/tiger.qml2
-rw-r--r--examples/declarative/canvas/twitterfriends/TwitterUser.qml2
-rw-r--r--src/declarative/items/context2d/qsgcanvasitem.cpp22
-rw-r--r--src/declarative/items/context2d/qsgcanvasitem_p.h6
-rw-r--r--src/declarative/items/context2d/qsgcontext2d.cpp457
-rw-r--r--src/declarative/items/context2d/qsgcontext2d_p.h6
-rw-r--r--src/declarative/items/context2d/qsgcontext2dcommandbuffer.cpp91
-rw-r--r--src/declarative/items/context2d/qsgcontext2dcommandbuffer_p.h11
-rw-r--r--src/declarative/items/context2d/qsgcontext2dtexture.cpp43
-rw-r--r--src/declarative/items/context2d/qsgcontext2dtexture_p.h1
-rw-r--r--src/declarative/items/context2d/qsgcontext2dtile.cpp12
-rw-r--r--src/declarative/items/context2d/qsgcontext2dtile_p.h5
-rw-r--r--tests/auto/declarative/declarative.pro2
-rw-r--r--tests/auto/declarative/qsgcanvasitem/data/testhelper.js18
-rw-r--r--tests/auto/declarative/qsgcanvasitem/data/tst_colors.qml19
-rw-r--r--tests/auto/declarative/qsgcanvasitem/data/tst_fillStyle.qml113
-rw-r--r--tests/auto/declarative/qsgcanvasitem/data/tst_fillrect.qml23
-rw-r--r--tests/auto/declarative/qsgcanvasitem/data/tst_strokeStyle.qml48
-rw-r--r--tests/auto/declarative/qsgcanvasitem/qsgcanvasitem.pro5
-rw-r--r--tests/auto/declarative/qsgcanvasitem/tst_qsgcanvasitem.cpp42
25 files changed, 643 insertions, 295 deletions
diff --git a/examples/declarative/canvas/bezierCurve/bezierCurve.qml b/examples/declarative/canvas/bezierCurve/bezierCurve.qml
index 4d30c4dbd1..cfd3e1f76f 100644
--- a/examples/declarative/canvas/bezierCurve/bezierCurve.qml
+++ b/examples/declarative/canvas/bezierCurve/bezierCurve.qml
@@ -120,4 +120,4 @@ Item {
}
}
}
-}
+} \ No newline at end of file
diff --git a/examples/declarative/canvas/quadraticCurveTo/quadraticCurveTo.qml b/examples/declarative/canvas/quadraticCurveTo/quadraticCurveTo.qml
index 00d9e9d2dc..7bd954648a 100644
--- a/examples/declarative/canvas/quadraticCurveTo/quadraticCurveTo.qml
+++ b/examples/declarative/canvas/quadraticCurveTo/quadraticCurveTo.qml
@@ -124,4 +124,4 @@ Item {
}
}
}
-}
+} \ No newline at end of file
diff --git a/examples/declarative/canvas/roundedrect/roundedrect.qml b/examples/declarative/canvas/roundedrect/roundedrect.qml
index 50c07eac42..c657e315e5 100644
--- a/examples/declarative/canvas/roundedrect/roundedrect.qml
+++ b/examples/declarative/canvas/roundedrect/roundedrect.qml
@@ -121,4 +121,4 @@ Item {
}
}
}
-}
+} \ No newline at end of file
diff --git a/examples/declarative/canvas/smile/smile.qml b/examples/declarative/canvas/smile/smile.qml
index 3a7fbe7cac..7db84a1d5e 100644
--- a/examples/declarative/canvas/smile/smile.qml
+++ b/examples/declarative/canvas/smile/smile.qml
@@ -124,4 +124,4 @@ Item {
}
}
}
-}
+} \ No newline at end of file
diff --git a/examples/declarative/canvas/squircle/squircle.qml b/examples/declarative/canvas/squircle/squircle.qml
index f9845e849e..9f69dcffd7 100644
--- a/examples/declarative/canvas/squircle/squircle.qml
+++ b/examples/declarative/canvas/squircle/squircle.qml
@@ -151,4 +151,4 @@ Item {
}
}
}
-}
+} \ No newline at end of file
diff --git a/examples/declarative/canvas/tiger/tiger.qml b/examples/declarative/canvas/tiger/tiger.qml
index 5ec920436c..0c53a2bd39 100644
--- a/examples/declarative/canvas/tiger/tiger.qml
+++ b/examples/declarative/canvas/tiger/tiger.qml
@@ -125,4 +125,4 @@ Item {
}
}
}
-}
+} \ No newline at end of file
diff --git a/examples/declarative/canvas/twitterfriends/TwitterUser.qml b/examples/declarative/canvas/twitterfriends/TwitterUser.qml
index 7b16581d69..8f98505a0b 100644
--- a/examples/declarative/canvas/twitterfriends/TwitterUser.qml
+++ b/examples/declarative/canvas/twitterfriends/TwitterUser.qml
@@ -291,4 +291,4 @@ Item {
x.send();
}
}
-}
+} \ No newline at end of file
diff --git a/src/declarative/items/context2d/qsgcanvasitem.cpp b/src/declarative/items/context2d/qsgcanvasitem.cpp
index 2ecd322288..50cbc7e2f1 100644
--- a/src/declarative/items/context2d/qsgcanvasitem.cpp
+++ b/src/declarative/items/context2d/qsgcanvasitem.cpp
@@ -216,6 +216,7 @@ void QSGCanvasItem::setCanvasSize(const QSizeF & size)
d->canvasSize = size;
emit canvasSizeChanged();
polish();
+ update();
}
}
@@ -249,6 +250,7 @@ void QSGCanvasItem::setTileSize(const QSize & size)
emit tileSizeChanged();
polish();
+ update();
}
}
@@ -279,6 +281,7 @@ void QSGCanvasItem::setCanvasWindow(const QRectF& rect)
d->hasCanvasWindow = true;
emit canvasWindowChanged();
polish();
+ update();
}
}
@@ -378,6 +381,7 @@ void QSGCanvasItem::setRenderInThread(bool renderInThread)
disconnect(this, SIGNAL(painted()), this, SLOT(update()));
emit renderInThreadChanged();
polish();
+ update();
}
}
@@ -406,26 +410,29 @@ void QSGCanvasItem::geometryChanged(const QRectF &newGeometry,
}
polish();
+ update();
}
void QSGCanvasItem::componentComplete()
{
Q_D(QSGCanvasItem);
- createContext();
+ if (!d->context)
+ createContext();
createTexture();
- markDirty(d->canvasWindow);
+
+ _doPainting(canvasWindow());
QSGItem::componentComplete();
d->baseUrl = qmlEngine(this)->contextForObject(this)->baseUrl();
d->componentCompleted = true;
+ update();
}
void QSGCanvasItem::updatePolish()
{
Q_D(QSGCanvasItem);
-
QSGItem::updatePolish();
if (d->texture) {
if (!d->renderInThread && d->dirtyRect.isValid())
@@ -507,9 +514,9 @@ QDeclarativeV8Handle QSGCanvasItem::getContext(const QString &contextId)
Q_D(QSGCanvasItem);
Q_UNUSED(contextId);
- if (d->context)
- return QDeclarativeV8Handle::fromHandle(d->context->v8value());
- return QDeclarativeV8Handle::fromHandle(v8::Undefined());
+ if (!d->context)
+ createContext();
+ return QDeclarativeV8Handle::fromHandle(d->context->v8value());
}
/*!
@@ -527,6 +534,7 @@ void QSGCanvasItem::markDirty(const QRectF& region)
Q_D(QSGCanvasItem);
d->dirtyRect |= region;
polish();
+ update();
}
@@ -717,4 +725,4 @@ QString QSGCanvasItem::toDataURL(const QString& mimeType) const
the Canvas is actually rendered.
*/
-QT_END_NAMESPACE \ No newline at end of file
+QT_END_NAMESPACE
diff --git a/src/declarative/items/context2d/qsgcanvasitem_p.h b/src/declarative/items/context2d/qsgcanvasitem_p.h
index 8d6441ac60..a2dfb7968a 100644
--- a/src/declarative/items/context2d/qsgcanvasitem_p.h
+++ b/src/declarative/items/context2d/qsgcanvasitem_p.h
@@ -45,8 +45,6 @@
#include "qsgitem.h"
#include <private/qv8engine_p.h>
-
-
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -54,7 +52,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class QSGContext2D;
class QSGCanvasItemPrivate;
-class QSGCanvasItem : public QSGItem
+class Q_DECLARATIVE_EXPORT QSGCanvasItem : public QSGItem
{
Q_OBJECT
Q_ENUMS(RenderTarget)
@@ -147,4 +145,4 @@ QML_DECLARE_TYPE(QSGCanvasItem)
QT_END_HEADER
-#endif //QSGCANVASITEM_P_H \ No newline at end of file
+#endif //QSGCANVASITEM_P_H
diff --git a/src/declarative/items/context2d/qsgcontext2d.cpp b/src/declarative/items/context2d/qsgcontext2d.cpp
index 205809861b..71cc9dc0c9 100644
--- a/src/declarative/items/context2d/qsgcontext2d.cpp
+++ b/src/declarative/items/context2d/qsgcontext2d.cpp
@@ -95,205 +95,85 @@ QT_BEGIN_NAMESPACE
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)
#define CHECK_CONTEXT(r) if (!r || !r->context || !r->context->buffer()) \
V8THROW_ERROR("Not a Context2D object");
#define CHECK_CONTEXT_SETTER(r) if (!r || !r->context || !r->context->buffer()) \
V8THROW_ERROR_SETTER("Not a Context2D object");
+#define qClamp(val, min, max) qMin(qMax(val, min), max)
-static inline int extractInt(const char **name)
+QColor qt_color_from_string(const QString& name)
{
- int result = 0;
- bool negative = false;
-
- //eat leading whitespace
- while (isspace(*name[0]))
- ++*name;
-
- if (*name[0] == '-') {
- ++*name;
- negative = true;
- } /*else if (name[0] == '+')
- ++name; //ignore*/
-
- //construct number
- while (isdigit(*name[0])) {
- result = result * 10 + (*name[0] - '0');
- ++*name;
- }
- if (negative)
- result = -result;
-
- //handle optional percentage
- if (*name[0] == '%')
- result *= qreal(255)/100; //### floor or round?
-
- //eat trailing whitespace
- while (isspace(*name[0]))
- ++*name;
+ //rgb/hsl color string has at least 7 characters
+ if (name.isEmpty() || name.size() > 255 || name.size() <= 7)
+ return QColor(name);
+ else {
+ const char* data = name.toLatin1().constData();
+ bool isRgb = false, isHsl = false, hasAlpha = false;
+
+ int pos = 0;
+ while (isspace(data[pos])) pos++;
+
+ if (strncmp(&(data[pos]), "rgb", 3) == 0)
+ isRgb = true;
+ else if (strncmp(&(data[pos]), "hsl", 3) == 0)
+ isHsl = true;
+ else
+ return QColor(name);
+ pos+=3;
+ if (data[pos] == 'a')
+ hasAlpha = true;
+
+ int rh, gs, bl, alpha = 255;
+
+ const int len = name.size();
+ while (pos < len && (data[pos] != '(' || isspace(data[pos]))) pos++;
+ if (pos >= len) return QColor();
+
+ //red
+ while (pos < len && !isdigit(data[pos])) pos++;
+ if (pos >= len) return QColor();
+ rh = atoi(&(data[pos]));
+ while (pos < len && ((data[pos] != ',' && data[pos] != '%') || isspace(data[pos]))) pos++;
+ if (data[pos] == '%') {
+ rh = qRound(rh/100.0 * 255);
+ pos++;
+ }
+ //green
+ while (pos < len && !isdigit(data[pos])) pos++;
+ if (pos >= len) return QColor();
+ gs = atoi(&(data[pos]));
+ while (pos < len && ((data[pos] != ',' && data[pos] != '%') || isspace(data[pos]))) pos++;
+ if (data[pos] == '%') {
+ gs = qRound(gs/100.0 * 255);
+ pos++;
+ }
- return result;
-}
+ //blue
+ while (pos < len && !isdigit(data[pos])) pos++;
+ if (pos >= len)
+ return QColor();
+ bl = atoi(&(data[pos]));
+ while (pos < len && ((data[pos] != ',' && data[pos] != '%') || isspace(data[pos]))) pos++;
+ if (data[pos] == '%') {
+ bl = qRound(bl/100.0 * 255);
+ pos++;
+ }
-static bool qt_get_rgb(const QString &string, QRgb *rgb)
-{
- const char *name = string.toLatin1().constData();
- int len = qstrlen(name);
-
- if (len < 5)
- return false;
+ if (hasAlpha) {
+ while (pos < len && !isdigit(data[pos])) pos++;
+ if (pos >= len)
+ return QColor();
+ alpha = qRound(strtof(&(data[pos]), 0) * 255);
+ }
- bool handleAlpha = false;
-
- if (name[0] != 'r')
- return false;
- if (name[1] != 'g')
- return false;
- if (name[2] != 'b')
- return false;
- if (name[3] == 'a') {
- handleAlpha = true;
- if(name[3] != '(')
- return false;
- } else if (name[3] != '(')
- return false;
-
- name += 4;
-
- int r, g, b, a = 1;
- int result;
-
- //red
- result = extractInt(&name);
- if (name[0] == ',') {
- r = result;
- ++name;
- } else
- return false;
-
- //green
- result = extractInt(&name);
- if (name[0] == ',') {
- g = result;
- ++name;
- } else
- return false;
-
- char nextChar = handleAlpha ? ',' : ')';
-
- //blue
- result = extractInt(&name);
- if (name[0] == nextChar) {
- b = result;
- ++name;
- } else
- return false;
-
- //alpha
- if (handleAlpha) {
- result = extractInt(&name);
- if (name[0] == ')') {
- a = result * 255; //map 0-1 to 0-255
- ++name;
- } else
- return false;
- }
-
- if (name[0] != '\0')
- return false;
-
- *rgb = qRgba(qClamp(r,0,255), qClamp(g,0,255), qClamp(b,0,255), qClamp(a,0,255));
- return true;
-}
-
-//### unify with qt_get_rgb?
-static bool qt_get_hsl(const QString &string, QColor *color)
-{
- const char *name = string.toLatin1().constData();
- int len = qstrlen(name);
-
- if (len < 5)
- return false;
-
- bool handleAlpha = false;
-
- if (name[0] != 'h')
- return false;
- if (name[1] != 's')
- return false;
- if (name[2] != 'l')
- return false;
- if (name[3] == 'a') {
- handleAlpha = true;
- if(name[3] != '(')
- return false;
- } else if (name[3] != '(')
- return false;
-
- name += 4;
-
- int h, s, l, a = 1;
- int result;
-
- //hue
- result = extractInt(&name);
- if (name[0] == ',') {
- h = result;
- ++name;
- } else
- return false;
-
- //saturation
- result = extractInt(&name);
- if (name[0] == ',') {
- s = result;
- ++name;
- } else
- return false;
-
- char nextChar = handleAlpha ? ',' : ')';
-
- //lightness
- result = extractInt(&name);
- if (name[0] == nextChar) {
- l = result;
- ++name;
- } else
- return false;
-
- //alpha
- if (handleAlpha) {
- result = extractInt(&name);
- if (name[0] == ')') {
- a = result * 255; //map 0-1 to 0-255
- ++name;
- } else
- return false;
- }
-
- if (name[0] != '\0')
- return false;
-
- *color = QColor::fromHsl(qClamp(h,0,255), qClamp(s,0,255), qClamp(l,0,255), qClamp(a,0,255));
- return true;
-}
-
-//### optimize further
-QColor qt_color_from_string(const QString &name)
-{
- if (name.startsWith(QLatin1String("rgb"))) {
- QRgb rgb;
- if (qt_get_rgb(name, &rgb))
- return QColor(rgb);
- } else if (name.startsWith(QLatin1String("hsl"))) {
- QColor color;
- if (qt_get_hsl(name, &color))
- return color;
+ if (isRgb)
+ return QColor::fromRgba(qRgba(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255)));
+ else
+ return QColor::fromHsl(qClamp(rh, 0, 255), qClamp(gs, 0, 255), qClamp(bl, 0, 255), qClamp(alpha, 0, 255));
}
-
- return QColor(name);
+ return QColor();
}
QFont qt_font_from_string(const QString& fontString) {
@@ -347,8 +227,14 @@ class QV8Context2DStyleResource : public QV8ObjectResource
{
V8_RESOURCE_TYPE(Context2DStyleType)
public:
- QV8Context2DStyleResource(QV8Engine *e) : QV8ObjectResource(e) {}
+ QV8Context2DStyleResource(QV8Engine *e)
+ : QV8ObjectResource(e)
+ , patternRepeatX(false)
+ , patternRepeatY(false)
+ {}
QBrush brush;
+ bool patternRepeatX:1;
+ bool patternRepeatY:1;
};
class QV8Context2DPixelArrayResource : public QV8ObjectResource
@@ -527,10 +413,10 @@ static v8::Local<v8::Object> qt_create_image_data(qreal w, qreal h, QV8Engine* e
QV8Context2DPixelArrayResource *r = new QV8Context2DPixelArrayResource(engine);
if (image.isNull()) {
r->image = QImage(w, h, QImage::Format_ARGB32);
- r->image.fill(Qt::transparent);
+ r->image.fill(0x00000000);
} else {
Q_ASSERT(image.width() == w && image.height() == h);
- r->image = image;
+ r->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
v8::Local<v8::Object> pixelData = ed->constructorPixelArray->NewInstance();
pixelData->SetExternalResource(r);
@@ -936,6 +822,19 @@ static v8::Handle<v8::Value> ctx2d_fillStyle(v8::Local<v8::String>, const v8::Ac
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
CHECK_CONTEXT(r)
+ QV8Engine *engine = V8ENGINE_ACCESSOR();
+
+ QColor color = r->context->state.fillStyle.color();
+ if (color.isValid()) {
+ if (color.alpha() == 255)
+ return engine->toString(color.name());
+ QString alphaString = QString::number(color.alphaF(), 'f');
+ while (alphaString.endsWith('0'))
+ alphaString.chop(1);
+ if (alphaString.endsWith('.'))
+ alphaString += '0';
+ return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
+ }
return r->context->m_fillStyle;
}
@@ -946,17 +845,20 @@ static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> valu
QV8Engine *engine = V8ENGINE_ACCESSOR();
- r->context->m_fillStyle = value;
if (value->IsObject()) {
QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
r->context->state.fillStyle = color;
r->context->buffer()->setFillStyle(color);
+ r->context->m_fillStyle = value;
} else {
QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
if (style && style->brush != r->context->state.fillStyle) {
r->context->state.fillStyle = style->brush;
- r->context->buffer()->setFillStyle(style->brush);
+ r->context->buffer()->setFillStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
+ r->context->m_fillStyle = value;
+ r->context->state.fillPatternRepeatX = style->patternRepeatX;
+ r->context->state.fillPatternRepeatY = style->patternRepeatY;
}
}
} else if (value->IsString()) {
@@ -964,6 +866,7 @@ static void ctx2d_fillStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> valu
if (color.isValid() && r->context->state.fillStyle != QBrush(color)) {
r->context->state.fillStyle = QBrush(color);
r->context->buffer()->setFillStyle(r->context->state.fillStyle);
+ r->context->m_fillStyle = value;
}
}
}
@@ -1024,7 +927,19 @@ v8::Handle<v8::Value> ctx2d_strokeStyle(v8::Local<v8::String>, const v8::Accesso
QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(info.This());
CHECK_CONTEXT(r)
+ QV8Engine *engine = V8ENGINE_ACCESSOR();
+ QColor color = r->context->state.strokeStyle.color();
+ if (color.isValid()) {
+ if (color.alpha() == 255)
+ return engine->toString(color.name());
+ QString alphaString = QString::number(color.alphaF(), 'f');
+ while (alphaString.endsWith('0'))
+ alphaString.chop(1);
+ if (alphaString.endsWith('.'))
+ alphaString += '0';
+ return engine->toString(QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString));
+ }
return r->context->m_strokeStyle;
}
@@ -1035,17 +950,21 @@ static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> va
QV8Engine *engine = V8ENGINE_ACCESSOR();
- r->context->m_strokeStyle = value;
if (value->IsObject()) {
QColor color = engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
r->context->state.fillStyle = color;
r->context->buffer()->setStrokeStyle(color);
+ r->context->m_strokeStyle = value;
} else {
QV8Context2DStyleResource *style = v8_resource_cast<QV8Context2DStyleResource>(value->ToObject());
if (style && style->brush != r->context->state.strokeStyle) {
r->context->state.strokeStyle = style->brush;
- r->context->buffer()->setStrokeStyle(style->brush);
+ r->context->buffer()->setStrokeStyle(style->brush, style->patternRepeatX, style->patternRepeatY);
+ r->context->m_strokeStyle = value;
+ r->context->state.strokePatternRepeatX = style->patternRepeatX;
+ r->context->state.strokePatternRepeatY = style->patternRepeatY;
+
}
}
} else if (value->IsString()) {
@@ -1053,6 +972,7 @@ static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> va
if (color.isValid() && r->context->state.strokeStyle != QBrush(color)) {
r->context->state.strokeStyle = QBrush(color);
r->context->buffer()->setStrokeStyle(r->context->state.strokeStyle);
+ r->context->m_strokeStyle = value;
}
}
}
@@ -1068,6 +988,7 @@ static void ctx2d_strokeStyle_set(v8::Local<v8::String>, v8::Local<v8::Value> va
\sa QtQuick2::Context2D::CanvasGradient::addColorStop
\sa QtQuick2::Context2D::createRadialGradient
+ \sa QtQuick2::Context2D::ctx2d_createConicalGradient
\sa QtQuick2::Context2D::createPattern
\sa QtQuick2::Context2D::fillStyle
\sa QtQuick2::Context2D::strokeStyle
@@ -1104,6 +1025,7 @@ static v8::Handle<v8::Value> ctx2d_createLinearGradient(const v8::Arguments &arg
\sa QtQuick2::Context2D::CanvasGradient::addColorStop
\sa QtQuick2::Context2D::createLinearGradient
+ \sa QtQuick2::Context2D::ctx2d_createConicalGradient
\sa QtQuick2::Context2D::createPattern
\sa QtQuick2::Context2D::fillStyle
\sa QtQuick2::Context2D::strokeStyle
@@ -1137,6 +1059,45 @@ static v8::Handle<v8::Value> ctx2d_createRadialGradient(const v8::Arguments &arg
return args.This();
}
+
+/*!
+ \qmlmethod QtQuick2::Context2D QtQuick2::Context2D::createConicalGradient(real x, real y, real angle)
+ Returns a CanvasGradient object that represents a conical gradient that interpolate colors counter-clockwise around a center point (\c x, \c y)
+ with start angle \c angle in units of radians.
+
+ \sa QtQuick2::Context2D::CanvasGradient::addColorStop
+ \sa QtQuick2::Context2D::createLinearGradient
+ \sa QtQuick2::Context2D::ctx2d_createRadialGradient
+ \sa QtQuick2::Context2D::createPattern
+ \sa QtQuick2::Context2D::fillStyle
+ \sa QtQuick2::Context2D::strokeStyle
+ */
+
+static v8::Handle<v8::Value> ctx2d_createConicalGradient(const v8::Arguments &args)
+{
+ QV8Context2DResource *r = v8_resource_cast<QV8Context2DResource>(args.This());
+ CHECK_CONTEXT(r)
+
+
+ QV8Engine *engine = V8ENGINE();
+
+ if (args.Length() == 6) {
+ QSGContext2DEngineData *ed = engineData(engine);
+ v8::Local<v8::Object> gradient = ed->constructorGradient->NewInstance();
+ QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
+
+ qreal x = args[0]->NumberValue();
+ qreal y = args[1]->NumberValue();
+ qreal angle = DEGREES(args[2]->NumberValue());
+ //TODO:infinite or NaN, a NOT_SUPPORTED_ERR exception must be raised.
+ //If either of r0 or r1 are negative, an INDEX_SIZE_ERR exception must be raised.
+ r->brush = QConicalGradient(x, y, angle);
+ gradient->SetExternalResource(r);
+ return gradient;
+ }
+
+ return args.This();
+}
/*!
\qmlmethod variant createPattern(Color color, enumeration patternMode)
This is a overload function.
@@ -1188,43 +1149,57 @@ static v8::Handle<v8::Value> ctx2d_createPattern(const v8::Arguments &args)
QV8Engine *engine = V8ENGINE();
- //FIXME::
-
-// if (args.Length() == 2) {
-// QSGContext2DEngineData *ed = engineData(engine);
-// v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
-// QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine);
-
-// QImage img;
-
-// QSGItem* item = qobject_cast<QSGItem*>(engine->toQObject(args[0]));
-// if (item) {
-// img = qt_item_to_image(item);
-// if (img.isNull()) {
-// //exception: INVALID_STATE_ERR
-// }
-// } /*else {
-// //exception: TYPE_MISMATCH_ERR
-// }*/
-
-// QString repetition = engine->toString(args[1]);
-
-// if (repetition == "repeat" || repetition.isEmpty()) {
-// //TODO
-// } else if (repetition == "repeat-x") {
-// //TODO
-// } else if (repetition == "repeat-y") {
-// //TODO
-// } else if (repetition == "no-repeat") {
-// //TODO
-// } else {
-// //TODO: exception: SYNTAX_ERR
-// }
-// r->brush = img;
-// pattern->SetExternalResource(r);
- // return pattern;
-// }
- return v8::Null();
+ if (args.Length() == 2) {
+ QSGContext2DEngineData *ed = engineData(engine);
+ QV8Context2DStyleResource *styleResouce = new QV8Context2DStyleResource(engine);
+
+ QColor color = engine->toVariant(args[0], qMetaTypeId<QColor>()).value<QColor>();
+ if (color.isValid()) {
+ int patternMode = args[1]->IntegerValue();
+ Qt::BrushStyle style = Qt::SolidPattern;
+ if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
+ style = static_cast<Qt::BrushStyle>(patternMode);
+ }
+ styleResouce->brush = QBrush(color, style);
+ } else {
+ QImage patternTexture;
+
+ if (args[0]->IsObject()) {
+ QV8Context2DPixelArrayResource *pixelData = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->Get(v8::String::New("data"))->ToObject());
+ if (pixelData) {
+ patternTexture = pixelData->image;
+ }
+ } else {
+ patternTexture = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
+ }
+
+ if (!patternTexture.isNull()) {
+ styleResouce->brush.setTextureImage(patternTexture);
+
+ QString repetition = engine->toString(args[1]);
+ if (repetition == "repeat" || repetition.isEmpty()) {
+ styleResouce->patternRepeatX = true;
+ styleResouce->patternRepeatY = true;
+ } else if (repetition == "repeat-x") {
+ styleResouce->patternRepeatX = true;
+ } else if (repetition == "repeat-y") {
+ styleResouce->patternRepeatY = true;
+ } else if (repetition == "no-repeat") {
+ styleResouce->patternRepeatY = false;
+ styleResouce->patternRepeatY = false;
+ } else {
+ //TODO: exception: SYNTAX_ERR
+ }
+
+ }
+ }
+
+ v8::Local<v8::Object> pattern = ed->constructorPattern->NewInstance();
+ pattern->SetExternalResource(styleResouce);
+ return pattern;
+
+ }
+ return v8::Undefined();
}
// line styles
@@ -2490,7 +2465,7 @@ static v8::Handle<v8::Value> ctx2d_imageData_filter(const v8::Arguments &args)
switch(filterFlag) {
case QSGCanvasItem::Mono :
{
- r->image = r->image.convertToFormat(QImage::Format_Mono).convertToFormat(QImage::Format_ARGB32);
+ r->image = r->image.convertToFormat(QImage::Format_Mono).convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
break;
case QSGCanvasItem::GrayScale :
@@ -2610,9 +2585,8 @@ v8::Handle<v8::Value> ctx2d_pixelArray_indexed(uint32_t index, const v8::Accesso
{
QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(args.This());
- if (r && index && index < r->image.width() * r->image.height() * 4) {
+ if (r && index >= 0 && index < r->image.width() * r->image.height() * 4) {
const int w = r->image.width();
- const int h = r->image.height();
const int row = (index / 4) / w;
const int col = (index / 4) % w;
const QRgb* pixel = reinterpret_cast<const QRgb*>(r->image.constScanLine(row));
@@ -2636,7 +2610,7 @@ v8::Handle<v8::Value> ctx2d_pixelArray_indexed_set(uint32_t index, v8::Local<v8:
QV8Context2DPixelArrayResource *r = v8_resource_cast<QV8Context2DPixelArrayResource>(info.This());
const int v = value->Uint32Value();
- if (r && index > 0 && index < r->image.width() * r->image.height() * 4 && v > 0 && v <= 255) {
+ if (r && index >= 0 && index < r->image.width() * r->image.height() * 4 && v > 0 && v <= 255) {
const int w = r->image.width();
const int row = (index / 4) / w;
const int col = (index / 4) % w;
@@ -2722,8 +2696,6 @@ static v8::Handle<v8::Value> ctx2d_getImageData(const v8::Arguments &args)
qreal w = args[2]->NumberValue();
qreal h = args[3]->NumberValue();
QImage image = r->context->canvas()->toImage(QRectF(x, y, w, h));
- if (image.format() != QImage::Format_ARGB32)
- image = image.convertToFormat(QImage::Format_ARGB32);
v8::Local<v8::Object> imageData = qt_create_image_data(w, h, engine, image);
return imageData;
@@ -3181,6 +3153,7 @@ QSGContext2DEngineData::QSGContext2DEngineData(QV8Engine *engine)
ft->InstanceTemplate()->SetAccessor(v8::String::New("strokeStyle"), ctx2d_strokeStyle, ctx2d_strokeStyle_set, v8::External::Wrap(engine));
ft->PrototypeTemplate()->Set(v8::String::New("createLinearGradient"), V8FUNCTION(ctx2d_createLinearGradient, engine));
ft->PrototypeTemplate()->Set(v8::String::New("createRadialGradient"), V8FUNCTION(ctx2d_createRadialGradient, engine));
+ ft->PrototypeTemplate()->Set(v8::String::New("createConicalGradient"), V8FUNCTION(ctx2d_createConicalGradient, engine));
ft->PrototypeTemplate()->Set(v8::String::New("createPattern"), V8FUNCTION(ctx2d_createPattern, engine));
ft->InstanceTemplate()->SetAccessor(v8::String::New("lineCap"), ctx2d_lineCap, ctx2d_lineCap_set, v8::External::Wrap(engine));
ft->InstanceTemplate()->SetAccessor(v8::String::New("lineJoin"), ctx2d_lineJoin, ctx2d_lineJoin_set, v8::External::Wrap(engine));
@@ -3326,8 +3299,12 @@ void QSGContext2D::reset()
newState.clipPath = defaultClipPath;
newState.clipPath.setFillRule(Qt::WindingFill);
- newState.strokeStyle = Qt::black;
- newState.fillStyle = Qt::black;
+ newState.strokeStyle = QColor(qRgba(1,1,1,1));
+ newState.fillStyle = QColor(qRgba(1,1,1,1));
+ newState.fillPatternRepeatX = false;
+ newState.fillPatternRepeatY = false;
+ newState.strokePatternRepeatX = false;
+ newState.strokePatternRepeatY = false;
newState.fillRule = Qt::WindingFill;
newState.globalAlpha = 1.0;
newState.lineWidth = 1;
@@ -3370,4 +3347,4 @@ void QSGContext2D::setV8Engine(QV8Engine *engine)
}
}
-QT_END_NAMESPACE
+QT_END_NAMESPACE \ No newline at end of file
diff --git a/src/declarative/items/context2d/qsgcontext2d_p.h b/src/declarative/items/context2d/qsgcontext2d_p.h
index 830a185a31..5354876d5d 100644
--- a/src/declarative/items/context2d/qsgcontext2d_p.h
+++ b/src/declarative/items/context2d/qsgcontext2d_p.h
@@ -69,7 +69,7 @@ class QSGCanvasItem;
class QSGContext2DCommandBuffer;
class QDeclarativePixmap;
-class QSGContext2D
+class Q_DECLARATIVE_EXPORT QSGContext2D
{
public:
enum TextBaseLineType { Alphabetic=0, Top, Middle, Bottom, Hanging};
@@ -111,6 +111,10 @@ public:
QPainterPath clipPath;
QBrush strokeStyle;
QBrush fillStyle;
+ bool fillPatternRepeatX:1;
+ bool fillPatternRepeatY:1;
+ bool strokePatternRepeatX:1;
+ bool strokePatternRepeatY:1;
Qt::FillRule fillRule;
qreal globalAlpha;
qreal lineWidth;
diff --git a/src/declarative/items/context2d/qsgcontext2dcommandbuffer.cpp b/src/declarative/items/context2d/qsgcontext2dcommandbuffer.cpp
index 550ad77515..51730d41ec 100644
--- a/src/declarative/items/context2d/qsgcontext2dcommandbuffer.cpp
+++ b/src/declarative/items/context2d/qsgcontext2dcommandbuffer.cpp
@@ -54,7 +54,7 @@ static QImage makeShadowImage(const QImage& image, qreal offsetX, qreal offsetY,
{
QImage shadowImg(image.width() + blur + qAbs(offsetX),
image.height() + blur + qAbs(offsetY),
- QImage::Format_ARGB32);
+ QImage::Format_ARGB32_Premultiplied);
shadowImg.fill(0);
QPainter tmpPainter(&shadowImg);
tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
@@ -80,7 +80,7 @@ static void fillRectShadow(QPainter* p, QRectF shadowRect, qreal offsetX, qreal
QRectF r = shadowRect;
r.moveTo(0, 0);
- QImage shadowImage(r.size().width() + 1, r.size().height() + 1, QImage::Format_ARGB32);
+ QImage shadowImage(r.size().width() + 1, r.size().height() + 1, QImage::Format_ARGB32_Premultiplied);
QPainter tp;
tp.begin(&shadowImage);
tp.fillRect(r, p->brush());
@@ -99,7 +99,7 @@ static void fillShadowPath(QPainter* p, const QPainterPath& path, qreal offsetX,
QRectF r = path.boundingRect();
QImage img(r.size().width() + r.left() + 1,
r.size().height() + r.top() + 1,
- QImage::Format_ARGB32);
+ QImage::Format_ARGB32_Premultiplied);
img.fill(0);
QPainter tp(&img);
tp.fillPath(path.translated(0, 0), p->brush());
@@ -118,7 +118,7 @@ static void strokeShadowPath(QPainter* p, const QPainterPath& path, qreal offset
QRectF r = path.boundingRect();
QImage img(r.size().width() + r.left() + 1,
r.size().height() + r.top() + 1,
- QImage::Format_ARGB32);
+ QImage::Format_ARGB32_Premultiplied);
img.fill(0);
QPainter tp(&img);
tp.strokePath(path, p->pen());
@@ -130,6 +130,72 @@ static void strokeShadowPath(QPainter* p, const QPainterPath& path, qreal offset
p->drawImage(dx, dy, shadowImage);
p->strokePath(path, p->pen());
}
+static inline void drawRepeatPattern(QPainter* p, const QImage& image, const QRectF& rect, const bool repeatX, const bool repeatY)
+{
+ // Patterns must be painted so that the top left of the first image is anchored at
+ // the origin of the coordinate space
+ if (!image.isNull()) {
+ int w = image.width();
+ int h = image.height();
+ int startX, startY;
+ QRect r(static_cast<int>(rect.x()), static_cast<int>(rect.y()), static_cast<int>(rect.width()), static_cast<int>(rect.height()));
+
+ // startX, startY is the coordinate of the first image we need to put on the left-top of the rect
+ if (repeatX && repeatY) {
+ // repeat
+ // startX, startY is at the left top side of the left-top of the rect
+ startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
+ startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
+ } else {
+ if (!repeatX && !repeatY) {
+ // no-repeat
+ // only draw the image once at orgin once, check if need to draw
+ QRect imageRect(0, 0, w, h);
+ if (imageRect.intersects(r)) {
+ startX = 0;
+ startY = 0;
+ } else
+ return;
+ } else if (repeatX && !repeatY) {
+ // repeat-x
+ // startY is fixed, but startX change based on the left-top of the rect
+ QRect imageRect(r.x(), 0, r.width(), h);
+ if (imageRect.intersects(r)) {
+ startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
+ startY = 0;
+ } else
+ return;
+ } else {
+ // repeat-y
+ // startX is fixed, but startY change based on the left-top of the rect
+ QRect imageRect(0, r.y(), w, r.height());
+ if (imageRect.intersects(r)) {
+ startX = 0;
+ startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
+ } else
+ return;
+ }
+ }
+
+ int x = startX;
+ int y = startY;
+ do {
+ // repeat Y
+ do {
+ // repeat X
+ QRect imageRect(x, y, w, h);
+ QRect intersectRect = imageRect.intersected(r);
+ QPoint destStart(intersectRect.x(), intersectRect.y());
+ QRect sourceRect(intersectRect.x() - imageRect.x(), intersectRect.y() - imageRect.y(), intersectRect.width(), intersectRect.height());
+
+ p->drawImage(destStart, image, sourceRect);
+ x += w;
+ } while (repeatX && x < r.x() + r.width());
+ x = startX;
+ y += h;
+ } while (repeatY && y < r.y() + r.height());
+ }
+}
QPen QSGContext2DCommandBuffer::makePen(QSGContext2D::State state)
{
@@ -186,7 +252,7 @@ QSGContext2D::State QSGContext2DCommandBuffer::replay(QPainter* p, QSGContext2D:
}
case QSGContext2D::ClearRect:
{
- p->eraseRect(takeRect());
+ p->fillRect(takeRect(), QColor(qRgba(0, 0, 0, 0)));
break;
}
case QSGContext2D::FillRect:
@@ -221,12 +287,16 @@ QSGContext2D::State QSGContext2DCommandBuffer::replay(QPainter* p, QSGContext2D:
case QSGContext2D::FillStyle:
{
state.fillStyle = takeFillStyle();
+ state.fillPatternRepeatX = takeBool();
+ state.fillPatternRepeatY = takeBool();
p->setBrush(state.fillStyle);
break;
}
case QSGContext2D::StrokeStyle:
{
state.strokeStyle = takeStrokeStyle();
+ state.strokePatternRepeatX = takeBool();
+ state.strokePatternRepeatY = takeBool();
pen.setBrush(state.strokeStyle);
p->setPen(pen);
break;
@@ -264,6 +334,7 @@ QSGContext2D::State QSGContext2DCommandBuffer::replay(QPainter* p, QSGContext2D:
break;
case QSGContext2D::Fill:
{
+ bool hasPattern = p->brush().style() == Qt::TexturePattern;
if (HAS_SHADOW(state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor))
fillShadowPath(p,takePath(), state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
else
@@ -289,13 +360,6 @@ QSGContext2D::State QSGContext2DCommandBuffer::replay(QPainter* p, QSGContext2D:
p->setClipPath(clipPath);
break;
}
- case QSGContext2D::UpdateBrush:
- {
- state.fillStyle = takeBrush();
- p->setBrush(state.fillStyle);
- break;
- }
-
case QSGContext2D::GlobalAlpha:
{
state.globalAlpha = takeGlobalAlpha();
@@ -357,6 +421,7 @@ QSGContext2D::State QSGContext2DCommandBuffer::replay(QPainter* p, QSGContext2D:
QSGContext2DCommandBuffer::QSGContext2DCommandBuffer()
: cmdIdx(0)
, intIdx(0)
+ , boolIdx(0)
, realIdx(0)
, colorIdx(0)
, matrixIdx(0)
@@ -375,6 +440,7 @@ void QSGContext2DCommandBuffer::clear()
{
commands.clear();
ints.clear();
+ bools.clear();
reals.clear();
colors.clear();
matrixes.clear();
@@ -388,6 +454,7 @@ void QSGContext2DCommandBuffer::reset()
{
cmdIdx = 0;
intIdx = 0;
+ boolIdx = 0;
realIdx = 0;
colorIdx = 0;
matrixIdx = 0;
diff --git a/src/declarative/items/context2d/qsgcontext2dcommandbuffer_p.h b/src/declarative/items/context2d/qsgcontext2dcommandbuffer_p.h
index d95adeeafd..95d0e9685e 100644
--- a/src/declarative/items/context2d/qsgcontext2dcommandbuffer_p.h
+++ b/src/declarative/items/context2d/qsgcontext2dcommandbuffer_p.h
@@ -89,10 +89,11 @@ public:
ints << cm;
}
- inline void setStrokeStyle(const QBrush &style)
+ inline void setStrokeStyle(const QBrush &style, bool repeatX = false, bool repeatY = false)
{
commands << QSGContext2D::StrokeStyle;
brushes << style;
+ bools << repeatX << repeatY;
}
inline void drawImage(const QImage& image, qreal sx, qreal sy, qreal sw, qreal sh, qreal dx, qreal dy, qreal dw, qreal dh)
@@ -157,10 +158,11 @@ public:
- inline void setFillStyle(const QBrush &style)
+ inline void setFillStyle(const QBrush &style, bool repeatX = false, bool repeatY = false)
{
- commands << QSGContext2D::UpdateBrush;
+ commands << QSGContext2D::FillStyle;
brushes << style;
+ bools << repeatX << repeatY;
}
@@ -229,6 +231,7 @@ public:
inline const QImage& takeImage() { return images[imageIdx++]; }
inline int takeInt() { return ints[intIdx++]; }
+ inline bool takeBool() {return bools[boolIdx++]; }
inline qreal takeReal() { return reals[realIdx++]; }
inline QColor takeColor() { return colors[colorIdx++]; }
inline QBrush takeBrush() { return brushes[brushIdx++]; }
@@ -239,6 +242,7 @@ private:
void setPainterState(QPainter* painter, QSGContext2D::State state, const QPen& pen);
int cmdIdx;
int intIdx;
+ int boolIdx;
int realIdx;
int colorIdx;
int matrixIdx;
@@ -248,6 +252,7 @@ private:
QVector<QSGContext2D::PaintCommand> commands;
QVector<int> ints;
+ QVector<bool> bools;
QVector<qreal> reals;
QVector<QColor> colors;
QVector<QTransform> matrixes;
diff --git a/src/declarative/items/context2d/qsgcontext2dtexture.cpp b/src/declarative/items/context2d/qsgcontext2dtexture.cpp
index 3f7692c0ba..455a46884b 100644
--- a/src/declarative/items/context2d/qsgcontext2dtexture.cpp
+++ b/src/declarative/items/context2d/qsgcontext2dtexture.cpp
@@ -163,11 +163,15 @@ bool QSGContext2DTexture::setCanvasWindow(const QRect& r)
bool QSGContext2DTexture::setDirtyRect(const QRect &r)
{
bool doDirty = false;
- foreach (QSGContext2DTile* t, m_tiles) {
- bool dirty = t->rect().intersected(r).isValid();
- t->markDirty(dirty);
- if (dirty)
- doDirty = true;
+ if (m_tiledCanvas) {
+ foreach (QSGContext2DTile* t, m_tiles) {
+ bool dirty = t->rect().intersected(r).isValid();
+ t->markDirty(dirty);
+ if (dirty)
+ doDirty = true;
+ }
+ } else {
+ doDirty = m_canvasWindow.intersected(r).isValid();
}
return doDirty;
}
@@ -186,23 +190,24 @@ void QSGContext2DTexture::canvasChanged(const QSize& canvasSize, const QSize& ti
bool canvasChanged = setCanvasSize(canvasSize);
bool tileChanged = setTileSize(ts);
- bool doDirty = false;
if (canvasSize == canvasWindow.size()) {
m_tiledCanvas = false;
m_dirtyCanvas = false;
} else {
m_tiledCanvas = true;
- if (dirtyRect.isValid())
- doDirty = setDirtyRect(dirtyRect);
}
- bool windowChanged = setCanvasWindow(canvasWindow);
+ bool doDirty = false;
+ if (dirtyRect.isValid())
+ doDirty = setDirtyRect(dirtyRect);
+ bool windowChanged = setCanvasWindow(canvasWindow);
if (windowChanged || doDirty) {
if (m_threadRendering)
QMetaObject::invokeMethod(this, "paint", Qt::QueuedConnection);
- else if (supportDirectRendering())
- QMetaObject::invokeMethod(this, "paint", Qt::DirectConnection);
+ else if (supportDirectRendering()) {
+ QMetaObject::invokeMethod(this, "paint", Qt::DirectConnection);
+ }
}
setSmooth(smooth);
@@ -312,7 +317,7 @@ void QSGContext2DTexture::paint()
return;
} else if (dirtyTile) {
m_state = ccb->replay(tile->createPainter(smooth), oldState);
-
+ tile->drawFinished();
lock();
tile->markDirty(false);
unlock();
@@ -568,12 +573,20 @@ QPaintDevice* QSGContext2DFBOTexture::beginPainting()
m_fbo->bind();
- if (!m_paint_device)
- m_paint_device = new QOpenGLPaintDevice(m_fbo->size());
+ if (!m_paint_device) {
+ QOpenGLPaintDevice *gl_device = new QOpenGLPaintDevice(m_fbo->size());
+ m_paint_device = gl_device;
+ }
return m_paint_device;
}
+void QSGContext2DFBOTexture::endPainting()
+{
+ QSGContext2DTexture::endPainting();
+ if (m_fbo)
+ m_fbo->release();
+}
void qt_quit_context2d_render_thread()
{
QThread* thread = globalCanvasThreadRenderInstance();
@@ -698,7 +711,7 @@ QPaintDevice* QSGContext2DImageTexture::beginPainting()
lock();
if (m_image.size() != m_canvasWindow.size()) {
m_image = QImage(m_canvasWindow.size(), QImage::Format_ARGB32_Premultiplied);
- m_image.fill(Qt::transparent);
+ m_image.fill(0x00000000);
}
unlock();
return &m_image;
diff --git a/src/declarative/items/context2d/qsgcontext2dtexture_p.h b/src/declarative/items/context2d/qsgcontext2dtexture_p.h
index c91d3fb2ba..fc251cde7b 100644
--- a/src/declarative/items/context2d/qsgcontext2dtexture_p.h
+++ b/src/declarative/items/context2d/qsgcontext2dtexture_p.h
@@ -138,6 +138,7 @@ public:
virtual QSGContext2DTile* createTile() const;
virtual QImage toImage(const QRectF& region = QRectF());
virtual QPaintDevice* beginPainting();
+ virtual void endPainting();
QRectF textureSubRect() const;
virtual bool supportThreadRendering() const {return false;}
virtual bool supportDirectRendering() const {return false;}
diff --git a/src/declarative/items/context2d/qsgcontext2dtile.cpp b/src/declarative/items/context2d/qsgcontext2dtile.cpp
index 14051b62c1..8c8ef836b0 100644
--- a/src/declarative/items/context2d/qsgcontext2dtile.cpp
+++ b/src/declarative/items/context2d/qsgcontext2dtile.cpp
@@ -109,10 +109,18 @@ void QSGContext2DFBOTile::aboutToDraw()
{
m_fbo->bind();
if (!m_device) {
- m_device = new QOpenGLPaintDevice(rect().size());
+ QOpenGLPaintDevice *gl_device = new QOpenGLPaintDevice(rect().size());
+ m_device = gl_device;
+ QPainter p(m_device);
+ p.fillRect(QRectF(0, 0, m_fbo->width(), m_fbo->height()), QColor(qRgba(0, 0, 0, 0)));
+ p.end();
}
}
+void QSGContext2DFBOTile::drawFinished()
+{
+ m_fbo->release();
+}
void QSGContext2DFBOTile::setRect(const QRect& r)
{
@@ -154,4 +162,4 @@ void QSGContext2DImageTile::setRect(const QRect& r)
m_image = QImage(r.size(), QImage::Format_ARGB32_Premultiplied);
}
m_device = &m_image;
-}
+} \ No newline at end of file
diff --git a/src/declarative/items/context2d/qsgcontext2dtile_p.h b/src/declarative/items/context2d/qsgcontext2dtile_p.h
index d5317f9357..57b68ef67d 100644
--- a/src/declarative/items/context2d/qsgcontext2dtile_p.h
+++ b/src/declarative/items/context2d/qsgcontext2dtile_p.h
@@ -67,11 +67,10 @@ public:
virtual void setRect(const QRect& r) = 0;
virtual QPainter* createPainter(bool smooth = false);
-
+ virtual void drawFinished() {}
protected:
virtual void aboutToDraw() {}
-
uint m_dirty : 1;
QRect m_rect;
QPaintDevice* m_device;
@@ -86,10 +85,10 @@ public:
~QSGContext2DFBOTile();
virtual void setRect(const QRect& r);
QOpenGLFramebufferObject* fbo() const {return m_fbo;}
+ void drawFinished();
protected:
void aboutToDraw();
-
private:
diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro
index 52abb02287..d8567db8bb 100644
--- a/tests/auto/declarative/declarative.pro
+++ b/tests/auto/declarative/declarative.pro
@@ -78,6 +78,7 @@ SGTESTS = \
qsgtextedit \
qsgtextinput \
qsgvisualdatamodel \
+ qsgcanvasitem \
SUBDIRS += $$PUBLICTESTS
@@ -91,4 +92,3 @@ contains(QT_CONFIG, private_tests) {
# Tests which should run in Pulse
PULSE_TESTS = $$SUBDIRS
-
diff --git a/tests/auto/declarative/qsgcanvasitem/data/testhelper.js b/tests/auto/declarative/qsgcanvasitem/data/testhelper.js
new file mode 100644
index 0000000000..bac0210e16
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvasitem/data/testhelper.js
@@ -0,0 +1,18 @@
+function comparePixel(ctx,x,y,r,g,b,a, d)
+{
+ var c = ctx.getImageData(x,y,1,1).data;
+ if (d === undefined)
+ d = 0;
+ r = Math.round(r);
+ g = Math.round(g);
+ b = Math.round(b);
+ a = Math.round(a);
+
+ if (Math.abs(c[0]-r)>d || Math.abs(c[1]-g)>d || Math.abs(c[2]-b)>d || Math.abs(c[3]-a)>d) {
+ console.log('Pixel compare fail:\nactual :[' + c[0]+','+c[1]+','+c[2]+','+c[3] + ']\nexpected:['+r+','+g+','+b+','+a+'] +/- '+d);
+ return false;
+ }
+ return true;
+}
+
+
diff --git a/tests/auto/declarative/qsgcanvasitem/data/tst_colors.qml b/tests/auto/declarative/qsgcanvasitem/data/tst_colors.qml
new file mode 100644
index 0000000000..a20a7dfaf9
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvasitem/data/tst_colors.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+import QtTest 1.0
+import "testhelper.js" as Helper
+
+Canvas {
+ id:canvas; width:1;height:1
+ TestCase {
+ name: "Colors"; when: windowShown
+ function test_globalAlpha() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ ctx.fillStyle = Qt.rgba(1, 0.7, 0.2, 0.5);
+ ctx.globalAlpha = 0.5;
+ ctx.fillRect(0,0,1,1);
+ var d = ctx.getImageData(0,0,1,1).data;
+ verify(Helper.comparePixel(ctx, 0, 0, 255, 0.7 * 255, 0.2*255, 0.25 * 255));
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgcanvasitem/data/tst_fillStyle.qml b/tests/auto/declarative/qsgcanvasitem/data/tst_fillStyle.qml
new file mode 100644
index 0000000000..a4b77ec2b3
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvasitem/data/tst_fillStyle.qml
@@ -0,0 +1,113 @@
+import QtQuick 2.0
+import QtTest 1.0
+import "testhelper.js" as Helper
+
+Canvas {
+ id:canvas; width:1;height:1
+ TestCase {
+ name: "fillStyle"; when: windowShown
+ function test_default() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ verify(ctx.fillStyle, "#000000");
+ ctx.clearRect(0, 0, 1, 1);
+ compare(ctx.fillStyle, "#000000");
+ }
+ function test_get() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ ctx.fillStyle = '#fa0';
+ compare(ctx.fillStyle, '#ffaa00');
+ ctx.fillStyle = Qt.rgba(0,0,0,0);
+ compare(ctx.fillStyle, 'rgba(0, 0, 0, 0.0)');
+ }
+ function test_hex() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ ctx.fillStyle = '#f00';
+ compare(ctx.fillStyle, '#ff0000');
+ ctx.fillStyle = "#0f0";
+ compare(ctx.fillStyle, '#00ff00');
+ ctx.fillStyle = "#0fF";
+ compare(ctx.fillStyle, '#00ffff');
+ ctx.fillStyle = "#0aCCfb";
+ compare(ctx.fillStyle, '#0accfb');
+
+ }
+ function test_invalid() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ ctx.fillStyle = '#fa0';
+ compare(ctx.fillStyle, '#ffaa00');
+ ctx.fillStyle = "invalid";
+ compare(ctx.fillStyle, '#ffaa00');
+ ctx.fillStyle = "rgb (1, 2, 3)";
+ compare(ctx.fillStyle, '#ffaa00');
+ ctx.fillStyle = "rgba(1, 2, 3)";
+ compare(ctx.fillStyle, '#ffaa00');
+ ctx.fillStyle = "rgb((3,4,1)";
+ compare(ctx.fillStyle, '#ffaa00');
+ ctx.fillStyle = "rgb(1, 3, 4, 0.5)";
+ compare(ctx.fillStyle, '#ffaa00');
+ ctx.fillStyle = "hsl(2, 3, 4, 0.8)";
+ compare(ctx.fillStyle, '#ffaa00');
+ ctx.fillStyle = "hsl(2, 3, 4";
+ compare(ctx.fillStyle, '#ffaa00');
+ }
+ function test_saverestore() {
+ var ctx = canvas.getContext('2d');
+ var old = ctx.fillStyle;
+ ctx.save();
+ ctx.fillStyle = "#ffaaff";
+ ctx.restore();
+ compare(ctx.fillStyle, old);
+
+ ctx.fillStyle = "#ffcc88";
+ old = ctx.fillStyle;
+ ctx.save();
+ compare(ctx.fillStyle, old);
+ ctx.restore();
+ }
+ function test_namedColor() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ ctx.fillStyle = "red";
+ ctx.fillRect(0,0,1,1);
+ verify(Helper.comparePixel(ctx,0,0,255,0,0,255));
+
+ ctx.fillStyle = "black";
+ ctx.fillRect(0,0,1,1);
+ verify(Helper.comparePixel(ctx,0,0,0,0,0,255));
+
+ ctx.fillStyle = "white";
+ ctx.fillRect(0,0,1,1);
+ verify(Helper.comparePixel(ctx,0,0,255,255,255,255));
+ }
+ function test_rgba() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ ctx.fillStyle = "rgb(-100, 300, 255)";
+ compare(ctx.fillStyle, "#00ffff");
+ ctx.fillStyle = "rgba(-100, 300, 255, 0.0)";
+ compare(ctx.fillStyle, "rgba(0, 255, 255, 0.0)");
+ ctx.fillStyle = "rgb(-10%, 110%, 50%)";
+ compare(ctx.fillStyle, "#00ff80");
+
+ ctx.clearRect(0, 0, 1, 1);
+ ctx.fillStyle = 'rgba(0%, 100%, 0%, 0.499)';
+ ctx.fillRect(0, 0, 1, 1);
+ //FIXME: currently we only return premultipled pixels
+ verify(Helper.comparePixel(ctx, 0,0, 0,127,0,255));
+ //verify(Helper.comparePixel(ctx, 0,0, 0,255,0,127));
+ }
+
+ function test_hsla() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ ctx.fillStyle = "hsla(120, 100%, 50%, 0.499)";
+ ctx.fillRect(0, 0, 1, 1);
+ verify(Helper.comparePixel(ctx,0,0,0,127,0,255));
+ }
+
+ }
+}
diff --git a/tests/auto/declarative/qsgcanvasitem/data/tst_fillrect.qml b/tests/auto/declarative/qsgcanvasitem/data/tst_fillrect.qml
new file mode 100644
index 0000000000..07ddc59a07
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvasitem/data/tst_fillrect.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+import QtTest 1.0
+
+Canvas {
+ id:canvas; width:1;height:1
+ onPaint: {
+ context.fillStyle = "red";
+ context.fillRect(0, 0, canvas.width, canvas.height);
+ }
+ TestCase {
+ name: "FillRect"; when: windowShown
+ function test_fillRect() {
+ var ctx = canvas.getContext('2d');
+ var imageData = ctx.getImageData(0, 0, 1, 1);
+ var d = imageData.data;
+ verify(d.length == 4);
+ verify(d[0] == 255);
+ verify(d[1] == 0);
+ verify(d[2] == 0);
+ verify(d[3] == 255);
+ }
+ }
+}
diff --git a/tests/auto/declarative/qsgcanvasitem/data/tst_strokeStyle.qml b/tests/auto/declarative/qsgcanvasitem/data/tst_strokeStyle.qml
new file mode 100644
index 0000000000..84f830d636
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvasitem/data/tst_strokeStyle.qml
@@ -0,0 +1,48 @@
+import QtQuick 2.0
+import QtTest 1.0
+import "testhelper.js" as Helper
+
+Canvas {
+ id:canvas; width:1;height:1
+ TestCase {
+ name: "strokeStyle"; when: windowShown
+ function test_default() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ compare(ctx.strokeStyle, "#000000")
+ ctx.clearRect(0, 0, 1, 1);
+ compare(ctx.strokeStyle, "#000000")
+ }
+ function test_saverestore() {
+ var ctx = canvas.getContext('2d');
+ var old = ctx.strokeStyle;
+ ctx.save();
+ ctx.strokeStyle = "#ffaaff";
+ ctx.restore();
+ compare(ctx.strokeStyle, old);
+
+ ctx.strokeStyle = "#ffcc88";
+ old = ctx.strokeStyle;
+ ctx.save();
+ compare(ctx.strokeStyle, old);
+ ctx.restore();
+ }
+ function test_namedColor() {
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ ctx.strokeStyle = "red";
+ ctx.strokeRect(0,0,1,1);
+ verify(Helper.comparePixel(ctx,0,0,255,0,0,255));
+
+ ctx.strokeStyle = "black";
+ ctx.strokeRect(0,0,1,1);
+ verify(Helper.comparePixel(ctx,0,0,0,0,0,255));
+
+ ctx.strokeStyle = "white";
+ ctx.strokeRect(0,0,1,1);
+ verify(Helper.comparePixel(ctx,0,0,255,255,255,255));
+ }
+
+
+ }
+}
diff --git a/tests/auto/declarative/qsgcanvasitem/qsgcanvasitem.pro b/tests/auto/declarative/qsgcanvasitem/qsgcanvasitem.pro
new file mode 100644
index 0000000000..b22c49f379
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvasitem/qsgcanvasitem.pro
@@ -0,0 +1,5 @@
+QT += core-private gui-private declarative-private widgets
+TE=app
+TARGET=tst_qsgcanvasitem
+CONFIG += warn_on qmltestcase
+SOURCES += tst_qsgcanvasitem.cpp \ No newline at end of file
diff --git a/tests/auto/declarative/qsgcanvasitem/tst_qsgcanvasitem.cpp b/tests/auto/declarative/qsgcanvasitem/tst_qsgcanvasitem.cpp
new file mode 100644
index 0000000000..680e45238e
--- /dev/null
+++ b/tests/auto/declarative/qsgcanvasitem/tst_qsgcanvasitem.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtQuickTest/quicktest.h>
+QUICK_TEST_MAIN(qsgcanvasitem)