From fac227f609e544f8f55aca8447b4328d6534407a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 17 Jun 2010 07:43:41 +0200 Subject: Speed up calls to QPainter::setCompositionMode when the mode is unchanged Avoid marking the composition mode as dirty and calling into the extended engine if the composition mode that the application wants to set is the same that's currently used. Reviewed-by: Gunnar --- src/gui/painting/qpainter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index d17c711..71bc990 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -2391,6 +2391,8 @@ void QPainter::setCompositionMode(CompositionMode mode) qWarning("QPainter::setCompositionMode: Painter not active"); return; } + if (d->state->composition_mode == mode) + return; if (d->extended) { d->state->composition_mode = mode; d->extended->compositionModeChanged(); -- cgit v0.12 From 594900e68f8e264facbe8c75eaf2b857240bc072 Mon Sep 17 00:00:00 2001 From: Geir Vattekar Date: Thu, 17 Jun 2010 09:11:18 +0200 Subject: Doc: Specified QAbstractEventDispatcher::filterEvent()'s argument types. Task-number: QTBUG-10904 Reviewed-by: Morten Engvoldsen --- src/corelib/kernel/qabstracteventdispatcher.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index ee3c4f2..bcf4477 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -393,6 +393,27 @@ void QAbstractEventDispatcher::closingDown() \snippet doc/src/snippets/code/src_corelib_kernel_qabstracteventdispatcher.cpp 0 + Note that the type of the \a message is platform dependent. The + following table shows the \a {message}'s type on Windows, Mac, and + X11. You can do a static cast to these types. + + \table + \header + \o Platform + \o type + \row + \o Windows + \o MSG + \row + \o X11 + \o XEvent + \row + \o Mac + \o NSEvent + \endtable + + + \sa setEventFilter(), filterEvent() */ @@ -434,6 +455,9 @@ QAbstractEventDispatcher::EventFilter QAbstractEventDispatcher::setEventFilter(E compatibility with any extensions that may be used in the application. + Note that the type of \a message is platform dependent. See + QAbstractEventDispatcher::EventFilter for details. + \sa setEventFilter() */ bool QAbstractEventDispatcher::filterEvent(void *message) -- cgit v0.12 From e4fbdd4fde9b8d2acc13268b44caa57405c3db1a Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 17 Jun 2010 10:24:49 +0200 Subject: Typo in qcleanlooksstyle.cpp Task-number: QTBUG-11506 --- src/gui/styles/qcleanlooksstyle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/styles/qcleanlooksstyle.cpp b/src/gui/styles/qcleanlooksstyle.cpp index 883f511..ada5293 100644 --- a/src/gui/styles/qcleanlooksstyle.cpp +++ b/src/gui/styles/qcleanlooksstyle.cpp @@ -884,7 +884,7 @@ void QCleanlooksStyle::drawPrimitive(PrimitiveElement elem, } painter->restore(); break; -#ifndef QT_NO_LINEDIT +#ifndef QT_NO_LINEEDIT case PE_FrameLineEdit: // fall through #endif // QT_NO_LINEEDIT -- cgit v0.12 From cf74e83d8b79c4840c073bb7dc387045b1210df8 Mon Sep 17 00:00:00 2001 From: Geir Vattekar Date: Thu, 17 Jun 2010 11:14:59 +0200 Subject: Doc: Small change to QAbstractItemDelegate::editorEvent() Task-number: QTBUG-2446 Reviewed-by: Marius Bugge Monsen --- src/gui/itemviews/qabstractitemdelegate.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gui/itemviews/qabstractitemdelegate.cpp b/src/gui/itemviews/qabstractitemdelegate.cpp index 775bf7d..0ea6d67 100644 --- a/src/gui/itemviews/qabstractitemdelegate.cpp +++ b/src/gui/itemviews/qabstractitemdelegate.cpp @@ -291,8 +291,14 @@ void QAbstractItemDelegate::updateEditorGeometry(QWidget *, } /*! - Whenever an event occurs, this function is called with the \a event - \a model \a option and the \a index that corresponds to the item being edited. + When editing of an item starts, this function is called with the + \a event that triggered the editing, the \a model, the \a index of + the item, and the \a option used for rendering the item. + + Mouse events are sent to editorEvent() even if they don't start + editing of the item. This can, for instance, be useful if you wish + to open a context menu when the right mouse button is pressed on + an item. The base implementation returns false (indicating that it has not handled the event). -- cgit v0.12 From 4cdeac4d4780e163eee3a1916683766f16747f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Thu, 17 Jun 2010 10:38:06 +0200 Subject: Optimized QPixmap::fromImage for raster pixmaps. If we know that the QImage is ARGB32 or ARGB32_Premultiplied and doesn't contain any alpha pixels we can treat it as RGB32 when doing the conversion. Reviewed-by: Gunnar Sletta --- src/gui/image/qpixmap_raster.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 9dc15fc..4f32d2f 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -192,10 +192,23 @@ void QRasterPixmapData::fromImage(const QImage &sourceImage, } #endif - if (!sourceImage.hasAlphaChannel() - || ((flags & Qt::NoOpaqueDetection) == 0 - && !const_cast(sourceImage).data_ptr()->checkForAlphaPixels())) { + if (!sourceImage.hasAlphaChannel()) { image = sourceImage.convertToFormat(opaqueFormat); + } else if ((flags & Qt::NoOpaqueDetection) == 0 + && !const_cast(sourceImage).data_ptr()->checkForAlphaPixels()) + { + // image has alpha format but is really opaque, so try to do a + // more efficient conversion + if (sourceImage.format() == QImage::Format_ARGB32 + || sourceImage.format() == QImage::Format_ARGB32_Premultiplied) + { + QImage rgbImage(sourceImage.bits(), sourceImage.width(), sourceImage.height(), + QImage::Format_RGB32); + image = rgbImage.convertToFormat(opaqueFormat); + image.detach(); + } else { + image = sourceImage.convertToFormat(opaqueFormat); + } } else { image = sourceImage.convertToFormat(alphaFormat); } -- cgit v0.12 From 21f5de51e0c49006f5be75ef64675145b9d8b5c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Thu, 17 Jun 2010 10:59:31 +0200 Subject: Don't do opaque detection when copying a sub-rect of a QPixmap. If the pixmap is non-opaque in the first place most likely a reasonably sized sub-rect is also non-opaque, so this check is a waste in 90 % of the cases. Reviewed-by: Gunnar Sletta --- src/gui/image/qpixmapdata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/image/qpixmapdata.cpp b/src/gui/image/qpixmapdata.cpp index ea4fe6b..31ca909 100644 --- a/src/gui/image/qpixmapdata.cpp +++ b/src/gui/image/qpixmapdata.cpp @@ -146,7 +146,7 @@ bool QPixmapData::fromData(const uchar *buf, uint len, const char *format, Qt::I void QPixmapData::copy(const QPixmapData *data, const QRect &rect) { - fromImage(data->toImage().copy(rect), Qt::AutoColor); + fromImage(data->toImage().copy(rect), Qt::NoOpaqueDetection); } bool QPixmapData::scroll(int dx, int dy, const QRect &rect) -- cgit v0.12 From cf5971503ee1f7a5ce96758e33796dfdf48375bf Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Fri, 18 Jun 2010 16:01:54 +0200 Subject: Fix a possible crash with the EVR video renderer in windows This can happn when the component can be instanciated but not all the services are available on it. The code is now more robust. Reviewed-By: gabi --- src/3rdparty/phonon/ds9/videorenderer_evr.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/3rdparty/phonon/ds9/videorenderer_evr.cpp b/src/3rdparty/phonon/ds9/videorenderer_evr.cpp index d23d9ce..de3f46f 100644 --- a/src/3rdparty/phonon/ds9/videorenderer_evr.cpp +++ b/src/3rdparty/phonon/ds9/videorenderer_evr.cpp @@ -43,14 +43,12 @@ namespace Phonon { //normally we should use IID_IMFGetService but this introduces another dependency //so here we simply define our own IId with the same value + ComPointer ret; ComPointer getService(filter, IID_IMFGetService); - Q_ASSERT(getService); - T *ptr = 0; - HRESULT hr = getService->GetService(guidService, riid, reinterpret_cast(&ptr)); - if (!SUCCEEDED(hr) || ptr == 0) - Q_ASSERT(!SUCCEEDED(hr) && ptr != 0); - ComPointer service(ptr); - return service; + if (getService) { + getService->GetService(guidService, riid, reinterpret_cast(ret.pparam())); + } + return ret; } VideoRendererEVR::~VideoRendererEVR() @@ -70,6 +68,10 @@ namespace Phonon } ComPointer filterControl = getService(m_filter, MR_VIDEO_RENDER_SERVICE, IID_IMFVideoDisplayControl); + if (!filterControl) { + m_filter = Filter(); //will release the interface + return; + } filterControl->SetVideoWindow(reinterpret_cast(target->winId())); filterControl->SetAspectRatioMode(MFVideoARMode_None); // We're in control of the size -- cgit v0.12 From 0a96503e84b418708712af61497df4a493ed9072 Mon Sep 17 00:00:00 2001 From: Benjamin Poulain Date: Sat, 19 Jun 2010 21:56:29 +0200 Subject: Start the implementation of in-place recoding for images MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, with the graphics system raster, converting from images to QPixmap often needs to allocate a new image to convert the right format. For example, for an image in ARGB32 of 10 mbytes, we need to allocate a second image of 10 mbytes in ARGB32_PM to convert the source image in the right format for pixmap. This can create a hight peak of memory, and is a bit slower than it should. This patch introduce in-place conversion of images when they are loaded with QPixmap::loadFromData(). The images are loaded in their default format by QImageReader, and are then converted in-place, trying to reduce memory allocations. Reviewed-by: Samuel Rødal --- src/gui/image/qimage.cpp | 274 +++++++++++++++++++++ src/gui/image/qimage_p.h | 3 + src/gui/image/qpixmap_raster.cpp | 214 +++++++++------- src/gui/image/qpixmap_raster_p.h | 3 + .../auto/qpixmap/loadFromData/designer_argb32.png | Bin 0 -> 4189 bytes .../loadFromData/designer_indexed8_no_alpha.gif | Bin 0 -> 3317 bytes .../loadFromData/designer_indexed8_no_alpha.png | Bin 0 -> 2431 bytes .../loadFromData/designer_indexed8_with_alpha.gif | Bin 0 -> 2086 bytes .../loadFromData/designer_indexed8_with_alpha.png | Bin 0 -> 1405 bytes tests/auto/qpixmap/loadFromData/designer_rgb32.jpg | Bin 0 -> 11810 bytes tests/auto/qpixmap/loadFromData/designer_rgb32.png | Bin 0 -> 4282 bytes tests/auto/qpixmap/tst_qpixmap.cpp | 37 +++ 12 files changed, 436 insertions(+), 95 deletions(-) create mode 100644 tests/auto/qpixmap/loadFromData/designer_argb32.png create mode 100644 tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha.gif create mode 100644 tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha.png create mode 100644 tests/auto/qpixmap/loadFromData/designer_indexed8_with_alpha.gif create mode 100644 tests/auto/qpixmap/loadFromData/designer_indexed8_with_alpha.png create mode 100644 tests/auto/qpixmap/loadFromData/designer_rgb32.jpg create mode 100644 tests/auto/qpixmap/loadFromData/designer_rgb32.png diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index adc2632..bb8a994 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -2274,6 +2274,8 @@ bool QImage::create(const QSize& size, int depth, int numColors, QImage::Endian typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); +typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags); + static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_ARGB32); @@ -2298,6 +2300,169 @@ static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt: } } +static bool convert_ARGB_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_ARGB32); + + const int pad = (data->bytes_per_line >> 2) - data->width; + QRgb *rgb_data = (QRgb *) data->data; + + for (int i = 0; i < data->height; ++i) { + const QRgb *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = PREMUL(*rgb_data); + ++rgb_data; + } + rgb_data += pad; + } + data->format = QImage::Format_ARGB32_Premultiplied; + return true; +} + +static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + const int depth = 32; + + const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const int nbytes = dst_bytes_per_line * data->height; + uchar *const newData = (uchar *)realloc(data->data, nbytes); + if (!newData) + return false; + + data->data = newData; + + // start converting from the end because the end image is bigger than the source + uchar *src_data = newData + data->nbytes; // end of src + quint32 *dest_data = (quint32 *) (newData + nbytes); // end of dest > end of src + const int width = data->width; + const int src_pad = data->bytes_per_line - width; + const int dest_pad = (dst_bytes_per_line >> 2) - width; + + for (int i = 0; i < data->height; ++i) { + src_data -= src_pad; + dest_data -= dest_pad; + for (int pixI = 0; pixI < width; ++pixI) { + --src_data; + --dest_data; + const uint pixel = data->colortable[*src_data]; + *dest_data = (quint32) PREMUL(pixel); + } + } + + data->format = QImage::Format_ARGB32_Premultiplied; + data->bytes_per_line = dst_bytes_per_line; + data->depth = depth; + data->nbytes = nbytes; + + return true; +} + +static bool convert_indexed8_to_RGB_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + const int depth = 32; + + const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const int nbytes = dst_bytes_per_line * data->height; + uchar *const newData = (uchar *)realloc(data->data, nbytes); + if (!newData) + return false; + + data->data = newData; + + // start converting from the end because the end image is bigger than the source + uchar *src_data = newData + data->nbytes; + quint32 *dest_data = (quint32 *) (newData + nbytes); + const int width = data->width; + const int src_pad = data->bytes_per_line - width; + const int dest_pad = (dst_bytes_per_line >> 2) - width; + + for (int i = 0; i < data->height; ++i) { + src_data -= src_pad; + dest_data -= dest_pad; + for (int pixI = 0; pixI < width; ++pixI) { + --src_data; + --dest_data; + *dest_data = (quint32) data->colortable[*src_data]; + } + } + + data->format = QImage::Format_RGB32; + data->bytes_per_line = dst_bytes_per_line; + data->depth = depth; + data->nbytes = nbytes; + + return true; +} + +static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_Indexed8); + const int depth = 16; + + const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const int nbytes = dst_bytes_per_line * data->height; + uchar *const newData = (uchar *)realloc(data->data, nbytes); + if (!newData) + return false; + + data->data = newData; + + // start converting from the end because the end image is bigger than the source + uchar *src_data = newData + data->nbytes; + quint16 *dest_data = (quint16 *) (newData + nbytes); + const int width = data->width; + const int src_pad = data->bytes_per_line - width; + const int dest_pad = (dst_bytes_per_line >> 1) - width; + + for (int i = 0; i < data->height; ++i) { + src_data -= src_pad; + dest_data -= dest_pad; + for (int pixI = 0; pixI < width; ++pixI) { + --src_data; + --dest_data; + const uint pixel = data->colortable[*src_data]; + *dest_data = qt_colorConvert(pixel, 0); + } + } + + data->format = QImage::Format_RGB16; + data->bytes_per_line = dst_bytes_per_line; + data->depth = depth; + data->nbytes = nbytes; + + return true; +} + +static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGB32); + const int depth = 16; + + const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; + const int src_bytes_per_line = data->bytes_per_line; + quint32 *src_data = (quint32 *) data->data; + quint16 *dst_data = (quint16 *) data->data; + + for (int i = 0; i < data->height; ++i) { + qt_memconvert(dst_data, src_data, data->width); + src_data = (quint32 *) (((char*)src_data) + src_bytes_per_line); + dst_data = (quint16 *) (((char*)dst_data) + dst_bytes_per_line); + } + data->format = QImage::Format_RGB16; + data->bytes_per_line = dst_bytes_per_line; + data->depth = depth; + data->nbytes = dst_bytes_per_line * data->height; + uchar *const newData = (uchar *)realloc(data->data, data->nbytes); + if (newData) { + data->data = newData; + return true; + } else { + return false; + } +} + static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); @@ -3447,6 +3612,103 @@ static const Image_Converter converter_map[QImage::NImageFormats][QImage::NImage } // Format_ARGB4444_Premultiplied }; +static const InPlace_Image_Converter inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] = +{ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_Mono + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_MonoLSB + { + 0, + 0, + 0, + 0, + 0, + convert_indexed8_to_RGB_inplace, + convert_indexed8_to_ARGB_PM_inplace, + convert_indexed8_to_RGB16_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, // Format_Indexed8 + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_RGB_to_RGB16_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, // Format_ARGB32 + { + 0, + 0, + 0, + 0, + 0, + 0, + convert_ARGB_to_ARGB_PM_inplace, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, // Format_ARGB32 + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_ARGB32_Premultiplied + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_RGB16 + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_ARGB8565_Premultiplied + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_RGB666 + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_ARGB6666_Premultiplied + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_RGB555 + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_ARGB8555_Premultiplied + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_RGB888 + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, // Format_RGB444 + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + } // Format_ARGB4444_Premultiplied +}; + /*! Returns a copy of the image in the given \a format. @@ -6276,6 +6538,18 @@ QTransform QImage::trueMatrix(const QTransform &matrix, int w, int h) return matrix * QTransform().translate(-delta.x(), -delta.y()); } +bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags) +{ + if (format == newFormat) + return true; + + const InPlace_Image_Converter *const converterPtr = &inplace_converter_map[format][newFormat]; + InPlace_Image_Converter converter = *converterPtr; + if (converter) + return converter(this, flags); + else + return false; +} /*! \typedef QImage::DataPtr diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 0c19647..f1a0c47 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -96,6 +96,9 @@ struct Q_GUI_EXPORT QImageData { // internal image data bool checkForAlphaPixels() const; + // Convert the image in-place, minimizing memory reallocation + // Return false if the conversion cannot be done in-place. + bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags); #ifndef QT_NO_IMAGE_TEXT QMap text; diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 4f32d2f..13c03a1 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -47,6 +47,9 @@ #include "qbitmap.h" #include "qimage.h" +#include +#include +#include #include #include @@ -127,104 +130,26 @@ void QRasterPixmapData::resize(int width, int height) setSerialNumber(image.serialNumber()); } +bool QRasterPixmapData::fromData(const uchar *buffer, uint len, const char *format, + Qt::ImageConversionFlags flags) +{ + QByteArray a = QByteArray::fromRawData(reinterpret_cast(buffer), len); + QBuffer b(&a); + b.open(QIODevice::ReadOnly); + QImage image = QImageReader(&b, format).read(); + if (image.isNull()) + return false; + + createPixmapForImage(image, flags, /* inplace = */true); + return !isNull(); +} + void QRasterPixmapData::fromImage(const QImage &sourceImage, Qt::ImageConversionFlags flags) { Q_UNUSED(flags); - -#ifdef Q_WS_QWS - QImage::Format format; - if (pixelType() == BitmapType) { - format = QImage::Format_Mono; - } else { - format = QScreen::instance()->pixelFormat(); - if (format == QImage::Format_Invalid) - format = QImage::Format_ARGB32_Premultiplied; - else if (format == QImage::Format_Indexed8) // currently not supported - format = QImage::Format_RGB444; - } - - if (sourceImage.hasAlphaChannel() - && ((flags & Qt::NoOpaqueDetection) - || const_cast(sourceImage).data_ptr()->checkForAlphaPixels())) { - switch (format) { - case QImage::Format_RGB16: - format = QImage::Format_ARGB8565_Premultiplied; - break; - case QImage::Format_RGB666: - format = QImage::Format_ARGB6666_Premultiplied; - break; - case QImage::Format_RGB555: - format = QImage::Format_ARGB8555_Premultiplied; - break; - case QImage::Format_RGB444: - format = QImage::Format_ARGB4444_Premultiplied; - break; - default: - format = QImage::Format_ARGB32_Premultiplied; - break; - } - } else if (format == QImage::Format_Invalid) { - format = QImage::Format_ARGB32_Premultiplied; - } - - image = sourceImage.convertToFormat(format); -#else - if (pixelType() == BitmapType) { - image = sourceImage.convertToFormat(QImage::Format_MonoLSB); - } else { - if (sourceImage.depth() == 1) { - image = sourceImage.hasAlphaChannel() - ? sourceImage.convertToFormat(QImage::Format_ARGB32_Premultiplied) - : sourceImage.convertToFormat(QImage::Format_RGB32); - } else { - - QImage::Format opaqueFormat = QNativeImage::systemFormat(); - QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; - -#ifndef QT_HAVE_NEON - switch (opaqueFormat) { - case QImage::Format_RGB16: - alphaFormat = QImage::Format_ARGB8565_Premultiplied; - break; - default: // We don't care about the others... - break; - } -#endif - - if (!sourceImage.hasAlphaChannel()) { - image = sourceImage.convertToFormat(opaqueFormat); - } else if ((flags & Qt::NoOpaqueDetection) == 0 - && !const_cast(sourceImage).data_ptr()->checkForAlphaPixels()) - { - // image has alpha format but is really opaque, so try to do a - // more efficient conversion - if (sourceImage.format() == QImage::Format_ARGB32 - || sourceImage.format() == QImage::Format_ARGB32_Premultiplied) - { - QImage rgbImage(sourceImage.bits(), sourceImage.width(), sourceImage.height(), - QImage::Format_RGB32); - image = rgbImage.convertToFormat(opaqueFormat); - image.detach(); - } else { - image = sourceImage.convertToFormat(opaqueFormat); - } - } else { - image = sourceImage.convertToFormat(alphaFormat); - } - } - } -#endif - if (image.d) { - w = image.d->width; - h = image.d->height; - d = image.d->depth; - } else { - w = h = d = 0; - } - is_null = (w <= 0 || h <= 0); - - setSerialNumber(image.serialNumber()); + QImage image = sourceImage; + createPixmapForImage(image, flags, /* inplace = */false); } // from qwindowsurface.cpp @@ -253,7 +178,7 @@ void QRasterPixmapData::fill(const QColor &color) if (alpha != 255) { if (!image.hasAlphaChannel()) { QImage::Format toFormat; -#ifndef QT_HAVE_NEON +#if !(defined(QT_HAVE_NEON) || defined(QT_ALWAYS_HAVE_SSE2)) if (image.format() == QImage::Format_RGB16) toFormat = QImage::Format_ARGB8565_Premultiplied; else if (image.format() == QImage::Format_RGB666) @@ -411,6 +336,105 @@ int QRasterPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const return 0; } +void QRasterPixmapData::createPixmapForImage(QImage &sourceImage, Qt::ImageConversionFlags flags, bool inPlace) +{ + QImage::Format format; +#ifdef Q_WS_QWS + if (pixelType() == BitmapType) { + format = QImage::Format_Mono; + } else { + format = QScreen::instance()->pixelFormat(); + if (format == QImage::Format_Invalid) + format = QImage::Format_ARGB32_Premultiplied; + else if (format == QImage::Format_Indexed8) // currently not supported + format = QImage::Format_RGB444; + } + + if (sourceImage.hasAlphaChannel() + && ((flags & Qt::NoOpaqueDetection) + || const_cast(sourceImage).data_ptr()->checkForAlphaPixels())) { + switch (format) { + case QImage::Format_RGB16: + format = QImage::Format_ARGB8565_Premultiplied; + break; + case QImage::Format_RGB666: + format = QImage::Format_ARGB6666_Premultiplied; + break; + case QImage::Format_RGB555: + format = QImage::Format_ARGB8555_Premultiplied; + break; + case QImage::Format_RGB444: + format = QImage::Format_ARGB4444_Premultiplied; + break; + default: + format = QImage::Format_ARGB32_Premultiplied; + break; + } + } else if (format == QImage::Format_Invalid) { + format = QImage::Format_ARGB32_Premultiplied; + } +#else + if (pixelType() == BitmapType) { + format = QImage::Format_MonoLSB; + } else { + if (sourceImage.depth() == 1) { + format = sourceImage.hasAlphaChannel() + ? QImage::Format_ARGB32_Premultiplied + : QImage::Format_RGB32; + } else { + QImage::Format opaqueFormat = QNativeImage::systemFormat(); + QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied; + +#if !defined(QT_HAVE_NEON) && !defined(QT_ALWAYS_HAVE_SSE2) + switch (opaqueFormat) { + case QImage::Format_RGB16: + alphaFormat = QImage::Format_ARGB8565_Premultiplied; + break; + default: // We don't care about the others... + break; + } +#endif + + if (!sourceImage.hasAlphaChannel()) { + format = opaqueFormat; + } else if ((flags & Qt::NoOpaqueDetection) == 0 + && !const_cast(sourceImage).data_ptr()->checkForAlphaPixels()) + { + // image has alpha format but is really opaque, so try to do a + // more efficient conversion + if (sourceImage.format() == QImage::Format_ARGB32 + || sourceImage.format() == QImage::Format_ARGB32_Premultiplied) + { + if (!inPlace) + sourceImage.detach(); + sourceImage.d->format = QImage::Format_RGB32; + } + format = opaqueFormat; + } else { + format = alphaFormat; + } + } + } +#endif + + if (inPlace && sourceImage.d->convertInPlace(format, flags)) { + image = sourceImage; + } else { + image = sourceImage.convertToFormat(format); + } + + if (image.d) { + w = image.d->width; + h = image.d->height; + d = image.d->depth; + } else { + w = h = d = 0; + } + is_null = (w <= 0 || h <= 0); + + setSerialNumber(image.serialNumber()); +} + QImage* QRasterPixmapData::buffer() { return ℑ diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h index 6cdd3d7..d7e3f85 100644 --- a/src/gui/image/qpixmap_raster_p.h +++ b/src/gui/image/qpixmap_raster_p.h @@ -72,6 +72,7 @@ public: void resize(int width, int height); void fromFile(const QString &filename, Qt::ImageConversionFlags flags); + bool fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags); void fromImage(const QImage &image, Qt::ImageConversionFlags flags); bool scroll(int dx, int dy, const QRect &rect); @@ -85,6 +86,8 @@ public: protected: int metric(QPaintDevice::PaintDeviceMetric metric) const; + void createPixmapForImage(QImage &sourceImage, Qt::ImageConversionFlags flags, bool inPlace); + void setImage(const QImage &image); QImage image; private: diff --git a/tests/auto/qpixmap/loadFromData/designer_argb32.png b/tests/auto/qpixmap/loadFromData/designer_argb32.png new file mode 100644 index 0000000..55d8247 Binary files /dev/null and b/tests/auto/qpixmap/loadFromData/designer_argb32.png differ diff --git a/tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha.gif b/tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha.gif new file mode 100644 index 0000000..26a6da3 Binary files /dev/null and b/tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha.gif differ diff --git a/tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha.png b/tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha.png new file mode 100644 index 0000000..28cd2f0 Binary files /dev/null and b/tests/auto/qpixmap/loadFromData/designer_indexed8_no_alpha.png differ diff --git a/tests/auto/qpixmap/loadFromData/designer_indexed8_with_alpha.gif b/tests/auto/qpixmap/loadFromData/designer_indexed8_with_alpha.gif new file mode 100644 index 0000000..49ec77b Binary files /dev/null and b/tests/auto/qpixmap/loadFromData/designer_indexed8_with_alpha.gif differ diff --git a/tests/auto/qpixmap/loadFromData/designer_indexed8_with_alpha.png b/tests/auto/qpixmap/loadFromData/designer_indexed8_with_alpha.png new file mode 100644 index 0000000..09735a9 Binary files /dev/null and b/tests/auto/qpixmap/loadFromData/designer_indexed8_with_alpha.png differ diff --git a/tests/auto/qpixmap/loadFromData/designer_rgb32.jpg b/tests/auto/qpixmap/loadFromData/designer_rgb32.jpg new file mode 100644 index 0000000..70f39c2 Binary files /dev/null and b/tests/auto/qpixmap/loadFromData/designer_rgb32.jpg differ diff --git a/tests/auto/qpixmap/loadFromData/designer_rgb32.png b/tests/auto/qpixmap/loadFromData/designer_rgb32.png new file mode 100644 index 0000000..bca471d Binary files /dev/null and b/tests/auto/qpixmap/loadFromData/designer_rgb32.png differ diff --git a/tests/auto/qpixmap/tst_qpixmap.cpp b/tests/auto/qpixmap/tst_qpixmap.cpp index 49b1e52..179f068 100644 --- a/tests/auto/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/qpixmap/tst_qpixmap.cpp @@ -172,6 +172,9 @@ private slots: void fromData(); void loadFromDataNullValues(); + void loadFromDataImage_data(); + void loadFromDataImage(); + void preserveDepth(); void splash_crash(); @@ -1540,6 +1543,40 @@ void tst_QPixmap::loadFromDataNullValues() } } +void tst_QPixmap::loadFromDataImage_data() +{ + QTest::addColumn("imagePath"); +#ifdef Q_OS_SYMBIAN + const QString prefix = QLatin1String(SRCDIR) + "loadFromData"; +#else + const QString prefix = QLatin1String(SRCDIR) + "/loadFromData"; +#endif + QTest::newRow("designer_argb32.png") << prefix + "/designer_argb32.png"; + QTest::newRow("designer_indexed8_no_alpha.png") << prefix + "/designer_indexed8_no_alpha.png"; + QTest::newRow("designer_indexed8_with_alpha.png") << prefix + "/designer_indexed8_with_alpha.png"; + QTest::newRow("designer_rgb32.png") << prefix + "/designer_rgb32.png"; + QTest::newRow("designer_indexed8_no_alpha.gif") << prefix + "/designer_indexed8_no_alpha.gif"; + QTest::newRow("designer_indexed8_with_alpha.gif") << prefix + "/designer_indexed8_with_alpha.gif"; + QTest::newRow("designer_rgb32.jpg") << prefix + "/designer_rgb32.jpg"; +} + +void tst_QPixmap::loadFromDataImage() +{ + QFETCH(QString, imagePath); + + QImage imageRef(imagePath); + QPixmap pixmapWithCopy = QPixmap::fromImage(imageRef); + + QFile file(imagePath); + file.open(QIODevice::ReadOnly); + QByteArray rawData = file.readAll(); + + QPixmap directLoadingPixmap; + directLoadingPixmap.loadFromData(rawData); + + QVERIFY(pixmapsAreEqual(&pixmapWithCopy, &directLoadingPixmap)); +} + void tst_QPixmap::task_246446() { // This crashed without the bugfix in 246446 -- cgit v0.12