Add support for cleanup functions for data-constructed QImages
A QImage can be constructed with a provided buffer, that has to be kept alive for the live-time of the QImage and all its copies. Frameworks like CoreGraphics or Cairo offer a similar method of creating image objects and also offer the ability to provide a callback function that is called when the image is destroyed. This patch adds this functionality to QImage by extending the QImage constructors that take a raw image buffer pointer. Change-Id: Ia6342408c560ef49b498c9e4664b4602febb0fcd Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com> Reviewed-by: Michalina Ziemba <michalina.ziemba@nokia.com> Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
This commit is contained in:
parent
2bf186a2e5
commit
298330bd43
@ -124,7 +124,8 @@ QImageData::QImageData()
|
||||
dpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
|
||||
dpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
|
||||
offset(0, 0), own_data(true), ro_data(false), has_alpha_clut(false),
|
||||
is_cached(false), is_locked(false), paintEngine(0)
|
||||
is_cached(false), is_locked(false), cleanupFunction(0), cleanupInfo(0),
|
||||
paintEngine(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -206,6 +207,8 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format, int nu
|
||||
|
||||
QImageData::~QImageData()
|
||||
{
|
||||
if (cleanupFunction)
|
||||
cleanupFunction(cleanupInfo);
|
||||
if (is_cached)
|
||||
QImagePixmapCleanupHooks::executeImageHooks((((qint64) ser_no) << 32) | ((qint64) detach_no));
|
||||
delete paintEngine;
|
||||
@ -615,6 +618,18 @@ bool QImageData::checkForAlphaPixels() const
|
||||
{Image Viewer Example}, {Scribble Example}, {Pixelator Example}
|
||||
*/
|
||||
|
||||
/*!
|
||||
\typedef QImageCleanupFunction
|
||||
\since 5.0
|
||||
|
||||
A function with the following signature that can be used to
|
||||
implement basic image memory management:
|
||||
|
||||
\code
|
||||
void myImageCleanupHandler(void *info);
|
||||
\endcode
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum QImage::InvertMode
|
||||
|
||||
@ -771,7 +786,7 @@ QImage::QImage(const QSize &size, Format format)
|
||||
|
||||
|
||||
|
||||
QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QImage::Format format, bool readOnly)
|
||||
QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
|
||||
{
|
||||
QImageData *d = 0;
|
||||
|
||||
@ -814,6 +829,9 @@ QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QIm
|
||||
d->bytes_per_line = bpl;
|
||||
d->nbytes = d->bytes_per_line * height;
|
||||
|
||||
d->cleanupFunction = cleanupFunction;
|
||||
d->cleanupInfo = cleanupInfo;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
@ -823,17 +841,21 @@ QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QIm
|
||||
and \a height must be specified in pixels, \a data must be 32-bit aligned,
|
||||
and each scanline of data in the image must also be 32-bit aligned.
|
||||
|
||||
The buffer must remain valid throughout the life of the
|
||||
QImage. The image does not delete the buffer at destruction.
|
||||
The buffer must remain valid throughout the life of the QImage and
|
||||
all copies that have not been modified or otherwise detached from
|
||||
the original buffer. The image does not delete the buffer at destruction.
|
||||
You can provide a function pointer \a cleanupFunction along with an
|
||||
extra pointer \a cleanupInfo that will be called when the last copy
|
||||
is destroyed.
|
||||
|
||||
If \a format is an indexed color format, the image color table is
|
||||
initially empty and must be sufficiently expanded with
|
||||
setColorCount() or setColorTable() before the image is used.
|
||||
*/
|
||||
QImage::QImage(uchar* data, int width, int height, Format format)
|
||||
QImage::QImage(uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
|
||||
: QPaintDevice()
|
||||
{
|
||||
d = QImageData::create(data, width, height, 0, format, false);
|
||||
d = QImageData::create(data, width, height, 0, format, false, cleanupFunction, cleanupInfo);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -845,8 +867,10 @@ QImage::QImage(uchar* data, int width, int height, Format format)
|
||||
|
||||
The buffer must remain valid throughout the life of the QImage and
|
||||
all copies that have not been modified or otherwise detached from
|
||||
the original buffer. The image does not delete the buffer at
|
||||
destruction.
|
||||
the original buffer. The image does not delete the buffer at destruction.
|
||||
You can provide a function pointer \a cleanupFunction along with an
|
||||
extra pointer \a cleanupInfo that will be called when the last copy
|
||||
is destroyed.
|
||||
|
||||
If \a format is an indexed color format, the image color table is
|
||||
initially empty and must be sufficiently expanded with
|
||||
@ -859,10 +883,10 @@ QImage::QImage(uchar* data, int width, int height, Format format)
|
||||
constructing a QImage from raw data, without the possibility of the raw
|
||||
data being changed.
|
||||
*/
|
||||
QImage::QImage(const uchar* data, int width, int height, Format format)
|
||||
QImage::QImage(const uchar* data, int width, int height, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
|
||||
: QPaintDevice()
|
||||
{
|
||||
d = QImageData::create(const_cast<uchar*>(data), width, height, 0, format, true);
|
||||
d = QImageData::create(const_cast<uchar*>(data), width, height, 0, format, true, cleanupFunction, cleanupInfo);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -871,17 +895,21 @@ QImage::QImage(const uchar* data, int width, int height, Format format)
|
||||
and \a height must be specified in pixels. \a bytesPerLine
|
||||
specifies the number of bytes per line (stride).
|
||||
|
||||
The buffer must remain valid throughout the life of the
|
||||
QImage. The image does not delete the buffer at destruction.
|
||||
The buffer must remain valid throughout the life of the QImage and
|
||||
all copies that have not been modified or otherwise detached from
|
||||
the original buffer. The image does not delete the buffer at destruction.
|
||||
You can provide a function pointer \a cleanupFunction along with an
|
||||
extra pointer \a cleanupInfo that will be called when the last copy
|
||||
is destroyed.
|
||||
|
||||
If \a format is an indexed color format, the image color table is
|
||||
initially empty and must be sufficiently expanded with
|
||||
setColorCount() or setColorTable() before the image is used.
|
||||
*/
|
||||
QImage::QImage(uchar *data, int width, int height, int bytesPerLine, Format format)
|
||||
QImage::QImage(uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
|
||||
:QPaintDevice()
|
||||
{
|
||||
d = QImageData::create(data, width, height, bytesPerLine, format, false);
|
||||
d = QImageData::create(data, width, height, bytesPerLine, format, false, cleanupFunction, cleanupInfo);
|
||||
}
|
||||
|
||||
|
||||
@ -891,8 +919,12 @@ QImage::QImage(uchar *data, int width, int height, int bytesPerLine, Format form
|
||||
and \a height must be specified in pixels. \a bytesPerLine
|
||||
specifies the number of bytes per line (stride).
|
||||
|
||||
The buffer must remain valid throughout the life of the
|
||||
QImage. The image does not delete the buffer at destruction.
|
||||
The buffer must remain valid throughout the life of the QImage and
|
||||
all copies that have not been modified or otherwise detached from
|
||||
the original buffer. The image does not delete the buffer at destruction.
|
||||
You can provide a function pointer \a cleanupFunction along with an
|
||||
extra pointer \a cleanupInfo that will be called when the last copy
|
||||
is destroyed.
|
||||
|
||||
If \a format is an indexed color format, the image color table is
|
||||
initially empty and must be sufficiently expanded with
|
||||
@ -906,10 +938,10 @@ QImage::QImage(uchar *data, int width, int height, int bytesPerLine, Format form
|
||||
data being changed.
|
||||
*/
|
||||
|
||||
QImage::QImage(const uchar *data, int width, int height, int bytesPerLine, Format format)
|
||||
QImage::QImage(const uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction, void *cleanupInfo)
|
||||
:QPaintDevice()
|
||||
{
|
||||
d = QImageData::create(const_cast<uchar*>(data), width, height, bytesPerLine, format, true);
|
||||
d = QImageData::create(const_cast<uchar*>(data), width, height, bytesPerLine, format, true, cleanupFunction, cleanupInfo);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -88,6 +88,7 @@ public:
|
||||
#endif
|
||||
#endif //QT_NO_IMAGE_TEXT
|
||||
|
||||
typedef void (*QImageCleanupFunction)(void*);
|
||||
|
||||
class Q_GUI_EXPORT QImage : public QPaintDevice
|
||||
{
|
||||
@ -128,10 +129,10 @@ public:
|
||||
QImage();
|
||||
QImage(const QSize &size, Format format);
|
||||
QImage(int width, int height, Format format);
|
||||
QImage(uchar *data, int width, int height, Format format);
|
||||
QImage(const uchar *data, int width, int height, Format format);
|
||||
QImage(uchar *data, int width, int height, int bytesPerLine, Format format);
|
||||
QImage(const uchar *data, int width, int height, int bytesPerLine, Format format);
|
||||
QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = 0, void *cleanupInfo = 0);
|
||||
QImage(const uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = 0, void *cleanupInfo = 0);
|
||||
QImage(uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = 0, void *cleanupInfo = 0);
|
||||
QImage(const uchar *data, int width, int height, int bytesPerLine, Format format, QImageCleanupFunction cleanupFunction = 0, void *cleanupInfo = 0);
|
||||
|
||||
#ifndef QT_NO_IMAGEFORMAT_XPM
|
||||
explicit QImage(const char * const xpm[]);
|
||||
|
@ -69,7 +69,7 @@ struct Q_GUI_EXPORT QImageData { // internal image data
|
||||
QImageData();
|
||||
~QImageData();
|
||||
static QImageData *create(const QSize &size, QImage::Format format, int numColors = 0);
|
||||
static QImageData *create(uchar *data, int w, int h, int bpl, QImage::Format format, bool readOnly);
|
||||
static QImageData *create(uchar *data, int w, int h, int bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction = 0, void *cleanupInfo = 0);
|
||||
|
||||
QAtomicInt ref;
|
||||
|
||||
@ -94,6 +94,9 @@ struct Q_GUI_EXPORT QImageData { // internal image data
|
||||
uint is_cached : 1;
|
||||
uint is_locked : 1;
|
||||
|
||||
QImageCleanupFunction cleanupFunction;
|
||||
void* cleanupInfo;
|
||||
|
||||
bool checkForAlphaPixels() const;
|
||||
|
||||
// Convert the image in-place, minimizing memory reallocation
|
||||
|
@ -144,6 +144,8 @@ private slots:
|
||||
|
||||
void deepCopyWhenPaintingActive();
|
||||
void scaled_QTBUG19157();
|
||||
|
||||
void cleanupFunctions();
|
||||
};
|
||||
|
||||
tst_QImage::tst_QImage()
|
||||
@ -1997,5 +1999,40 @@ void tst_QImage::scaled_QTBUG19157()
|
||||
QVERIFY(!foo.isNull());
|
||||
}
|
||||
|
||||
static void cleanupFunction(void* info)
|
||||
{
|
||||
bool *called = static_cast<bool*>(info);
|
||||
*called = true;
|
||||
}
|
||||
|
||||
void tst_QImage::cleanupFunctions()
|
||||
{
|
||||
QImage bufferImage(64, 64, QImage::Format_ARGB32);
|
||||
bufferImage.fill(0);
|
||||
|
||||
bool called;
|
||||
|
||||
{
|
||||
called = false;
|
||||
{
|
||||
QImage image(bufferImage.bits(), bufferImage.width(), bufferImage.height(), bufferImage.format(), cleanupFunction, &called);
|
||||
}
|
||||
QVERIFY(called);
|
||||
}
|
||||
|
||||
{
|
||||
called = false;
|
||||
QImage *copy = 0;
|
||||
{
|
||||
QImage image(bufferImage.bits(), bufferImage.width(), bufferImage.height(), bufferImage.format(), cleanupFunction, &called);
|
||||
copy = new QImage(image);
|
||||
}
|
||||
QVERIFY(!called);
|
||||
delete copy;
|
||||
QVERIFY(called);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QImage)
|
||||
#include "tst_qimage.moc"
|
||||
|
Loading…
Reference in New Issue
Block a user