diff options
Diffstat (limited to 'src/quick/items/context2d')
-rw-r--r-- | src/quick/items/context2d/qquickcanvasitem.cpp | 38 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2d.cpp | 146 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2d_p.h | 3 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp | 206 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dtexture.cpp | 1 |
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() |