diff options
Diffstat (limited to 'src/openvg/qpixmapdata_vg.cpp')
-rw-r--r-- | src/openvg/qpixmapdata_vg.cpp | 177 |
1 files changed, 132 insertions, 45 deletions
diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index 732b484..3f67c79 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -50,6 +50,7 @@ #include <QBuffer> #include <QImageReader> #include <QtGui/private/qimage_p.h> +#include <QtGui/private/qnativeimagehandleprovider_p.h> QT_BEGIN_NAMESPACE @@ -66,11 +67,15 @@ QVGPixmapData::QVGPixmapData(PixelType type) inImagePool = false; inLRU = false; failedToAlloc = false; +#if defined(Q_OS_SYMBIAN) + nativeImageHandleProvider = 0; + nativeImageHandle = 0; +#endif #if !defined(QT_NO_EGL) context = 0; qt_vg_register_pixmap(this); #endif - setSerialNumber(++qt_vg_pixmap_serial); + updateSerial(); } QVGPixmapData::~QVGPixmapData() @@ -98,6 +103,10 @@ void QVGPixmapData::destroyImages() vgImage = VG_INVALID_HANDLE; vgImageOpacity = VG_INVALID_HANDLE; inImagePool = false; + +#if defined(Q_OS_SYMBIAN) + releaseNativeImageHandle(); +#endif } void QVGPixmapData::destroyImageAndContext() @@ -105,6 +114,8 @@ void QVGPixmapData::destroyImageAndContext() if (vgImage != VG_INVALID_HANDLE) { // We need to have a context current to destroy the image. #if !defined(QT_NO_EGL) + if (!context) + context = qt_vg_create_context(0, QInternal::Pixmap); if (context->isCurrent()) { destroyImages(); } else { @@ -118,6 +129,10 @@ void QVGPixmapData::destroyImageAndContext() #else destroyImages(); #endif + } else { +#if defined(Q_OS_SYMBIAN) + releaseNativeImageHandle(); +#endif } #if !defined(QT_NO_EGL) if (context) { @@ -138,25 +153,31 @@ bool QVGPixmapData::isValid() const return (w > 0 && h > 0); } +void QVGPixmapData::updateSerial() +{ + setSerialNumber(++qt_vg_pixmap_serial); +} + void QVGPixmapData::resize(int wid, int ht) { - if (w == wid && h == ht) + if (w == wid && h == ht) { + updateSerial(); return; + } w = wid; h = ht; d = 32; // We always use ARGB_Premultiplied for VG pixmaps. is_null = (w <= 0 || h <= 0); - source = QImage(); + source = QVolatileImage(); recreate = true; - setSerialNumber(++qt_vg_pixmap_serial); + updateSerial(); } -void QVGPixmapData::fromImage - (const QImage &image, Qt::ImageConversionFlags flags) +void QVGPixmapData::fromImage(const QImage &image, Qt::ImageConversionFlags flags) { - if(image.isNull()) + if (image.isNull()) return; QImage img = image; @@ -200,33 +221,34 @@ bool QVGPixmapData::fromData(const uchar *buffer, uint len, const char *format, return !isNull(); } -/*! - out-of-place conversion (inPlace == false) will always detach() - */ -void QVGPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) +QImage::Format QVGPixmapData::idealFormat(QImage *image, Qt::ImageConversionFlags flags) const { - if (image.size() == QSize(w, h)) - setSerialNumber(++qt_vg_pixmap_serial); - else - resize(image.width(), image.height()); - QImage::Format format = sourceFormat(); - int d = image.depth(); - if (d == 1 || d == 16 || d == 24 || (d == 32 && !image.hasAlphaChannel())) + int d = image->depth(); + if (d == 1 || d == 16 || d == 24 || (d == 32 && !image->hasAlphaChannel())) format = QImage::Format_RGB32; - else if (!(flags & Qt::NoOpaqueDetection) && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels()) + else if (!(flags & Qt::NoOpaqueDetection) && image->data_ptr()->checkForAlphaPixels()) format = sourceFormat(); else - format = image.hasAlphaChannel() ? sourceFormat() : QImage::Format_RGB32; + format = image->hasAlphaChannel() ? sourceFormat() : QImage::Format_RGB32; + return format; +} + +void QVGPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) +{ + resize(image.width(), image.height()); + + QImage::Format format = idealFormat(&image, flags); if (inPlace && image.data_ptr()->convertInPlace(format, flags)) { - source = image; + source = QVolatileImage(image); } else { - source = image.convertToFormat(format); - - // convertToFormat won't detach the image if format stays the same. - if (image.format() == format) - source.detach(); + QImage convertedImage = image.convertToFormat(format); + // convertToFormat won't detach the image if format stays the + // same. Detaching is needed to prevent issues with painting + // onto this QPixmap later on. + convertedImage.detach(); + source = QVolatileImage(convertedImage); } recreate = true; @@ -236,27 +258,23 @@ void QVGPixmapData::fill(const QColor &color) { if (!isValid()) return; - - if (source.isNull()) - source = QImage(w, h, sourceFormat()); - + forceToImage(); if (source.depth() == 1) { // Pick the best approximate color in the image's colortable. int gray = qGray(color.rgba()); - if (qAbs(qGray(source.color(0)) - gray) < qAbs(qGray(source.color(1)) - gray)) + if (qAbs(qGray(source.imageRef().color(0)) - gray) + < qAbs(qGray(source.imageRef().color(1)) - gray)) source.fill(0); else source.fill(1); } else { source.fill(PREMUL(color.rgba())); } - - // Re-upload the image to VG the next time toVGImage() is called. - recreate = true; } bool QVGPixmapData::hasAlphaChannel() const { + ensureReadback(true); if (!source.isNull()) return source.hasAlphaChannel(); else @@ -265,27 +283,52 @@ bool QVGPixmapData::hasAlphaChannel() const void QVGPixmapData::setAlphaChannel(const QPixmap &alphaChannel) { + if (!isValid()) + return; forceToImage(); - source.setAlphaChannel(alphaChannel.toImage()); + source.setAlphaChannel(alphaChannel); } QImage QVGPixmapData::toImage() const { if (!isValid()) return QImage(); - + ensureReadback(true); if (source.isNull()) { - source = QImage(w, h, sourceFormat()); + source = QVolatileImage(w, h, sourceFormat()); recreate = true; } + return source.toImage(); +} - return source; +void QVGPixmapData::copy(const QPixmapData *data, const QRect &rect) +{ + // toImage() is potentially expensive with QVolatileImage so provide a + // more efficient implementation of copy() that does not rely on it. + if (!data) { + return; + } + if (data->classId() != OpenVGClass) { + fromImage(data->toImage(rect), Qt::NoOpaqueDetection); + return; + } + const QVGPixmapData *pd = static_cast<const QVGPixmapData *>(data); + QRect r = rect; + if (r.isNull() || r.contains(QRect(0, 0, pd->w, pd->h))) { + r = QRect(0, 0, pd->w, pd->h); + } + resize(r.width(), r.height()); + recreate = true; + if (!pd->source.isNull()) { + source = QVolatileImage(r.width(), r.height(), pd->source.format()); + source.copyFrom(&pd->source, r); + } } QImage *QVGPixmapData::buffer() { - forceToImage(); - return &source; + // Cannot be safely implemented and QVGPixmapData is not (must not be) RasterClass anyway. + return 0; } QPaintEngine* QVGPixmapData::paintEngine() const @@ -313,6 +356,12 @@ VGImage QVGPixmapData::toVGImage() else if (recreate) cachedOpacity = -1.0f; // Force opacity image to be refreshed later. +#if defined(Q_OS_SYMBIAN) + if (recreate && nativeImageHandleProvider && !nativeImageHandle) { + createFromNativeImageHandleProvider(); + } +#endif + if (vgImage == VG_INVALID_HANDLE) { vgImage = QVGImagePool::instance()->createImageForPixmap (qt_vg_image_to_vg_format(source.format()), w, h, VG_IMAGE_QUALITY_FASTER, this); @@ -329,10 +378,12 @@ VGImage QVGPixmapData::toVGImage() } if (!source.isNull() && recreate) { + source.beginDataAccess(); vgImageSubData (vgImage, source.constBits(), source.bytesPerLine(), qt_vg_image_to_vg_format(source.format()), 0, 0, w, h); + source.endDataAccess(true); } recreate = false; @@ -395,9 +446,16 @@ void QVGPixmapData::detachImageFromPool() void QVGPixmapData::hibernate() { - // If the image was imported (e.g, from an SgImage under Symbian), - // then we cannot copy it back to main memory for storage. - if (vgImage != VG_INVALID_HANDLE && source.isNull()) + // If the image was imported (e.g, from an SgImage under Symbian), then + // skip the hibernation, there is no sense in copying it back to main + // memory because the data is most likely shared between several processes. + bool skipHibernate = (vgImage != VG_INVALID_HANDLE && source.isNull()); +#if defined(Q_OS_SYMBIAN) + // However we have to proceed normally if the image was retrieved via + // a handle provider. + skipHibernate &= !nativeImageHandleProvider; +#endif + if (skipHibernate) return; forceToImage(); @@ -442,18 +500,47 @@ int QVGPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const } } -// Force the pixmap data to be in QImage format. +// Ensures that the pixmap is backed by some valid data and forces the data to +// be re-uploaded to the VGImage when toVGImage() is called next time. void QVGPixmapData::forceToImage() { if (!isValid()) return; + ensureReadback(false); + if (source.isNull()) - source = QImage(w, h, sourceFormat()); + source = QVolatileImage(w, h, sourceFormat()); recreate = true; } +void QVGPixmapData::ensureReadback(bool readOnly) const +{ + if (vgImage != VG_INVALID_HANDLE && source.isNull()) { + source = QVolatileImage(w, h, sourceFormat()); + source.beginDataAccess(); + vgGetImageSubData(vgImage, source.bits(), source.bytesPerLine(), + qt_vg_image_to_vg_format(source.format()), + 0, 0, w, h); + source.endDataAccess(); + if (readOnly) { + recreate = false; + } else { + // Once we did a readback, the original VGImage must be destroyed + // because it may be shared (e.g. created via SgImage) and a subsequent + // upload of the image data may produce unexpected results. + const_cast<QVGPixmapData *>(this)->destroyImages(); +#if defined(Q_OS_SYMBIAN) + // There is now an own copy of the data so drop the handle provider, + // otherwise toVGImage() would request the handle again, which is wrong. + nativeImageHandleProvider = 0; +#endif + recreate = true; + } + } +} + QImage::Format QVGPixmapData::sourceFormat() const { return QImage::Format_ARGB32_Premultiplied; |