Qt 4.8
qpixmapdata_vg.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtOpenVG module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qpixmapdata_vg_p.h"
43 #include "qpaintengine_vg_p.h"
44 #include <QtGui/private/qdrawhelper_p.h>
45 #if !defined(QT_NO_EGL)
46 #include <QtGui/private/qegl_p.h>
47 #endif
48 #include "qvg_p.h"
49 #include "qvgimagepool_p.h"
50 #include <QBuffer>
51 #include <QImageReader>
52 #include <QtGui/private/qimage_p.h>
53 #include <QtGui/private/qnativeimagehandleprovider_p.h>
54 #include <QtGui/private/qfont_p.h>
55 
57 
58 static int qt_vg_pixmap_serial = 0;
59 
61  : QPixmapData(type, OpenVGClass)
62 {
64  vgImage = VG_INVALID_HANDLE;
65  vgImageOpacity = VG_INVALID_HANDLE;
66  cachedOpacity = 1.0f;
67  recreate = true;
68  inImagePool = false;
69  inLRU = false;
70 #if defined(Q_OS_SYMBIAN)
71  nativeImageHandleProvider = 0;
72  nativeImageHandle = 0;
73 #endif
74 #if !defined(QT_NO_EGL)
75  context = 0;
77 #endif
78  updateSerial();
79 }
80 
82 {
84 #if !defined(QT_NO_EGL)
86 #endif
87 }
88 
90 {
91  if (inImagePool) {
93  if (vgImage != VG_INVALID_HANDLE)
94  pool->releaseImage(this, vgImage);
95  if (vgImageOpacity != VG_INVALID_HANDLE)
96  pool->releaseImage(this, vgImageOpacity);
97  } else {
98  if (vgImage != VG_INVALID_HANDLE)
99  vgDestroyImage(vgImage);
100  if (vgImageOpacity != VG_INVALID_HANDLE)
101  vgDestroyImage(vgImageOpacity);
102  }
103  vgImage = VG_INVALID_HANDLE;
104  vgImageOpacity = VG_INVALID_HANDLE;
105  inImagePool = false;
106 
107 #if defined(Q_OS_SYMBIAN)
108  releaseNativeImageHandle();
109 #endif
110 }
111 
113 {
114  if (vgImage != VG_INVALID_HANDLE) {
115  // We need to have a context current to destroy the image.
116 #if !defined(QT_NO_EGL)
117  if (!context)
119  if (context->isCurrent()) {
120  destroyImages();
121  } else {
122  // We don't currently have a widget surface active, but we
123  // need a surface to make the context current. So use the
124  // shared pbuffer surface instead.
126  destroyImages();
128  }
129 #else
130  destroyImages();
131 #endif
132  } else {
133 #if defined(Q_OS_SYMBIAN)
134  releaseNativeImageHandle();
135 #endif
136  }
137 #if !defined(QT_NO_EGL)
138  if (context) {
140  context = 0;
141  }
142 #endif
143  recreate = true;
144 }
145 
147 {
148  return new QVGPixmapData(pixelType());
149 }
150 
152 {
153  return (w > 0 && h > 0);
154 }
155 
157 {
159 }
160 
161 void QVGPixmapData::resize(int wid, int ht)
162 {
163  if (w == wid && h == ht) {
164  updateSerial();
165  return;
166  }
167 
168  w = wid;
169  h = ht;
170  d = 32; // We always use ARGB_Premultiplied for VG pixmaps.
171  is_null = (w <= 0 || h <= 0);
173  recreate = true;
174 
175  updateSerial();
176 }
177 
178 void QVGPixmapData::fromImage(const QImage &image, Qt::ImageConversionFlags flags)
179 {
180  if (image.isNull())
181  return;
182 
183  QImage img = image;
184  createPixmapForImage(img, flags, false);
185 }
186 
188  Qt::ImageConversionFlags flags)
189 {
190  QImage image = imageReader->read();
191  if (image.isNull())
192  return;
193 
194  createPixmapForImage(image, flags, true);
195 }
196 
197 bool QVGPixmapData::fromFile(const QString &filename, const char *format,
198  Qt::ImageConversionFlags flags)
199 {
200  QImage image = QImageReader(filename, format).read();
201  if (image.isNull())
202  return false;
203 
204  createPixmapForImage(image, flags, true);
205 
206  return !isNull();
207 }
208 
209 bool QVGPixmapData::fromData(const uchar *buffer, uint len, const char *format,
210  Qt::ImageConversionFlags flags)
211 {
212  QByteArray a = QByteArray::fromRawData(reinterpret_cast<const char *>(buffer), len);
213  QBuffer b(&a);
215  QImage image = QImageReader(&b, format).read();
216  if (image.isNull())
217  return false;
218 
219  createPixmapForImage(image, flags, true);
220 
221  return !isNull();
222 }
223 
224 QImage::Format QVGPixmapData::idealFormat(QImage *image, Qt::ImageConversionFlags flags) const
225 {
227  int d = image->depth();
228  if (d == 1 || d == 16 || d == 24 || (d == 32 && !image->hasAlphaChannel()))
229  format = QImage::Format_RGB32;
230  else if (!(flags & Qt::NoOpaqueDetection) && image->data_ptr()->checkForAlphaPixels())
231  format = sourceFormat();
232  else
233  format = image->hasAlphaChannel() ? sourceFormat() : QImage::Format_RGB32;
234  return format;
235 }
236 
237 void QVGPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace)
238 {
239  resize(image.width(), image.height());
240 
241  QImage::Format format = idealFormat(&image, flags);
242 
243  if (inPlace && image.data_ptr()->convertInPlace(format, flags)) {
244  source = QVolatileImage(image);
245  } else {
246  QImage convertedImage = image.convertToFormat(format);
247  // convertToFormat won't detach the image if format stays the
248  // same. Detaching is needed to prevent issues with painting
249  // onto this QPixmap later on.
250  convertedImage.detach();
251  if (convertedImage.isNull())
252  qWarning("QVGPixmapData: Failed to convert image data (out of memory? try increasing heap size)");
253  source = QVolatileImage(convertedImage);
254  }
255  recreate = true;
256 }
257 
258 void QVGPixmapData::fill(const QColor &color)
259 {
260  if (!isValid())
261  return;
262  forceToImage();
263  if (source.depth() == 1) {
264  // Pick the best approximate color in the image's colortable.
265  int gray = qGray(color.rgba());
266  if (qAbs(qGray(source.imageRef().color(0)) - gray)
267  < qAbs(qGray(source.imageRef().color(1)) - gray))
268  source.fill(0);
269  else
270  source.fill(1);
271  } else {
272  source.fill(PREMUL(color.rgba()));
273  }
274 }
275 
277 {
278  ensureReadback(true);
279  if (!source.isNull())
280  return source.hasAlphaChannel();
281  else
282  return isValid();
283 }
284 
286 {
287  if (!isValid())
288  return;
289  forceToImage();
290  source.setAlphaChannel(alphaChannel);
291 }
292 
294 {
295  if (!isValid())
296  return QImage();
297  ensureReadback(true);
298  if (source.isNull()) {
300  recreate = true;
301  }
302  return source.toImage();
303 }
304 
305 void QVGPixmapData::copy(const QPixmapData *data, const QRect &rect)
306 {
307  // toImage() is potentially expensive with QVolatileImage so provide a
308  // more efficient implementation of copy() that does not rely on it.
309  if (!data) {
310  return;
311  }
312  if (data->classId() != OpenVGClass) {
314  return;
315  }
316  const QVGPixmapData *pd = static_cast<const QVGPixmapData *>(data);
317  QRect r = rect;
318  if (r.isNull() || r.contains(QRect(0, 0, pd->w, pd->h))) {
319  r = QRect(0, 0, pd->w, pd->h);
320  }
321  resize(r.width(), r.height());
322  recreate = true;
323  if (!pd->source.isNull()) {
324  source = QVolatileImage(r.width(), r.height(), pd->source.format());
325  source.copyFrom(&pd->source, r);
326  }
327 }
328 
330 {
331  // Cannot be safely implemented and QVGPixmapData is not (must not be) RasterClass anyway.
332  return 0;
333 }
334 
336 {
337  // If the application wants to paint into the QPixmap, we first
338  // force it to QImage format and then paint into that.
339  // This is simpler than juggling multiple VG contexts.
340  const_cast<QVGPixmapData *>(this)->forceToImage();
341  return source.paintEngine();
342 }
343 
345 {
346  if (!isValid())
347  return VG_INVALID_HANDLE;
348 
349 #if !defined(QT_NO_EGL)
350  // Increase the reference count on the shared context.
351  if (!context)
353 #endif
354 
355  if (recreate && prevSize != QSize(w, h))
356  destroyImages();
357  else if (recreate)
358  cachedOpacity = -1.0f; // Force opacity image to be refreshed later.
359 
360 #if defined(Q_OS_SYMBIAN)
361  if (recreate && nativeImageHandleProvider && !nativeImageHandle) {
362  createFromNativeImageHandleProvider();
363  }
364 #endif
365 
366  if (vgImage == VG_INVALID_HANDLE) {
368  (qt_vg_image_to_vg_format(source.format()), w, h, VG_IMAGE_QUALITY_FASTER, this);
369 
370  // Bail out if we run out of GPU memory - try again next time.
371  if (vgImage == VG_INVALID_HANDLE) {
372  return VG_INVALID_HANDLE;
373  }
374 
375  inImagePool = true;
376  } else if (inImagePool) {
378  }
379 
380  if (!source.isNull() && (recreate || source.paintingActive())) {
382  vgImageSubData
383  (vgImage,
386  source.endDataAccess(true);
387  }
388 
389  recreate = false;
390  prevSize = QSize(w, h);
391 
392  return vgImage;
393 }
394 
396 {
397 #if !defined(QT_SHIVAVG)
398  // Force the primary VG image to be recreated if necessary.
399  if (toVGImage() == VG_INVALID_HANDLE)
400  return VG_INVALID_HANDLE;
401 
402  if (opacity == 1.0f)
403  return vgImage;
404 
405  // Create an alternative image for the selected opacity.
406  if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) {
407  if (vgImageOpacity == VG_INVALID_HANDLE) {
408  if (inImagePool) {
410  (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this);
411  } else {
412  vgImageOpacity = vgCreateImage
413  (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER);
414  }
415 
416  // Bail out if we run out of GPU memory - try again next time.
417  if (vgImageOpacity == VG_INVALID_HANDLE)
418  return VG_INVALID_HANDLE;
419  }
420  VGfloat matrix[20] = {
421  1.0f, 0.0f, 0.0f, 0.0f,
422  0.0f, 1.0f, 0.0f, 0.0f,
423  0.0f, 0.0f, 1.0f, 0.0f,
424  0.0f, 0.0f, 0.0f, opacity,
425  0.0f, 0.0f, 0.0f, 0.0f
426  };
427  vgColorMatrix(vgImageOpacity, vgImage, matrix);
428  cachedOpacity = opacity;
429  }
430 
431  return vgImageOpacity;
432 #else
433  // vgColorMatrix() doesn't work with ShivaVG, so ignore the opacity.
434  Q_UNUSED(opacity);
435  return toVGImage();
436 #endif
437 }
438 
440 {
441  if (inImagePool) {
443  inImagePool = false;
444  }
445 }
446 
448 {
449  // If the image was imported (e.g, from an SgImage under Symbian), then
450  // skip the hibernation, there is no sense in copying it back to main
451  // memory because the data is most likely shared between several processes.
452  bool skipHibernate = (vgImage != VG_INVALID_HANDLE && source.isNull());
453 #if defined(Q_OS_SYMBIAN)
454  // However we have to proceed normally if the image was retrieved via
455  // a handle provider.
456  skipHibernate &= !nativeImageHandleProvider;
457 #endif
458  if (skipHibernate)
459  return;
460 
461  forceToImage(false); // no readback allowed here
463 }
464 
466 {
467  if (!inImagePool)
468  return;
469  forceToImage();
470  destroyImages();
471 }
472 
474 {
475  switch (metric) {
477  return w;
479  return h;
481  return 0;
483  return d;
485  return qRound(w * 25.4 / qt_defaultDpiX());
487  return qRound(h * 25.4 / qt_defaultDpiY());
490  return qt_defaultDpiX();
493  return qt_defaultDpiY();
494  default:
495  qWarning("QVGPixmapData::metric(): Invalid metric");
496  return 0;
497  }
498 }
499 
500 // Ensures that the pixmap is backed by some valid data and forces the data to
501 // be re-uploaded to the VGImage when toVGImage() is called next time.
502 void QVGPixmapData::forceToImage(bool allowReadback)
503 {
504  if (!isValid())
505  return;
506 
507  if (allowReadback)
508  ensureReadback(false);
509 
510  if (source.isNull())
512 
513  recreate = true;
514 }
515 
516 void QVGPixmapData::ensureReadback(bool readOnly) const
517 {
518  if (vgImage != VG_INVALID_HANDLE && source.isNull()) {
521  vgGetImageSubData(vgImage, source.bits(), source.bytesPerLine(),
523  0, 0, w, h);
525  if (readOnly) {
526  recreate = false;
527  } else {
528  // Once we did a readback, the original VGImage must be destroyed
529  // because it may be shared (e.g. created via SgImage) and a subsequent
530  // upload of the image data may produce unexpected results.
531  const_cast<QVGPixmapData *>(this)->destroyImages();
532 #if defined(Q_OS_SYMBIAN)
533  // There is now an own copy of the data so drop the handle provider,
534  // otherwise toVGImage() would request the handle again, which is wrong.
535  nativeImageHandleProvider = 0;
536 #endif
537  recreate = true;
538  }
539  }
540 }
541 
543 {
545 }
546 
547 /*
548  \internal
549 
550  Returns the VGImage that is storing the contents of \a pixmap.
551  Returns VG_INVALID_HANDLE if \a pixmap is not owned by the OpenVG
552  graphics system or \a pixmap is invalid.
553 
554  This function is typically used to access the backing store
555  for a pixmap when executing raw OpenVG calls. It must only
556  be used when a QPainter is active and the OpenVG paint engine
557  is in use by the QPainter.
558 
559  \sa {QtOpenVG Module}
560 */
562 {
563  QPixmapData *pd = pixmap.pixmapData();
564  if (!pd)
565  return VG_INVALID_HANDLE; // null QPixmap
566  if (pd->classId() == QPixmapData::OpenVGClass) {
567  QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd);
568  if (vgpd->isValid())
569  return vgpd->toVGImage();
570  }
571  return VG_INVALID_HANDLE;
572 }
573 
virtual void useImage(QVGPixmapData *data)
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
void destroyImageAndContext()
Format
The following image formats are available in Qt.
Definition: qimage.h:91
VGImageFormat qt_vg_image_to_vg_format(QImage::Format format)
bool isNull() const
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition: qrect.h:231
int type
Definition: qmetatype.cpp:239
double qreal
Definition: qglobal.h:1193
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QImage toImage() const
This will always perform a copy of the pixel data.
void fromImageReader(QImageReader *imageReader, Qt::ImageConversionFlags flags)
void forceToImage(bool allowReadback=true)
virtual void ensureReadback(bool readOnly) const
void beginDataAccess() const
Q_GUI_EXPORT int qt_defaultDpiY()
Definition: qfont.cpp:201
void createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace)
bool open(OpenMode openMode)
Reimplemented Function
Definition: qbuffer.cpp:338
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition: qimage.cpp:1542
QVGPixmapData(PixelType type)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
Q_GUI_EXPORT int qt_defaultDpiX()
Definition: qfont.cpp:162
void setAlphaChannel(const QPixmap &alphaChannel)
Q_OPENVG_EXPORT QEglContext * qt_vg_create_context(QPaintDevice *device, int devType)
QImage::Format sourceFormat() const
int width() const
Returns the width of the rectangle.
Definition: qrect.h:303
bool hasAlphaChannel() const
Returns true if the image has a format that respects the alpha channel, otherwise returns false...
Definition: qimage.cpp:6495
long ASN1_INTEGER_get ASN1_INTEGER * a
The QBuffer class provides a QIODevice interface for a QByteArray.
Definition: qbuffer.h:57
int height() const
Returns the height of the rectangle.
Definition: qrect.h:306
The QString class provides a Unicode character string.
Definition: qstring.h:83
QEglContext * context
QImage toImage() const
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
void endDataAccess(bool readOnly=false) const
bool fromFile(const QString &filename, const char *format, Qt::ImageConversionFlags flags)
virtual VGImage createImageForPixmap(VGImageFormat format, VGint width, VGint height, VGbitfield allowedQuality, QVGPixmapData *data)
bool isNull() const
void copy(const QPixmapData *data, const QRect &rect)
QImage::Format idealFormat(QImage *image, Qt::ImageConversionFlags flags) const
void fill(uint pixelValue)
void fill(const QColor &color)
PixelType pixelType() const
static int qt_vg_pixmap_serial
virtual QPixmap alphaChannel() const
unsigned char uchar
Definition: qglobal.h:994
virtual QImage toImage() const =0
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
virtual VGImage toVGImage()
int depth() const
Q_OPENVG_EXPORT void qt_vg_destroy_context(QEglContext *context, int devType)
Q_STATIC_INLINE_FUNCTION uint PREMUL(uint x)
Q_OPENVG_EXPORT EGLSurface qt_vg_shared_surface(void)
static QByteArray fromRawData(const char *, int size)
Constructs a QByteArray that uses the first size bytes of the data array.
bool hasAlphaChannel() const
void detach()
If multiple images share common data, this image makes a copy of the data and detaches itself from th...
Definition: qimage.cpp:1359
Q_CORE_EXPORT void qWarning(const char *,...)
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
Q_OPENVG_EXPORT VGImage qPixmapToVGImage(const QPixmap &pixmap)
ClassId classId() const
int depth() const
Returns the depth of the image.
Definition: qimage.cpp:1620
uchar * bits()
Access to pixel data via bits() or constBits() should be guarded by begin/endDataAccess().
QPaintEngine * paintEngine() const
The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a g...
Definition: qpaintengine.h:90
QImage::Format format() const
friend void qt_vg_register_pixmap(QVGPixmapData *pd)
bool contains(const QPoint &p, bool proper=false) const
Returns true if the given point is inside or on the edge of the rectangle, otherwise returns false...
Definition: qrect.cpp:1101
bool isCurrent() const
Definition: qegl.cpp:121
The QImageReader class provides a format independent interface for reading images from files or other...
Definition: qimagereader.h:62
DataPtr & data_ptr()
Definition: qimage.h:346
QVolatileImage source
void fromImage(const QImage &image, Qt::ImageConversionFlags flags)
Q_GUI_EXPORT_INLINE int qGray(int r, int g, int b)
Definition: qrgb.h:75
static QVGImagePool * instance()
bool isValid() const
int width() const
Returns the width of the image.
Definition: qimage.cpp:1557
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const Q_REQUIRED_RESULT
Returns a copy of the image in the given format.
Definition: qimage.cpp:3966
bool lazyDoneCurrent()
Definition: qegl.cpp:519
bool checkForAlphaPixels() const
Definition: qimage.cpp:236
bool makeCurrent(EGLSurface surface)
Definition: qegl.cpp:433
int bytesPerLine() const
bool hasAlphaChannel() const
VGImage vgImageOpacity
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
bool fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags)
bool paintingActive() const
void resize(int width, int height)
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
int metric(QPaintDevice::PaintDeviceMetric metric) const
QImage * buffer()
bool isNull() const
virtual void detachImage(QVGPixmapData *data)
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
virtual void hibernate()
bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags)
Definition: qimage.cpp:6935
QRgb rgba() const
Returns the RGB value of the color, including its alpha.
Definition: qcolor.cpp:1019
void setSerialNumber(int serNo)
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
#define Q_OPENVG_EXPORT
Definition: qglobal.h:1457
QImage & imageRef()
Returns a reference to the image that is potentially using some native buffer internally.
QImage read()
Reads an image from the device.
QRgb color(int i) const
Returns the color in the color table at index i.
Definition: qimage.cpp:1829
virtual void detachImageFromPool()
virtual void releaseImage(QVGPixmapData *data, VGImage image)
Q_DECL_CONSTEXPR int qRound(qreal d)
Definition: qglobal.h:1203
virtual void reclaimImages()
friend void qt_vg_unregister_pixmap(QVGPixmapData *pd)
void copyFrom(QVolatileImage *source, const QRect &rect)
const uchar * constBits() const
QPaintEngine * paintEngine()
To be called from the PixmapData&#39;s paintEngine().
QPixmapData * pixmapData() const
Definition: qpixmap.cpp:2277
QPixmapData * createCompatiblePixmapData() const
void setAlphaChannel(const QPixmap &alphaChannel)