diff options
-rw-r--r-- | src/gui/image/image.pri | 3 | ||||
-rw-r--r-- | src/gui/image/qpixmapdata_p.h | 3 | ||||
-rw-r--r-- | src/openvg/qpixmapdata_vg.cpp | 37 | ||||
-rw-r--r-- | src/openvg/qpixmapdata_vg_p.h | 11 | ||||
-rw-r--r-- | src/openvg/qvg_symbian.cpp | 45 | ||||
-rw-r--r-- | src/s60installs/bwins/QtOpenVGu.def | 3 | ||||
-rw-r--r-- | src/s60installs/eabi/QtOpenVGu.def | 3 | ||||
-rw-r--r-- | tests/auto/nativeimagehandleprovider/nativeimagehandleprovider.pro | 6 | ||||
-rw-r--r-- | tests/auto/nativeimagehandleprovider/tst_nativeimagehandleprovider.cpp | 237 | ||||
-rw-r--r-- | tests/auto/other.pro | 3 |
10 files changed, 345 insertions, 6 deletions
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index d99b1c6..00dccbe 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -30,7 +30,8 @@ HEADERS += \ image/qpixmapfilter_p.h \ image/qimagepixmapcleanuphooks_p.h \ image/qvolatileimage_p.h \ - image/qvolatileimagedata_p.h + image/qvolatileimagedata_p.h \ + image/qnativeimagehandleprovider_p.h SOURCES += \ image/qbitmap.cpp \ diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h index aa24a0e..0d0d417 100644 --- a/src/gui/image/qpixmapdata_p.h +++ b/src/gui/image/qpixmapdata_p.h @@ -72,7 +72,8 @@ public: enum NativeType { FbsBitmap, SgImage, - VolatileImage + VolatileImage, + NativeImageHandleProvider }; #endif enum ClassId { RasterClass, X11Class, MacClass, DirectFBClass, diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index 47de5ab..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,6 +67,10 @@ 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); @@ -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() @@ -120,6 +129,10 @@ void QVGPixmapData::destroyImageAndContext() #else destroyImages(); #endif + } else { +#if defined(Q_OS_SYMBIAN) + releaseNativeImageHandle(); +#endif } #if !defined(QT_NO_EGL) if (context) { @@ -343,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); @@ -427,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(); @@ -505,6 +531,11 @@ void QVGPixmapData::ensureReadback(bool readOnly) const // 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; } } diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index 80ff1cb..15ff889 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -76,6 +76,8 @@ void qt_vg_unregister_pixmap(QVGPixmapData *pd); void qt_vg_hibernate_pixmaps(QVGSharedContext *context); #endif +class QNativeImageHandleProvider; + class Q_OPENVG_EXPORT QVGPixmapData : public QPixmapData { public: @@ -138,6 +140,9 @@ public: #if defined(Q_OS_SYMBIAN) void* toNativeType(NativeType type); void fromNativeType(void* pixmap, NativeType type); + bool initFromNativeImageHandle(void *handle, const QString &type); + void createFromNativeImageHandleProvider(); + void releaseNativeImageHandle(); #endif protected: @@ -177,6 +182,12 @@ protected: mutable QEglContext *context; #endif +#if defined(Q_OS_SYMBIAN) + mutable QNativeImageHandleProvider *nativeImageHandleProvider; + void *nativeImageHandle; + QString nativeImageType; +#endif + void forceToImage(); QImage::Format sourceFormat() const; QImage::Format idealFormat(QImage *image, Qt::ImageConversionFlags flags) const; diff --git a/src/openvg/qvg_symbian.cpp b/src/openvg/qvg_symbian.cpp index c6521fd..5eb64bd 100644 --- a/src/openvg/qvg_symbian.cpp +++ b/src/openvg/qvg_symbian.cpp @@ -41,6 +41,7 @@ #include "qpixmapdata_vg_p.h" #include "qvgfontglyphcache_p.h" +#include <QtGui/private/qnativeimagehandleprovider_p.h> #include <private/qt_s60_p.h> #include <fbs.h> @@ -111,6 +112,44 @@ void QVGPixmapData::cleanup() source = QVolatileImage(); } +bool QVGPixmapData::initFromNativeImageHandle(void *handle, const QString &type) +{ + if (type == QLatin1String("RSgImage")) { + fromNativeType(handle, QPixmapData::SgImage); + return true; + } else if (type == QLatin1String("CFbsBitmap")) { + fromNativeType(handle, QPixmapData::FbsBitmap); + return true; + } + return false; +} + +void QVGPixmapData::createFromNativeImageHandleProvider() +{ + void *handle = 0; + QString type; + nativeImageHandleProvider->get(&handle, &type); + if (handle) { + if (initFromNativeImageHandle(handle, type)) { + nativeImageHandle = handle; + nativeImageType = type; + } else { + qWarning("QVGPixmapData: Unknown native image type '%s'", qPrintable(type)); + } + } else { + qWarning("QVGPixmapData: Native handle is null"); + } +} + +void QVGPixmapData::releaseNativeImageHandle() +{ + if (nativeImageHandleProvider && nativeImageHandle) { + nativeImageHandleProvider->release(nativeImageHandle, nativeImageType); + nativeImageHandle = 0; + nativeImageType = QString(); + } +} + void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) { if (type == QPixmapData::SgImage && pixmap) { @@ -149,6 +188,11 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) source = *img; source.ensureFormat(idealFormat(&source.imageRef(), Qt::AutoColor)); recreate = true; + } else if (type == QPixmapData::NativeImageHandleProvider && pixmap) { + destroyImages(); + nativeImageHandleProvider = static_cast<QNativeImageHandleProvider *>(pixmap); + // Cannot defer the retrieval, we need at least the size right away. + createFromNativeImageHandleProvider(); } } @@ -216,6 +260,7 @@ void* QVGPixmapData::toNativeType(NativeType type) return reinterpret_cast<void*>(sgImage.take()); #endif } else if (type == QPixmapData::FbsBitmap && isValid()) { + ensureReadback(true); if (source.isNull()) { source = QVolatileImage(w, h, sourceFormat()); } diff --git a/src/s60installs/bwins/QtOpenVGu.def b/src/s60installs/bwins/QtOpenVGu.def index 0bc44e9..18f576b 100644 --- a/src/s60installs/bwins/QtOpenVGu.def +++ b/src/s60installs/bwins/QtOpenVGu.def @@ -180,4 +180,7 @@ EXPORTS ?copy@QVGPixmapData@@UAEXPBVQPixmapData@@ABVQRect@@@Z @ 179 NONAME ; void QVGPixmapData::copy(class QPixmapData const *, class QRect const &) ?idealFormat@QVGPixmapData@@IBE?AW4Format@QImage@@PAV3@V?$QFlags@W4ImageConversionFlag@Qt@@@@@Z @ 180 NONAME ; enum QImage::Format QVGPixmapData::idealFormat(class QImage *, class QFlags<enum Qt::ImageConversionFlag>) const ?ensureReadback@QVGPixmapData@@UBEX_N@Z @ 181 NONAME ; void QVGPixmapData::ensureReadback(bool) const + ?initFromNativeImageHandle@QVGPixmapData@@QAE_NPAXABVQString@@@Z @ 182 NONAME ; bool QVGPixmapData::initFromNativeImageHandle(void *, class QString const &) + ?createFromNativeImageHandleProvider@QVGPixmapData@@QAEXXZ @ 183 NONAME ; void QVGPixmapData::createFromNativeImageHandleProvider(void) + ?releaseNativeImageHandle@QVGPixmapData@@QAEXXZ @ 184 NONAME ; void QVGPixmapData::releaseNativeImageHandle(void) diff --git a/src/s60installs/eabi/QtOpenVGu.def b/src/s60installs/eabi/QtOpenVGu.def index 4c01550..25c53b8 100644 --- a/src/s60installs/eabi/QtOpenVGu.def +++ b/src/s60installs/eabi/QtOpenVGu.def @@ -210,4 +210,7 @@ EXPORTS _ZN13QVGPixmapData4copyEPK11QPixmapDataRK5QRect @ 209 NONAME _ZNK13QVGPixmapData11idealFormatEP6QImage6QFlagsIN2Qt19ImageConversionFlagEE @ 210 NONAME _ZNK13QVGPixmapData14ensureReadbackEb @ 211 NONAME + _ZN13QVGPixmapData24releaseNativeImageHandleEv @ 212 NONAME + _ZN13QVGPixmapData25initFromNativeImageHandleEPvRK7QString @ 213 NONAME + _ZN13QVGPixmapData35createFromNativeImageHandleProviderEv @ 214 NONAME diff --git a/tests/auto/nativeimagehandleprovider/nativeimagehandleprovider.pro b/tests/auto/nativeimagehandleprovider/nativeimagehandleprovider.pro new file mode 100644 index 0000000..fb8ecb0 --- /dev/null +++ b/tests/auto/nativeimagehandleprovider/nativeimagehandleprovider.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +SOURCES += tst_nativeimagehandleprovider.cpp +symbian { + LIBS += -lfbscli -lbitgdi + contains(QT_CONFIG, openvg): QT *= openvg +} diff --git a/tests/auto/nativeimagehandleprovider/tst_nativeimagehandleprovider.cpp b/tests/auto/nativeimagehandleprovider/tst_nativeimagehandleprovider.cpp new file mode 100644 index 0000000..5aaf055 --- /dev/null +++ b/tests/auto/nativeimagehandleprovider/tst_nativeimagehandleprovider.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtGui/private/qpixmapdata_p.h> +#include <QtGui/private/qnativeimagehandleprovider_p.h> +#include <QScopedPointer> +#include <QPixmap> +#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_OPENVG) +#include <fbs.h> +#include <bitdev.h> +#include <QtOpenVG/private/qpixmapdata_vg_p.h> +#endif + +QPixmap pixmapFromNativeImageHandleProvider(QNativeImageHandleProvider *source) +{ +#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_OPENVG) + if (!source) + return QPixmap(); + QScopedPointer<QPixmapData> pd(QPixmapData::create(0, 0, QPixmapData::PixmapType)); + pd->fromNativeType(source, QPixmapData::NativeImageHandleProvider); + return QPixmap(pd.take()); +#else + Q_UNUSED(source); + return QPixmap(); +#endif +} + +class DummyProvider : public QNativeImageHandleProvider +{ +public: + void get(void **handle, QString *type); + void release(void *handle, const QString &type); +}; + +void DummyProvider::get(void **handle, QString *type) +{ + *handle = (void *) 0x12345678; + *type = "some dummy type"; +} + +void DummyProvider::release(void *handle, const QString &type) +{ + Q_UNUSED(handle); + Q_UNUSED(type); +} + +#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_OPENVG) +class BitmapProvider : public QNativeImageHandleProvider +{ +public: + BitmapProvider() : bmp(0), refCount(0), w(50), h(60) { } + void get(void **handle, QString *type); + void release(void *handle, const QString &type); + + CFbsBitmap *bmp; + int refCount, w, h; + void *returnedHandle; + QString returnedType; +}; + +void BitmapProvider::get(void **handle, QString *type) +{ + // There may not be a release() if the get() fails so don't bother with + // refcounting in such cases. + if (bmp) + ++refCount; + returnedType = QLatin1String("CFbsBitmap"); + returnedHandle = bmp; + *handle = returnedHandle; + *type = returnedType; +} + +void BitmapProvider::release(void *handle, const QString &type) +{ + if (handle == returnedHandle && type == returnedType && returnedHandle) { + --refCount; + } +} +#endif // symbian & openvg + +class tst_NativeImageHandleProvider : public QObject +{ + Q_OBJECT + +public: + tst_NativeImageHandleProvider() { } + +private slots: + void create(); + void bitmap(); + void hibernate(); +}; + +void tst_NativeImageHandleProvider::create() +{ + QPixmap pm = pixmapFromNativeImageHandleProvider(0); + QVERIFY(pm.isNull()); + QPixmap tmp(10, 20); + if (tmp.pixmapData()->classId() == QPixmapData::OpenVGClass) { + // Verify that null pixmap is properly returned when get() provides bogus results. + DummyProvider prov; + pm = pixmapFromNativeImageHandleProvider(&prov); + QVERIFY(pm.isNull()); + pm = QPixmap(); + } else { + QSKIP("Not openvg, skipping non-trivial tests", SkipSingle); + } +} + +void tst_NativeImageHandleProvider::bitmap() +{ +#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_OPENVG) + QPixmap tmp(10, 20); + if (tmp.pixmapData()->classId() == QPixmapData::OpenVGClass) { + BitmapProvider prov; + + // This should fail because of null ptr. + QPixmap pm = pixmapFromNativeImageHandleProvider(&prov); + QVERIFY(pm.isNull()); + pm = QPixmap(); + QCOMPARE(prov.refCount, 0); + + prov.bmp = new CFbsBitmap; + QCOMPARE(prov.bmp->Create(TSize(prov.w, prov.h), EColor16MAP), KErrNone); + CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(prov.bmp); + CBitmapContext *bitmapContext = 0; + QCOMPARE(bitmapDevice->CreateBitmapContext(bitmapContext), KErrNone); + TRgb symbianColor = TRgb(255, 200, 100); + bitmapContext->SetBrushColor(symbianColor); + bitmapContext->Clear(); + delete bitmapContext; + delete bitmapDevice; + + pm = pixmapFromNativeImageHandleProvider(&prov); + QVERIFY(!pm.isNull()); + QCOMPARE(pm.width(), prov.w); + QCOMPARE(pm.height(), prov.h); + QVERIFY(prov.refCount == 1); + QImage img = pm.toImage(); + QVERIFY(prov.refCount == 1); + QRgb pix = img.pixel(QPoint(1, 2)); + QCOMPARE(qRed(pix), symbianColor.Red()); + QCOMPARE(qGreen(pix), symbianColor.Green()); + QCOMPARE(qBlue(pix), symbianColor.Blue()); + + pm = QPixmap(); // should result in calling release + QCOMPARE(prov.refCount, 0); + delete prov.bmp; + } else { + QSKIP("Not openvg", SkipSingle); + } +#else + QSKIP("Not applicable", SkipSingle); +#endif +} + +void tst_NativeImageHandleProvider::hibernate() +{ +#if defined(Q_OS_SYMBIAN) && !defined(QT_NO_OPENVG) + QPixmap tmp(10, 20); + if (tmp.pixmapData()->classId() == QPixmapData::OpenVGClass) { + BitmapProvider prov; + prov.bmp = new CFbsBitmap; + QCOMPARE(prov.bmp->Create(TSize(prov.w, prov.h), EColor16MAP), KErrNone); + + QPixmap pm = pixmapFromNativeImageHandleProvider(&prov); + QCOMPARE(prov.refCount, 1); + + QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pm.pixmapData()); + vgpd->hibernate(); + QCOMPARE(prov.refCount, 0); + + // Calling toVGImage() may cause some warnings as we don't have a gui initialized, + // but the only thing we care about here is get() being called. + vgpd->toVGImage(); + QCOMPARE(prov.refCount, 1); + + pm = QPixmap(); + QCOMPARE(prov.refCount, 0); + delete prov.bmp; + } else { + QSKIP("Not openvg", SkipSingle); + } +#else + QSKIP("Not applicable", SkipSingle); +#endif +} + +int main(int argc, char *argv[]) +{ + QApplication::setGraphicsSystem("openvg"); + QApplication app(argc, argv); + tst_NativeImageHandleProvider tc; + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_nativeimagehandleprovider.moc" diff --git a/tests/auto/other.pro b/tests/auto/other.pro index 3c8f856..40fa4a9 100644 --- a/tests/auto/other.pro +++ b/tests/auto/other.pro @@ -32,7 +32,8 @@ SUBDIRS=\ qvariant \ qwidget \ qworkspace \ - windowsmobile + windowsmobile \ + nativeimagehandleprovider contains(QT_CONFIG, OdfWriter):SUBDIRS += qzip qtextodfwriter mac: { |