#include <qqmlengine.h>
#include <private/qv8domerrors_p.h>
#include <QtCore/qnumeric.h>
+#include <private/qquickwindow_p.h>
+#include <private/qquickwindowmanager_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
#ifdef Q_OS_QNX
#include <ctype.h>
/*!
\qmlclass Context2D QQuickContext2D
\inqmlmodule QtQuick 2
+ \ingroup qtquick-canvas
\since QtQuick 2.0
- \brief The Context2D API allows you to draw 2d graphic shapes on the \c
- Canvas item.
+ \brief Provides 2D context for shapes on a Canvas item
The Context2D object can be created by \c Canvas item's \c getContext()
method:
QFont font;
// ### this is simplified and incomplete
// ### TODO:get code from Qt webkit
- QStringList tokens = fontString.split(QLatin1String(" "));
+ const QStringList tokens = fontString.split(QLatin1Char(' '));
foreach (const QString &token, tokens) {
if (token == QLatin1String("italic"))
font.setItalic(true);
{
V8_RESOURCE_TYPE(Context2DType)
public:
- QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e) {}
+ QV8Context2DResource(QV8Engine *e) : QV8ObjectResource(e), context(0) {}
QQuickContext2D* context;
};
if (!qIsFinite(x0)
|| !qIsFinite(y0)
|| !qIsFinite(x1)
- || !qIsFinite(y1))
+ || !qIsFinite(y1)) {
+ delete r;
V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
+ }
r->brush = QLinearGradient(x0, y0, x1, y1);
gradient->SetExternalResource(r);
|| !qIsFinite(x1)
|| !qIsFinite(r0)
|| !qIsFinite(r1)
- || !qIsFinite(y1))
+ || !qIsFinite(y1)) {
+ delete r;
V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
+ }
if (r0 < 0 || r1 < 0)
V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
qreal x = args[0]->NumberValue();
qreal y = args[1]->NumberValue();
qreal angle = DEGREES(args[2]->NumberValue());
- if (!qIsFinite(x) || !qIsFinite(y))
+ if (!qIsFinite(x) || !qIsFinite(y)) {
+ delete r;
V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
+ }
- if (!qIsFinite(angle))
+ if (!qIsFinite(angle)) {
+ delete r;
V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
+ }
r->brush = QConicalGradient(x, y, angle);
gradient->SetExternalResource(r);
patternTexture = pixelData->image;
}
} else {
- patternTexture = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
+ patternTexture = r->context->createPixmap(QUrl(engine->toString(args[0]->ToString())))->image();
}
if (!patternTexture.isNull()) {
else if (lineJoin == QLatin1String("bevel"))
join = Qt::BevelJoin;
else if (lineJoin == QLatin1String("miter"))
- join = Qt::MiterJoin;
+ join = Qt::SvgMiterJoin;
else
return;
\qmlmethod object QtQuick2::Context2D::arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise)
Adds an arc to the current subpath that lies on the circumference of the circle whose center is at the point (\c x,\cy) and whose radius is \c radius.
\image qml-item-canvas-arcTo2.png
- \sa QtQuick2::Context2D::arcTo
- See {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
+ \sa QtQuick2::Context2D::arcTo,
+ {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C 2d context standard for arc}
*/
static v8::Handle<v8::Value> ctx2d_arc(const v8::Arguments &args)
{
\image qml-item-canvas-startAngle.png
The anticlockwise has the value TRUE for each arc in the figure above because they are all drawn in the counterclockwise direction.
- \sa QtQuick2::Context2D::arc
- \sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d context standard for arcTo}
+ \sa QtQuick2::Context2D::arc, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C 2d
+ context standard for arcTo}
*/
static v8::Handle<v8::Value> ctx2d_arcTo(const v8::Arguments &args)
{
static v8::Handle<v8::Value> ctx2d_drawFocusRing(const v8::Arguments &args)
{
+ Q_UNUSED(args);
+
V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
- return args.This();
}
static v8::Handle<v8::Value> ctx2d_setCaretSelectionRect(const v8::Arguments &args)
{
+ Q_UNUSED(args);
+
V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
- return args.This();
}
static v8::Handle<v8::Value> ctx2d_caretBlinkRate(const v8::Arguments &args)
{
+ Q_UNUSED(args);
+
V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
- return args.This();
}
// text
/*!
return args.This();
}
/*!
- \qmlclass QtQuick2::TextMetrics
+ \qmlclass TextMetrics
\inqmlmodule QtQuick 2
\since QtQuick 2.0
- \brief The Context2D TextMetrics interface.
+ \ingroup qtquick-canvas
+ \brief Provides a Context2D TextMetrics interface
+
The TextMetrics object can be created by QtQuick2::Context2D::measureText method.
See {http://www.w3.org/TR/2dcontext/#textmetrics}{W3C 2d context TexMetrics} for more details.
/*!
\qmlmethod QtQuick2::Context2D::drawImage(variant image, real sx, real sy, real sw, sh, real dx, real dy, real dw, dh)
This is an overloaded function.
- Draws the given item as \a image from source point (\a sx, \a sy) and source width \sw, source height \sh
+ Draws the given item as \a image from source point (\a sx, \a sy) and source width \a sw, source height \a sh
onto the canvas at point (\a dx, \a dy) and with width \a dw, height \a dh.
if (!r->context->state.invertibleCTM)
return args.This();
- QImage image;
+ QQmlRefPointer<QQuickCanvasPixmap> pixmap;
+
if (args[0]->IsString()) {
QUrl url(engine->toString(args[0]->ToString()));
if (!url.isValid())
V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
- image = r->context->createImage(url);
+ pixmap = r->context->createPixmap(url);
} else if (args[0]->IsObject()) {
QQuickImage *imageItem = qobject_cast<QQuickImage*>(engine->toQObject(args[0]->ToObject()));
QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(engine->toQObject(args[0]->ToObject()));
QV8Context2DPixelArrayResource *pix = v8_resource_cast<QV8Context2DPixelArrayResource>(args[0]->ToObject()->GetInternalField(0)->ToObject());
- if (pix) {
- image = pix->image;
+ if (pix && !pix->image.isNull()) {
+ pixmap.take(new QQuickCanvasPixmap(pix->image, r->context->canvas()->window()));
} else if (imageItem) {
- image = imageItem->image();
+ pixmap.take(r->context->createPixmap(imageItem->source()));
} else if (canvas) {
- image = canvas->toImage();
+ QImage img = canvas->toImage();
+ if (!img.isNull())
+ pixmap.take(new QQuickCanvasPixmap(img, canvas->window()));
} else {
V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
V8THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
+
+ if (pixmap.isNull() || !pixmap->isValid())
+ return args.This();
+
if (args.Length() == 3) {
dx = args[1]->NumberValue();
dy = args[2]->NumberValue();
sx = 0;
sy = 0;
- sw = image.width();
- sh = image.height();
+ sw = pixmap->width();
+ sh = pixmap->height();
dw = sw;
dh = sh;
} else if (args.Length() == 5) {
sx = 0;
sy = 0;
- sw = image.width();
- sh = image.height();
+ sw = pixmap->width();
+ sh = pixmap->height();
dx = args[1]->NumberValue();
dy = args[2]->NumberValue();
dw = args[3]->NumberValue();
|| !qIsFinite(dh))
return args.This();
- if (!image.isNull()) {
- if (sx < 0 || sy < 0 || sw == 0 || sh == 0
- || sx + sw > image.width() || sy + sh > image.height()
- || sx + sw < 0 || sy + sh < 0) {
+ if (sx < 0
+ || sy < 0
+ || sw == 0
+ || sh == 0
+ || sx + sw > pixmap->width()
+ || sy + sh > pixmap->height()
+ || sx + sw < 0 || sy + sh < 0) {
V8THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
- }
-
- r->context->buffer()->drawImage(image,sx, sy, sw, sh, dx, dy, dw, dh);
}
+ r->context->buffer()->drawPixmap(pixmap, QRectF(sx, sy, sw, sh), QRectF(dx, dy, dw, dh));
+
return args.This();
}
// pixel manipulation
/*!
- \qmlclass QtQuick2::CanvasImageData
+ \qmlclass CanvasImageData
+ \inqmlmodule QtQuick 2
+ \ingroup qtquick-canvas
+ \brief Contains image pixel data in RGBA order
+
The \a QtQuick2::CanvasImageData object holds the image pixel data.
The \a QtQuick2::CanvasImageData object has the actual dimensions of the data stored in
}
/*!
- \qmlclass QtQuick2::CanvasPixelArray
+ \qmlclass CanvasPixelArray
+ \inqmlmodule QtQuick 2
+ \ingroup qtquick-canvas
+ \brief Provides ordered and indexed access to the components of each pixel in image data
+
The CanvasPixelArray object provides ordered, indexed access to the color components of each pixel of the image data.
The CanvasPixelArray can be accessed as normal Javascript array.
\sa QtQuick2::CanvasImageData
return qt_create_image_data(w, h, engine, QImage());
}
} else if (args[0]->IsString()) {
- QImage image = r->context->createImage(QUrl(engine->toString(args[0]->ToString())));
+ QImage image = r->context->createPixmap(QUrl(engine->toString(args[0]->ToString())))->image();
return qt_create_image_data(image.width(), image.height(), engine, image);
}
} else if (args.Length() == 2) {
}
QImage image = pixelArray->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
- r->context->buffer()->drawImage(image, dirtyX, dirtyY, dirtyWidth, dirtyHeight, dx, dy, dirtyWidth, dirtyHeight);
+ r->context->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight));
}
return args.This();
}
/*!
- \qmlclass QtQuick2::CanvasGradient
+ \qmlclass CanvasGradient
\inqmlmodule QtQuick 2
\since QtQuick 2.0
- \brief The Context2D opaque CanvasGradient interface.
+ \ingroup qtquick-canvas
+ \brief Provides an opaque CanvasGradient interface
*/
/*!
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
return;
- buffer()->fillRect(x, y, w, h);
+ buffer()->fillRect(QRectF(x, y, w, h));
}
void QQuickContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
return;
- buffer()->strokeRect(x, y, w, h);
+ buffer()->strokeRect(QRectF(x, y, w, h));
}
void QQuickContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
return;
- buffer()->clearRect(x, y, w, h);
+ buffer()->clearRect(QRectF(x, y, w, h));
}
void QQuickContext2D::drawText(const QString& text, qreal x, qreal y, bool fill)
}
-QImage QQuickContext2D::createImage(const QUrl& url)
+QQmlRefPointer<QQuickCanvasPixmap> QQuickContext2D::createPixmap(const QUrl& url)
{
- return m_canvas->loadedImage(url);
+ return m_canvas->loadedPixmap(url);
}
QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString& text)
: QQuickCanvasContext(parent)
, m_buffer(new QQuickContext2DCommandBuffer)
, m_v8engine(0)
+ , m_windowManager(0)
+ , m_surface(0)
+ , m_glContext(0)
{
}
m_canvas = canvasItem;
m_renderTarget = canvasItem->renderTarget();
- // For the FBO target we only (currently) support Cooperative
- if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
- canvasItem->setRenderStrategy(QQuickCanvasItem::Cooperative);
- }
-
+ QQuickWindow *window = canvasItem->window();
+ m_windowManager = QQuickWindowPrivate::get(window)->windowManager;
m_renderStrategy = canvasItem->renderStrategy();
switch (m_renderTarget) {
m_texture = new QQuickContext2DImageTexture(m_renderStrategy == QQuickCanvasItem::Threaded);
break;
case QQuickCanvasItem::FramebufferObject:
+ {
m_texture = new QQuickContext2DFBOTexture;
+ // No BufferQueueingOpenGL, falls back to Cooperative mode
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL))
+ m_renderStrategy = QQuickCanvasItem::Cooperative;
+ }
break;
}
m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
m_texture->setSmooth(canvasItem->smooth());
+ QThread *renderThread = QThread::currentThread();
+ QThread *sceneGraphThread = window->openglContext() ? window->openglContext()->thread() : 0;
+
+ if (m_renderStrategy == QQuickCanvasItem::Threaded)
+ renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem));
+ else if (m_renderStrategy == QQuickCanvasItem::Cooperative)
+ renderThread = sceneGraphThread;
+
+ if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) {
+ QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->glContext();
+ m_surface = window;
+ m_glContext = new QOpenGLContext;
+ m_glContext->setFormat(cc->format());
+ m_glContext->setShareContext(cc);
+ if (renderThread != QThread::currentThread())
+ m_glContext->moveToThread(renderThread);
+ }
+
connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
reset();
m_stateStack.clear();
m_stateStack.push(newState);
popState();
- m_buffer->clearRect(0, 0, m_canvas->width(), m_canvas->height());
+ m_buffer->clearRect(QRectF(0, 0, m_canvas->width(), m_canvas->height()));
}
void QQuickContext2D::setV8Engine(QV8Engine *engine)