diff options
Diffstat (limited to 'src/openvg/qpaintengine_vg.cpp')
-rw-r--r-- | src/openvg/qpaintengine_vg.cpp | 126 |
1 files changed, 122 insertions, 4 deletions
diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index f0f198f..ebdfa5f 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -1024,9 +1024,11 @@ static VGImage toVGImage switch (img.format()) { case QImage::Format_Mono: img = image.convertToFormat(QImage::Format_MonoLSB, flags); + img.invertPixels(); format = VG_BW_1; break; case QImage::Format_MonoLSB: + img.invertPixels(); format = VG_BW_1; break; case QImage::Format_RGB32: @@ -2333,6 +2335,7 @@ bool QVGPaintEngine::isDefaultClipRect(const QRect& rect) void QVGPaintEngine::clipEnabledChanged() { #if defined(QVG_SCISSOR_CLIP) + vgSeti(VG_MASKING, VG_FALSE); // disable mask fallback updateScissor(); #else Q_D(QVGPaintEngine); @@ -3070,6 +3073,95 @@ static void drawVGImage(QVGPaintEnginePrivate *d, vgDrawImage(vgImg); } +static void drawImageTiled(QVGPaintEnginePrivate *d, + const QRectF &r, + const QImage &image, + const QRectF &sr = QRectF()) +{ + const int minTileSize = 16; + int tileWidth = 512; + int tileHeight = tileWidth; + + VGImageFormat tileFormat = qt_vg_image_to_vg_format(image.format()); + VGImage tile = VG_INVALID_HANDLE; + QVGImagePool *pool = QVGImagePool::instance(); + while (tile == VG_INVALID_HANDLE && tileWidth >= minTileSize) { + tile = pool->createPermanentImage(tileFormat, tileWidth, tileHeight, + VG_IMAGE_QUALITY_FASTER); + if (tile == VG_INVALID_HANDLE) { + tileWidth /= 2; + tileHeight /= 2; + } + } + if (tile == VG_INVALID_HANDLE) { + qWarning("drawImageTiled: Failed to create %dx%d tile, giving up", tileWidth, tileHeight); + return; + } + + VGfloat opacityMatrix[20] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, d->opacity, + 0.0f, 0.0f, 0.0f, 0.0f + }; + VGImage tileWithOpacity = VG_INVALID_HANDLE; + if (d->opacity != 1) { + tileWithOpacity = pool->createPermanentImage(VG_sARGB_8888_PRE, + tileWidth, tileHeight, VG_IMAGE_QUALITY_FASTER); + if (tileWithOpacity == VG_INVALID_HANDLE) + qWarning("drawImageTiled: Failed to create extra tile, ignoring opacity"); + } + + QRect sourceRect = sr.toRect(); + if (sourceRect.isNull()) + sourceRect = QRect(0, 0, image.width(), image.height()); + + VGfloat scaleX = r.width() / sourceRect.width(); + VGfloat scaleY = r.height() / sourceRect.height(); + + d->setImageOptions(); + + for (int y = sourceRect.y(); y < sourceRect.height(); y += tileHeight) { + int h = qMin(tileHeight, sourceRect.height() - y); + if (h < 1) + break; + for (int x = sourceRect.x(); x < sourceRect.width(); x += tileWidth) { + int w = qMin(tileWidth, sourceRect.width() - x); + if (w < 1) + break; + + int bytesPerPixel = image.depth() / 8; + const uchar *sptr = image.constBits() + x * bytesPerPixel + y * image.bytesPerLine(); + vgImageSubData(tile, sptr, image.bytesPerLine(), tileFormat, 0, 0, w, h); + + QTransform transform(d->imageTransform); + transform.translate(r.x() + x, r.y() + y); + transform.scale(scaleX, scaleY); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + VGImage actualTile = tile; + if (tileWithOpacity != VG_INVALID_HANDLE) { + vgColorMatrix(tileWithOpacity, actualTile, opacityMatrix); + if (w < tileWidth || h < tileHeight) + actualTile = vgChildImage(tileWithOpacity, 0, 0, w, h); + else + actualTile = tileWithOpacity; + } else if (w < tileWidth || h < tileHeight) { + actualTile = vgChildImage(tile, 0, 0, w, h); + } + vgDrawImage(actualTile); + + if (actualTile != tile && actualTile != tileWithOpacity) + vgDestroyImage(actualTile); + } + } + + vgDestroyImage(tile); + if (tileWithOpacity != VG_INVALID_HANDLE) + vgDestroyImage(tileWithOpacity); +} + // Used by qpixmapfilter_vg.cpp to draw filtered VGImage's. void qt_vg_drawVGImage(QPainter *painter, const QPointF& pos, VGImage vgImg) { @@ -3099,6 +3191,19 @@ void qt_vg_drawVGImageStencil bool QVGPaintEngine::canVgWritePixels(const QImage &image) const { Q_D(const QVGPaintEngine); + + // qt_vg_image_to_vg_format returns VG_sARGB_8888 as + // fallback case if no matching VG format is found. + // If given image format is not Format_ARGB32 and returned + // format is VG_sARGB_8888, it means that no match was + // found. In that case vgWritePixels cannot be used. + // Also 1-bit formats cannot be used directly either. + if ((image.format() != QImage::Format_ARGB32 + && qt_vg_image_to_vg_format(image.format()) == VG_sARGB_8888) + || image.depth() == 1) { + return false; + } + // vgWritePixels ignores masking, blending and xforms so we can only use it if // ALL of the following conditions are true: // - It is a simple translate, or a scale of -1 on the y-axis (inverted) @@ -3169,7 +3274,7 @@ void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) vgpd->source.beginDataAccess(); drawImage(pos, vgpd->source.imageRef()); - vgpd->source.endDataAccess(); + vgpd->source.endDataAccess(true); } else { drawImage(pos, *(pd->buffer())); } @@ -3180,6 +3285,8 @@ void QVGPaintEngine::drawImage Qt::ImageConversionFlags flags) { Q_D(QVGPaintEngine); + if (image.isNull()) + return; VGImage vgImg; if (d->simpleTransform || d->opacity == 1.0f) vgImg = toVGImageSubRect(image, sr.toRect(), flags); @@ -3216,7 +3323,10 @@ void QVGPaintEngine::drawImage } else { // Monochrome images need to use the vgChildImage() path. vgImg = toVGImage(image, flags); - drawVGImage(d, r, vgImg, image.size(), sr); + if (vgImg == VG_INVALID_HANDLE) + drawImageTiled(d, r, image, sr); + else + drawVGImage(d, r, vgImg, image.size(), sr); } } vgDestroyImage(vgImg); @@ -3225,6 +3335,8 @@ void QVGPaintEngine::drawImage void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image) { Q_D(QVGPaintEngine); + if (image.isNull()) + return; VGImage vgImg; if (canVgWritePixels(image)) { // Optimization for straight blits, no blending @@ -3241,7 +3353,10 @@ void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image) } else { vgImg = toVGImageWithOpacity(image, d->opacity); } - drawVGImage(d, pos, vgImg); + if (vgImg == VG_INVALID_HANDLE) + drawImageTiled(d, QRectF(pos, image.size()), image); + else + drawVGImage(d, pos, vgImg); vgDestroyImage(vgImg); } @@ -4018,6 +4133,8 @@ VGImageFormat qt_vg_image_to_vg_format(QImage::Format format) switch (format) { case QImage::Format_MonoLSB: return VG_BW_1; + case QImage::Format_Indexed8: + return VG_sL_8; case QImage::Format_ARGB32_Premultiplied: return VG_sARGB_8888_PRE; case QImage::Format_RGB32: @@ -4028,7 +4145,8 @@ VGImageFormat qt_vg_image_to_vg_format(QImage::Format format) return VG_sRGB_565; case QImage::Format_ARGB4444_Premultiplied: return VG_sARGB_4444; - default: break; + default: + break; } return VG_sARGB_8888; // XXX } |