aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/context2d
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/context2d')
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp38
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp146
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h3
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp206
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp1
5 files changed, 232 insertions, 162 deletions
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index e7546535a1..9c4cef1fe1 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -175,7 +175,6 @@ public:
uint hasTileSize :1;
uint hasCanvasWindow :1;
uint available :1;
- uint contextInitialized :1;
QQuickCanvasItem::RenderTarget renderTarget;
QQuickCanvasItem::RenderStrategy renderStrategy;
QString contextType;
@@ -193,7 +192,6 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
, hasTileSize(false)
, hasCanvasWindow(false)
, available(false)
- , contextInitialized(false)
, renderTarget(QQuickCanvasItem::Image)
, renderStrategy(QQuickCanvasItem::Cooperative)
{
@@ -272,7 +270,7 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
requires the pixel data to be exchanged between the system memory and the
graphic card, which is significantly more expensive. Rendering may also be
synchronized with the V-sync signal (to avoid
- \l{en.wikipedia.org/wiki/Screen_tearing}{screen tearing}) which will further
+ \l{http://en.wikipedia.org/wiki/Screen_tearing}{screen tearing}) which will further
impact pixel operations with \c Canvas.FrambufferObject render target.
\section1 Tips for Porting Existing HTML5 Canvas applications
@@ -343,7 +341,7 @@ void QQuickCanvasItem::setContextType(const QString &contextType)
if (contextType.compare(d->contextType, Qt::CaseInsensitive) == 0)
return;
- if (d->contextInitialized) {
+ if (d->context) {
qmlInfo(this) << "Canvas already initialized with a different context type";
return;
}
@@ -368,7 +366,7 @@ void QQuickCanvasItem::setContextType(const QString &contextType)
QQmlV4Handle QQuickCanvasItem::context() const
{
Q_D(const QQuickCanvasItem);
- if (d->contextInitialized)
+ if (d->context)
return QQmlV4Handle(d->context->v4value());
return QQmlV4Handle(QV4::Value::nullValue());
@@ -402,7 +400,7 @@ void QQuickCanvasItem::setCanvasSize(const QSizeF & size)
d->canvasSize = size;
emit canvasSizeChanged();
- if (d->contextInitialized)
+ if (d->context)
polish();
}
}
@@ -437,7 +435,7 @@ void QQuickCanvasItem::setTileSize(const QSize & size)
emit tileSizeChanged();
- if (d->contextInitialized)
+ if (d->context)
polish();
}
}
@@ -470,7 +468,7 @@ void QQuickCanvasItem::setCanvasWindow(const QRectF& rect)
d->hasCanvasWindow = true;
emit canvasWindowChanged();
- if (d->contextInitialized)
+ if (d->context)
polish();
}
}
@@ -502,7 +500,7 @@ void QQuickCanvasItem::setRenderTarget(QQuickCanvasItem::RenderTarget target)
{
Q_D(QQuickCanvasItem);
if (d->renderTarget != target) {
- if (d->contextInitialized) {
+ if (d->context) {
qmlInfo(this) << "Canvas:renderTarget not changeble once context is active.";
return;
}
@@ -546,7 +544,7 @@ void QQuickCanvasItem::setRenderStrategy(QQuickCanvasItem::RenderStrategy strate
{
Q_D(QQuickCanvasItem);
if (d->renderStrategy != strategy) {
- if (d->contextInitialized) {
+ if (d->context) {
qmlInfo(this) << "Canvas:renderStrategy not changeable once context is active.";
return;
}
@@ -651,7 +649,7 @@ void QQuickCanvasItem::updatePolish()
Q_D(QQuickCanvasItem);
- if (d->contextInitialized)
+ if (d->context && d->renderStrategy != QQuickCanvasItem::Cooperative)
d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth, d->antialiasing);
if (d->animationCallbacks.size() > 0 && isVisible()) {
@@ -676,7 +674,7 @@ void QQuickCanvasItem::updatePolish()
}
}
- if (d->contextInitialized) {
+ if (d->context) {
if (d->renderStrategy == QQuickCanvasItem::Cooperative)
update();
else
@@ -688,8 +686,10 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
{
Q_D(QQuickCanvasItem);
- if (!d->contextInitialized)
+ if (!d->context || d->canvasWindow.size().isEmpty()) {
+ delete oldNode;
return 0;
+ }
QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode*>(oldNode);
if (!node)
@@ -700,10 +700,13 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
else
node->setFiltering(QSGTexture::Nearest);
- if (d->renderStrategy == QQuickCanvasItem::Cooperative)
+ if (d->renderStrategy == QQuickCanvasItem::Cooperative) {
+ d->context->prepare(d->canvasSize.toSize(), d->tileSize, d->canvasWindow.toRect(), d->dirtyRect.toRect(), d->smooth, d->antialiasing);
d->context->flush();
+ }
node->setTexture(d->context->texture());
+ node->markDirty(QSGNode::DirtyMaterial);
node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
return node;
}
@@ -763,7 +766,7 @@ void QQuickCanvasItem::getContext(QQmlV4Function *args)
/*!
\qmlmethod long QtQuick2::Canvas::requestAnimationFrame(callback)
- This function schedules callback to be invoked before composing the QtQuick
+ This function schedules callback to be invoked before composing the Qt Quick
scene.
*/
@@ -970,7 +973,7 @@ bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const
QImage QQuickCanvasItem::toImage(const QRectF& rect) const
{
Q_D(const QQuickCanvasItem);
- if (d->contextInitialized) {
+ if (d->context) {
if (rect.isEmpty())
return d->context->toImage(canvasWindow());
else
@@ -1026,7 +1029,7 @@ void QQuickCanvasItem::delayedCreate()
{
Q_D(QQuickCanvasItem);
- if (!d->contextInitialized && !d->contextType.isNull())
+ if (!d->context && !d->contextType.isNull())
createContext(d->contextType);
requestPaint();
@@ -1055,7 +1058,6 @@ void QQuickCanvasItem::initializeContext(QQuickCanvasContext *context, const QVa
d->context = context;
d->context->init(this, args);
d->context->setV8Engine(QQmlEnginePrivate::getV8Engine(qmlEngine(this)));
- d->contextInitialized = true;
connect(d->context, SIGNAL(textureChanged()), SLOT(update()));
connect(d->context, SIGNAL(textureChanged()), SIGNAL(painted()));
emit contextChanged();
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 5011fd45f2..c9ee426565 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -210,9 +210,11 @@ QFont qt_font_from_string(const QString& fontString) {
font.setBold(true);
else if (token.endsWith(QStringLiteral("px"))) {
QString number = token;
- number.remove(QStringLiteral("px"));
- //font.setPointSizeF(number.trimmed().toFloat());
- font.setPixelSize(number.trimmed().toInt());
+ number.remove(QLatin1String("px"));
+ bool ok = false;
+ float pixelSize = number.trimmed().toFloat(&ok);
+ if (ok)
+ font.setPixelSize(int(pixelSize));
} else
font.setFamily(token);
}
@@ -426,50 +428,86 @@ DEFINE_MANAGED_VTABLE(QQuickContext2DStyle);
QImage qt_image_convolute_filter(const QImage& src, const QVector<qreal>& weights, int radius = 0)
{
- int sides = radius ? radius : qRound(qSqrt(weights.size()));
- int half = qFloor(sides/2);
+ // weights 3x3 => delta 1
+ int delta = radius ? radius : qFloor(qSqrt(weights.size()) / qreal(2));
+ int filterDim = 2 * delta + 1;
QImage dst = QImage(src.size(), src.format());
+
int w = src.width();
int h = src.height();
- for (int y = 0; y < dst.height(); ++y) {
- QRgb *dr = (QRgb*)dst.scanLine(y);
- for (int x = 0; x < dst.width(); ++x) {
- unsigned char* dRgb = ((unsigned char*)&dr[x]);
- unsigned char red=0, green=0, blue=0, alpha=0;
- int sy = y;
- int sx = x;
-
- for (int cy=0; cy<sides; cy++) {
- for (int cx=0; cx<sides; cx++) {
- int scy = sy + cy - half;
- int scx = sx + cx - half;
- if (scy >= 0 && scy < w && scx >= 0 && scx < h) {
- const QRgb *sr = (const QRgb*)(src.constScanLine(scy));
- const unsigned char* sRgb = ((const unsigned char*)&sr[scx]);
- qreal wt = radius ? weights[0] : weights[cy*sides+cx];
- red += sRgb[0] * wt;
- green += sRgb[1] * wt;
- blue += sRgb[2] * wt;
- alpha += sRgb[3] * wt;
- }
- }
- }
- dRgb[0] = red;
- dRgb[1] = green;
- dRgb[2] = blue;
- dRgb[3] = alpha;
- }
+
+ const QRgb *sr = (const QRgb *)(src.constBits());
+ int srcStride = src.bytesPerLine() / 4;
+
+ QRgb *dr = (QRgb*)dst.bits();
+ int dstStride = dst.bytesPerLine() / 4;
+
+ for (int y = 0; y < h; ++y) {
+ for (int x = 0; x < w; ++x) {
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+ int alpha = 0;
+
+ qreal redF = 0;
+ qreal greenF = 0;
+ qreal blueF = 0;
+ qreal alphaF = 0;
+
+ int sy = y;
+ int sx = x;
+
+ for (int cy = 0; cy < filterDim; ++cy) {
+ int scy = sy + cy - delta;
+
+ if (scy < 0 || scy >= h)
+ continue;
+
+ const QRgb *sry = sr + scy * srcStride;
+
+ for (int cx = 0; cx < filterDim; ++cx) {
+ int scx = sx + cx - delta;
+
+ if (scx < 0 || scx >= w)
+ continue;
+
+ const QRgb col = sry[scx];
+
+ if (radius) {
+ red += qRed(col);
+ green += qGreen(col);
+ blue += qBlue(col);
+ alpha += qAlpha(col);
+ } else {
+ qreal wt = weights[cy * filterDim + cx];
+
+ redF += qRed(col) * wt;
+ greenF += qGreen(col) * wt;
+ blueF += qBlue(col) * wt;
+ alphaF += qAlpha(col) * wt;
+ }
+ }
+ }
+
+ if (radius)
+ dr[x] = qRgba(qRound(red * weights[0]), qRound(green * weights[0]), qRound(blue * weights[0]), qRound(alpha * weights[0]));
+ else
+ dr[x] = qRgba(qRound(redF), qRound(greenF), qRound(blueF), qRound(alphaF));
+ }
+
+ dr += dstStride;
}
+
return dst;
}
void qt_image_boxblur(QImage& image, int radius, bool quality)
{
int passes = quality? 3: 1;
- for (int i=0; i < passes; i++) {
- image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0/(radius * radius * 1.0), radius);
- }
+ int filterSize = 2 * radius + 1;
+ for (int i = 0; i < passes; ++i)
+ image = qt_image_convolute_filter(image, QVector<qreal>() << 1.0 / (filterSize * filterSize), radius);
}
static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator)
@@ -644,7 +682,7 @@ static QV4::Value qt_create_image_data(qreal w, qreal h, QV8Engine* engine, cons
pixelData->image = QImage(w, h, QImage::Format_ARGB32);
pixelData->image.fill(0x00000000);
} else {
- Q_ASSERT(image.width() == w && image.height() == h);
+ Q_ASSERT(image.width() == int(w) && image.height() == int(h));
pixelData->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
@@ -2525,7 +2563,11 @@ QV4::Value QQuickJSContext2DPrototype::method_drawImage(QV4::SimpleCallContext *
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
+ QUrl url(ctx->arguments[0].toQString());
+ if (url.isValid())
+ pixmap = r->context->createPixmap(url);
+ else
+ V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
@@ -2790,7 +2832,7 @@ QV4::Value QQuickJSContext2DPrototype::method_createImageData(QV4::SimpleCallCon
}
/*!
- \qmlmethod CanvasImageData QtQuick2::Canvas::getImageData(real sx, real sy, real sw, real sh)
+ \qmlmethod CanvasImageData QtQuick2::Context2D::getImageData(real sx, real sy, real sw, real sh)
Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
*/
QV4::Value QQuickJSContext2DPrototype::method_getImageData(QV4::SimpleCallContext *ctx)
@@ -3488,7 +3530,6 @@ QPainterPath QQuickContext2D::createTextGlyphs(qreal x, qreal y, const QString&
QPainterPath textPath;
textPath.addText(x - xoffset, y - yoffset+metrics.ascent(), state.font, text);
- textPath = state.matrix.map(textPath);
return textPath;
}
@@ -3662,7 +3703,7 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
if (m_texture->thread() == QThread::currentThread())
m_texture->grabImage(bounds);
else if (m_renderStrategy == QQuickCanvasItem::Cooperative) {
- qWarning() << "Pixel read back is not support in Cooperative mode, please try Theaded or Immediate mode";
+ qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode";
return QImage();
} else {
QMetaObject::invokeMethod(m_texture,
@@ -3775,7 +3816,6 @@ void QQuickContext2D::pushState()
void QQuickContext2D::reset()
{
QQuickContext2D::State newState;
- newState.matrix = QTransform();
m_path = QPainterPath();
@@ -3787,28 +3827,6 @@ void QQuickContext2D::reset()
newState.clipPath = defaultClipPath;
newState.clipPath.setFillRule(Qt::WindingFill);
- newState.strokeStyle = QColor("#000000");
- newState.fillStyle = QColor("#000000");
- newState.fillPatternRepeatX = false;
- newState.fillPatternRepeatY = false;
- newState.strokePatternRepeatX = false;
- newState.strokePatternRepeatY = false;
- newState.invertibleCTM = true;
- newState.fillRule = Qt::WindingFill;
- newState.globalAlpha = 1.0;
- newState.lineWidth = 1;
- newState.lineCap = Qt::FlatCap;
- newState.lineJoin = Qt::MiterJoin;
- newState.miterLimit = 10;
- newState.shadowOffsetX = 0;
- newState.shadowOffsetY = 0;
- newState.shadowBlur = 0;
- newState.shadowColor = qRgba(0, 0, 0, 0);
- newState.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
- newState.font = QFont(QStringLiteral("sans-serif"), 10);
- newState.textAlign = QQuickContext2D::Start;
- newState.textBaseline = QQuickContext2D::Alphabetic;
-
m_stateStack.clear();
m_stateStack.push(newState);
popState();
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 0fe8bc6db2..8164108bd3 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -131,10 +131,11 @@ public:
, shadowBlur(0)
, shadowColor(qRgba(0, 0, 0, 0))
, globalCompositeOperation(QPainter::CompositionMode_SourceOver)
- , font(QFont(QLatin1String("sans-serif"), 10))
+ , font(QFont(QLatin1String("sans-serif")))
, textAlign(QQuickContext2D::Start)
, textBaseline(QQuickContext2D::Alphabetic)
{
+ font.setPixelSize(10);
}
QTransform matrix;
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index 7c5841810b..d433efcb69 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -54,86 +54,136 @@ QT_BEGIN_NAMESPACE
void qt_image_boxblur(QImage& image, int radius, bool quality);
-static QImage makeShadowImage(const QImage& image, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
-{
- QImage shadowImg(image.width() + blur + qAbs(offsetX),
- image.height() + blur + qAbs(offsetY),
- QImage::Format_ARGB32_Premultiplied);
- shadowImg.fill(0);
- QPainter tmpPainter(&shadowImg);
- tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
- qreal shadowX = offsetX > 0? offsetX : 0;
- qreal shadowY = offsetY > 0? offsetY : 0;
-
- tmpPainter.drawImage(shadowX, shadowY, image);
- tmpPainter.end();
-
- if (blur > 0)
- qt_image_boxblur(shadowImg, blur/2, true);
-
- // blacken the image with shadow color...
- tmpPainter.begin(&shadowImg);
- tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
- tmpPainter.fillRect(shadowImg.rect(), color);
- tmpPainter.end();
- return shadowImg;
-}
+namespace {
+ class ShadowImageMaker
+ {
+ public:
+ virtual ~ShadowImageMaker() {}
-static void fillRectShadow(QPainter* p, QRectF shadowRect, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
-{
- QRectF r = shadowRect;
- r.moveTo(0, 0);
+ void paintShapeAndShadow(QPainter *p, qreal offsetX, qreal offsetY, qreal blur, const QColor &color)
+ {
+ QRectF bounds = boundingRect().translated(offsetX, offsetY).adjusted(-2*blur, -2*blur, 2*blur, 2*blur);
+ QRect boundsAligned = bounds.toAlignedRect();
+
+ QImage shadowImage(boundsAligned.size(), QImage::Format_ARGB32_Premultiplied);
+ shadowImage.fill(0);
+
+ QPainter shadowPainter(&shadowImage);
+ shadowPainter.setRenderHints(p->renderHints());
+ shadowPainter.translate(offsetX - boundsAligned.left(), offsetY - boundsAligned.top());
+ paint(&shadowPainter);
+ shadowPainter.end();
+
+ if (blur > 0)
+ qt_image_boxblur(shadowImage, qMax(1, qRound(blur / 2)), true);
+
+ // blacken the image with shadow color...
+ shadowPainter.begin(&shadowImage);
+ shadowPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ shadowPainter.fillRect(shadowImage.rect(), color);
+ shadowPainter.end();
+
+ p->drawImage(boundsAligned.topLeft(), shadowImage);
+ paint(p);
+ }
- QImage shadowImage(r.size().width() + 1, r.size().height() + 1, QImage::Format_ARGB32_Premultiplied);
- QPainter tp;
- tp.begin(&shadowImage);
- tp.fillRect(r, p->brush());
- tp.end();
- shadowImage = makeShadowImage(shadowImage, offsetX, offsetY, blur, color);
+ virtual void paint(QPainter *p) const = 0;
+ virtual QRectF boundingRect() const = 0;
+ };
- qreal dx = shadowRect.left() + (offsetX < 0? offsetX:0);
- qreal dy = shadowRect.top() + (offsetY < 0? offsetY:0);
+ class FillRectShadow : public ShadowImageMaker
+ {
+ public:
+ FillRectShadow(const QRectF &rect, const QBrush &brush)
+ : m_rect(rect.normalized())
+ , m_brush(brush)
+ {
+ }
+
+ void paint(QPainter *p) const { p->fillRect(m_rect, m_brush); }
+ QRectF boundingRect() const { return m_rect; }
- p->drawImage(dx, dy, shadowImage);
- p->fillRect(shadowRect, p->brush());
+ private:
+ QRectF m_rect;
+ QBrush m_brush;
+ };
+
+ class FillPathShadow : public ShadowImageMaker
+ {
+ public:
+ FillPathShadow(const QPainterPath &path, const QBrush &brush)
+ : m_path(path)
+ , m_brush(brush)
+ {
+ }
+
+ void paint(QPainter *p) const { p->fillPath(m_path, m_brush); }
+ QRectF boundingRect() const { return m_path.boundingRect(); }
+
+ private:
+ QPainterPath m_path;
+ QBrush m_brush;
+ };
+
+ class StrokePathShadow : public ShadowImageMaker
+ {
+ public:
+ StrokePathShadow(const QPainterPath &path, const QPen &pen)
+ : m_path(path)
+ , m_pen(pen)
+ {
+ }
+
+ void paint(QPainter *p) const { p->strokePath(m_path, m_pen); }
+
+ QRectF boundingRect() const
+ {
+ qreal d = qMax(qreal(1), m_pen.widthF());
+ return m_path.boundingRect().adjusted(-d, -d, d, d);
+ }
+
+ private:
+ QPainterPath m_path;
+ QPen m_pen;
+ };
+
+ class DrawImageShadow : public ShadowImageMaker
+ {
+ public:
+ DrawImageShadow(const QImage &image, const QPointF &offset)
+ : m_image(image)
+ , m_offset(offset)
+ {
+ }
+
+ void paint(QPainter *p) const { p->drawImage(m_offset, m_image); }
+
+ QRectF boundingRect() const { return QRectF(m_image.rect()).translated(m_offset); }
+
+ private:
+ QImage m_image;
+ QPointF m_offset;
+ };
+}
+
+static void fillRectShadow(QPainter* p, QRectF shadowRect, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
+{
+ FillRectShadow shadowMaker(shadowRect, p->brush());
+ shadowMaker.paintShapeAndShadow(p, offsetX, offsetY, blur, color);
}
static void fillShadowPath(QPainter* p, const QPainterPath& path, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
{
- QRectF r = path.boundingRect();
- QImage img(r.size().width() + r.left() + 1,
- r.size().height() + r.top() + 1,
- QImage::Format_ARGB32_Premultiplied);
- img.fill(0);
- QPainter tp(&img);
- tp.fillPath(path.translated(0, 0), p->brush());
- tp.end();
-
- QImage shadowImage = makeShadowImage(img, offsetX, offsetY, blur, color);
- qreal dx = r.left() + (offsetX < 0? offsetX:0);
- qreal dy = r.top() + (offsetY < 0? offsetY:0);
-
- p->drawImage(dx, dy, shadowImage);
- p->fillPath(path, p->brush());
+ FillPathShadow shadowMaker(path, p->brush());
+ shadowMaker.paintShapeAndShadow(p, offsetX, offsetY, blur, color);
}
static void strokeShadowPath(QPainter* p, const QPainterPath& path, qreal offsetX, qreal offsetY, qreal blur, const QColor& color)
{
- QRectF r = path.boundingRect();
- QImage img(r.size().width() + r.left() + 1,
- r.size().height() + r.top() + 1,
- QImage::Format_ARGB32_Premultiplied);
- img.fill(0);
- QPainter tp(&img);
- tp.strokePath(path, p->pen());
- tp.end();
-
- QImage shadowImage = makeShadowImage(img, offsetX, offsetY, blur, color);
- qreal dx = r.left() + (offsetX < 0? offsetX:0);
- qreal dy = r.top() + (offsetY < 0? offsetY:0);
- p->drawImage(dx, dy, shadowImage);
- p->strokePath(path, p->pen());
+ StrokePathShadow shadowMaker(path, p->pen());
+ shadowMaker.paintShapeAndShadow(p, offsetX, offsetY, blur, color);
}
+
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
@@ -259,15 +309,16 @@ static void qt_drawImage(QPainter *p, QQuickContext2D::State& state, QImage imag
if (sw != dw || sh != dh)
image = image.scaled(dw, dh);
- if (shadow) {
- QImage shadow = makeShadowImage(image, state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
- qreal shadow_dx = dx + (state.shadowOffsetX < 0? state.shadowOffsetY:0);
- qreal shadow_dy = dy + (state.shadowOffsetX < 0? state.shadowOffsetY:0);
- p->drawImage(shadow_dx, shadow_dy, shadow);
- }
//Strange OpenGL painting behavior here, without beginNativePainting/endNativePainting, only the first image is painted.
p->beginNativePainting();
- p->drawImage(dx, dy, image);
+
+ if (shadow) {
+ DrawImageShadow shadowMaker(image, QPointF(dx, dy));
+ shadowMaker.paintShapeAndShadow(p, state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
+ } else {
+ p->drawImage(dx, dy, image);
+ }
+
p->endNativePainting();
}
@@ -295,12 +346,9 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
case QQuickContext2D::ClearRect:
{
QPainter::CompositionMode cm = p->compositionMode();
- qreal alpha = p->opacity();
- p->setCompositionMode(QPainter::CompositionMode_Source);
- p->setOpacity(0);
- p->fillRect(takeRect(), QColor(qRgba(0, 0, 0, 0)));
+ p->setCompositionMode(QPainter::CompositionMode_Clear);
+ p->fillRect(takeRect(), Qt::white);
p->setCompositionMode(cm);
- p->setOpacity(alpha);
break;
}
case QQuickContext2D::FillRect:
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 729e32e564..84ab5bb8fb 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -586,6 +586,7 @@ QQuickCanvasItem::RenderTarget QQuickContext2DImageTexture::renderTarget() const
void QQuickContext2DImageTexture::bind()
{
imageTexture()->bind();
+ updateBindOptions();
}
bool QQuickContext2DImageTexture::updateTexture()