summaryrefslogtreecommitdiffstats
path: root/src/openvg/qpixmapdata_vg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvg/qpixmapdata_vg.cpp')
-rw-r--r--src/openvg/qpixmapdata_vg.cpp177
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;