diff options
30 files changed, 760 insertions, 149 deletions
@@ -3369,10 +3369,10 @@ Configure options: -debug-and-release . Compile and link two versions of Qt, with and without debugging turned on (Mac only). - -developer-build.... Compile and link Qt with Qt developer options (including auto-tests exporting) + -developer-build ... Compile and link Qt with Qt developer options (including auto-tests exporting) - -opensource......... Compile and link the Open-Source Edition of Qt. - -commercial......... Compile and link the Commercial Edition of Qt. + -opensource ........ Compile and link the Open-Source Edition of Qt. + -commercial ........ Compile and link the Commercial Edition of Qt. * -shared ............ Create and use shared Qt libraries. @@ -3765,7 +3765,7 @@ Qt/X11 only: Requires fontconfig/fontconfig.h, libfontconfig, freetype.h and libfreetype. - $XIN -no-xinput.......... Do not compile Xinput support. + $XIN -no-xinput ......... Do not compile Xinput support. $XIY -xinput ............ Compile Xinput support. This also enabled tablet support which requires IRIX with wacom.h and libXi or XFree86 with X11/extensions/XInput.h and libXi. diff --git a/dist/changes-4.6.2 b/dist/changes-4.6.2 index d35f945..2a884fe 100644 --- a/dist/changes-4.6.2 +++ b/dist/changes-4.6.2 @@ -46,8 +46,14 @@ QtCore QtGui ----- - - foo - * bar + - QBmpHandler + * [QTBUG-7530] Fixed an infinite loop that could occur when reading invalid BMP images. + + - QImage + * [QTBUG-7231] Avoid an unnecessary copy in QImage::scaled(). + + - QPDFEngine + * [QTBUG-7249] Fixed the encoding of the Tile and Creator tags in the PDF engine. QtDBus ------ @@ -64,8 +70,14 @@ QtNetwork QtOpenGL -------- - - foo - * bar + - QGLWidget + * [QTBUG-7213] Fixed QGLWidget::renderPixmap() on Windows. + + - QGLPixelBuffer + * [QTBUG-7476] Fixed a crash under X11 when drawing QPixmaps to QGLPixelBuffers. + + - QGL2PaintEngineEx + * [QTBUG-7203] Reset the GL stencil mask, op and function in resetGLState(). QtScript -------- @@ -121,7 +133,8 @@ Qt for Windows Qt for Mac OS X --------------- - - + - QPrintPreviewDialog + * [QTBUG-7481] Re-added the Close button in QPrintPreviewDialog for Mac/Carbon. Qt for Embedded Linux --------------------- diff --git a/src/3rdparty/phonon/ds9/videowidget.cpp b/src/3rdparty/phonon/ds9/videowidget.cpp index 091be16..95423c6 100644 --- a/src/3rdparty/phonon/ds9/videowidget.cpp +++ b/src/3rdparty/phonon/ds9/videowidget.cpp @@ -218,6 +218,9 @@ namespace Phonon if (toNative && m_noNativeRendererSupported) return current; //no switch here + if (!mediaObject()) + return current; + //firt we delete the renderer //initialization of the widgets for(int i = 0; i < FILTER_COUNT; ++i) { diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp index dbf422e..36e4af9 100644 --- a/src/corelib/kernel/qabstractitemmodel.cpp +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -1006,6 +1006,9 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent, Returns the child of the model index that is stored in the given \a row and \a column. + \note This function does not work for an invalid model index which is often + used as the root index. + \sa parent(), sibling() */ diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index 21650bb..089e04a 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -229,11 +229,10 @@ Q_GUI_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook \value ReadOnly Indicates that the model is readonly. \value HideNameFilterDetails Indicates if the is hidden or not. - This value is obsolete and does nothing since Qt 4.5: \value DontUseSheet In previous versions of Qt, the static functions would create a sheet by default if the static function - was given a parent. This is no longer supported in Qt 4.5, The + was given a parent. This is no longer supported and does nothing in Qt 4.5, The static functions will always be an application modal dialog. If you want to use sheets, use QFileDialog::open() instead. diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index ed36f87..b4e19d1 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2569,6 +2569,7 @@ void QGraphicsItem::setOpacity(qreal opacity) if (newOpacity == d_ptr->opacity) return; + bool wasFullyTransparent = d_ptr->isOpacityNull(); d_ptr->opacity = newOpacity; // Notify change. @@ -2584,7 +2585,9 @@ void QGraphicsItem::setOpacity(qreal opacity) d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true, /*force=*/false, - /*ignoreOpacity=*/true); + /*ignoreOpacity=*/d_ptr->isOpacityNull()); + if (wasFullyTransparent) + d_ptr->paintedViewBoundingRectsNeedRepaint = 1; } if (d_ptr->isObject) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 5ad6cd5..b3ca3b5 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -358,14 +358,20 @@ public: return o; } + inline bool isOpacityNull() const + { return (opacity < qreal(0.001)); } + + static inline bool isOpacityNull(qreal opacity) + { return (opacity < qreal(0.001)); } + inline bool isFullyTransparent() const { - if (opacity < 0.001) + if (isOpacityNull()) return true; if (!parent) return false; - return calcEffectiveOpacity() < 0.001; + return isOpacityNull(calcEffectiveOpacity()); } inline qreal effectiveOpacity() const { diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 54d47fa..842d368 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -4630,7 +4630,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * return; // Item has neither contents nor children!(?) const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); - const bool itemIsFullyTransparent = (opacity < 0.0001); + const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity); if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) return; @@ -4750,7 +4750,7 @@ void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const Q qreal opacity, const QTransform *effectTransform, bool wasDirtyParentSceneTransform, bool drawItem) { - const bool itemIsFullyTransparent = (opacity < 0.0001); + const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity); const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); const bool itemHasChildren = !item->d_ptr->children.isEmpty(); @@ -4980,7 +4980,8 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool } const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); - const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity && opacity < 0.0001; + const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity + && QGraphicsItemPrivate::isOpacityNull(opacity); if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) { resetDirtyItem(item, /*recursive=*/itemHasChildren); return; diff --git a/src/gui/graphicsview/qgraphicssceneindex.cpp b/src/gui/graphicsview/qgraphicssceneindex.cpp index 043c4eb..707c71f 100644 --- a/src/gui/graphicsview/qgraphicssceneindex.cpp +++ b/src/gui/graphicsview/qgraphicssceneindex.cpp @@ -279,7 +279,7 @@ void QGraphicsSceneIndexPrivate::recursive_items_helper(QGraphicsItem *item, QRe return; const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); - const bool itemIsFullyTransparent = (opacity < 0.0001); + const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity); const bool itemHasChildren = !item->d_ptr->children.isEmpty(); if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) return; @@ -554,7 +554,7 @@ QList<QGraphicsItem *> QGraphicsSceneIndex::estimateTopLevelItems(const QRectF & /*! \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(Qt::SortOrder order = Qt::DescendingOrder) const - + This pure virtual function all items in the index and sort them using \a order. */ diff --git a/src/gui/image/qimagepixmapcleanuphooks.cpp b/src/gui/image/qimagepixmapcleanuphooks.cpp index 61d538f..ace4bb6 100644 --- a/src/gui/image/qimagepixmapcleanuphooks.cpp +++ b/src/gui/image/qimagepixmapcleanuphooks.cpp @@ -62,12 +62,12 @@ QImagePixmapCleanupHooks *QImagePixmapCleanupHooks::instance() return qt_image_and_pixmap_cleanup_hooks(); } -void QImagePixmapCleanupHooks::addPixmapModificationHook(_qt_pixmap_cleanup_hook_pm hook) +void QImagePixmapCleanupHooks::addPixmapDataModificationHook(_qt_pixmap_cleanup_hook_pmd hook) { pixmapModificationHooks.append(hook); } -void QImagePixmapCleanupHooks::addPixmapDestructionHook(_qt_pixmap_cleanup_hook_pm hook) +void QImagePixmapCleanupHooks::addPixmapDataDestructionHook(_qt_pixmap_cleanup_hook_pmd hook) { pixmapDestructionHooks.append(hook); } @@ -78,12 +78,12 @@ void QImagePixmapCleanupHooks::addImageHook(_qt_image_cleanup_hook_64 hook) imageHooks.append(hook); } -void QImagePixmapCleanupHooks::removePixmapModificationHook(_qt_pixmap_cleanup_hook_pm hook) +void QImagePixmapCleanupHooks::removePixmapDataModificationHook(_qt_pixmap_cleanup_hook_pmd hook) { pixmapModificationHooks.removeAll(hook); } -void QImagePixmapCleanupHooks::removePixmapDestructionHook(_qt_pixmap_cleanup_hook_pm hook) +void QImagePixmapCleanupHooks::removePixmapDataDestructionHook(_qt_pixmap_cleanup_hook_pmd hook) { pixmapDestructionHooks.removeAll(hook); } @@ -93,24 +93,24 @@ void QImagePixmapCleanupHooks::removeImageHook(_qt_image_cleanup_hook_64 hook) imageHooks.removeAll(hook); } -void QImagePixmapCleanupHooks::executePixmapModificationHooks(QPixmap* pm) +void QImagePixmapCleanupHooks::executePixmapDataModificationHooks(QPixmapData* pmd) { QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks(); for (int i = 0; i < h->pixmapModificationHooks.count(); ++i) - h->pixmapModificationHooks[i](pm); + h->pixmapModificationHooks[i](pmd); if (qt_pixmap_cleanup_hook_64) - qt_pixmap_cleanup_hook_64(pm->cacheKey()); + qt_pixmap_cleanup_hook_64(pmd->cacheKey()); } -void QImagePixmapCleanupHooks::executePixmapDestructionHooks(QPixmap* pm) +void QImagePixmapCleanupHooks::executePixmapDataDestructionHooks(QPixmapData* pmd) { QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks(); for (int i = 0; i < h->pixmapDestructionHooks.count(); ++i) - h->pixmapDestructionHooks[i](pm); + h->pixmapDestructionHooks[i](pmd); if (qt_pixmap_cleanup_hook_64) - qt_pixmap_cleanup_hook_64(pm->cacheKey()); + qt_pixmap_cleanup_hook_64(pmd->cacheKey()); } void QImagePixmapCleanupHooks::executeImageHooks(qint64 key) diff --git a/src/gui/image/qimagepixmapcleanuphooks_p.h b/src/gui/image/qimagepixmapcleanuphooks_p.h index 7176044..88dd3a6 100644 --- a/src/gui/image/qimagepixmapcleanuphooks_p.h +++ b/src/gui/image/qimagepixmapcleanuphooks_p.h @@ -58,7 +58,8 @@ QT_BEGIN_NAMESPACE typedef void (*_qt_image_cleanup_hook_64)(qint64); -typedef void (*_qt_pixmap_cleanup_hook_pm)(QPixmap*); +typedef void (*_qt_pixmap_cleanup_hook_pmd)(QPixmapData*); + class QImagePixmapCleanupHooks; @@ -71,27 +72,27 @@ public: static void enableCleanupHooks(const QPixmap &pixmap); static void enableCleanupHooks(QPixmapData *pixmapData); - // Gets called when a pixmap is about to be modified: - void addPixmapModificationHook(_qt_pixmap_cleanup_hook_pm); + // Gets called when a pixmap data is about to be modified: + void addPixmapDataModificationHook(_qt_pixmap_cleanup_hook_pmd); - // Gets called when a pixmap is about to be destroyed: - void addPixmapDestructionHook(_qt_pixmap_cleanup_hook_pm); + // Gets called when a pixmap data is about to be destroyed: + void addPixmapDataDestructionHook(_qt_pixmap_cleanup_hook_pmd); // Gets called when an image is about to be modified or destroyed: void addImageHook(_qt_image_cleanup_hook_64); - void removePixmapModificationHook(_qt_pixmap_cleanup_hook_pm); - void removePixmapDestructionHook(_qt_pixmap_cleanup_hook_pm); + void removePixmapDataModificationHook(_qt_pixmap_cleanup_hook_pmd); + void removePixmapDataDestructionHook(_qt_pixmap_cleanup_hook_pmd); void removeImageHook(_qt_image_cleanup_hook_64); - static void executePixmapModificationHooks(QPixmap*); - static void executePixmapDestructionHooks(QPixmap*); + static void executePixmapDataModificationHooks(QPixmapData*); + static void executePixmapDataDestructionHooks(QPixmapData*); static void executeImageHooks(qint64 key); private: QList<_qt_image_cleanup_hook_64> imageHooks; - QList<_qt_pixmap_cleanup_hook_pm> pixmapModificationHooks; - QList<_qt_pixmap_cleanup_hook_pm> pixmapDestructionHooks; + QList<_qt_pixmap_cleanup_hook_pmd> pixmapModificationHooks; + QList<_qt_pixmap_cleanup_hook_pmd> pixmapDestructionHooks; }; QT_END_NAMESPACE diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index f823fdc..d1e5c40 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -320,8 +320,6 @@ QPixmap::QPixmap(const char * const xpm[]) QPixmap::~QPixmap() { Q_ASSERT(!data || data->ref >= 1); // Catch if ref-counting changes again - if (data && data->is_cached && data->ref == 1) // ref will be decrememnted after destructor returns - QImagePixmapCleanupHooks::executePixmapDestructionHooks(this); } /*! @@ -1025,12 +1023,8 @@ qint64 QPixmap::cacheKey() const if (isNull()) return 0; - int classKey = data->classId(); - if (classKey >= 1024) - classKey = -(classKey >> 10); - return ((((qint64) classKey) << 56) - | (((qint64) data->serialNumber()) << 32) - | ((qint64) (data->detach_no))); + Q_ASSERT(data); + return data->cacheKey(); } static void sendResizeEvents(QWidget *target) @@ -1943,7 +1937,7 @@ void QPixmap::detach() } if (data->is_cached && data->ref == 1) - QImagePixmapCleanupHooks::executePixmapModificationHooks(this); + QImagePixmapCleanupHooks::executePixmapDataModificationHooks(data.data()); #if defined(Q_WS_MAC) QMacPixmapData *macData = id == QPixmapData::MacClass ? static_cast<QMacPixmapData*>(data.data()) : 0; diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp index 0e66e09..e1e8a0d 100644 --- a/src/gui/image/qpixmap_x11.cpp +++ b/src/gui/image/qpixmap_x11.cpp @@ -68,6 +68,7 @@ #include "qx11info_x11.h" #include <private/qdrawhelper_p.h> #include <private/qimage_p.h> +#include <private/qimagepixmapcleanuphooks_p.h> #include <stdlib.h> @@ -1228,6 +1229,12 @@ void QX11PixmapData::fill(const QColor &fillColor) QX11PixmapData::~QX11PixmapData() { + // Cleanup hooks have to be called before the handles are freed + if (is_cached) { + QImagePixmapCleanupHooks::executePixmapDataDestructionHooks(this); + is_cached = false; + } + release(); } @@ -1236,8 +1243,13 @@ void QX11PixmapData::release() delete pengine; pengine = 0; - if (!X11) + if (!X11) { +#ifndef QT_NO_DEBUG + qWarning("~QX11PixmapData(): QPixmap objects must be destroyed before the QApplication" + " object, otherwise the native pixmap object will be leaked."); +#endif return; + } if (x11_mask) { #ifndef QT_NO_XRENDER diff --git a/src/gui/image/qpixmapdata.cpp b/src/gui/image/qpixmapdata.cpp index 65032da..ea4fe6b 100644 --- a/src/gui/image/qpixmapdata.cpp +++ b/src/gui/image/qpixmapdata.cpp @@ -45,6 +45,7 @@ #include <QtGui/qimagereader.h> #include <private/qgraphicssystem_p.h> #include <private/qapplication_p.h> +#include <private/qimagepixmapcleanuphooks_p.h> QT_BEGIN_NAMESPACE @@ -80,6 +81,16 @@ QPixmapData::QPixmapData(PixelType pixelType, int objectId) QPixmapData::~QPixmapData() { + // Sometimes the pixmap cleanup hooks will be called from derrived classes, which will + // then set is_cached to false. For example, on X11 QtOpenGL needs to delete the GLXPixmap + // or EGL Pixmap Surface for a given pixmap _before_ the native X11 pixmap is deleted, + // otherwise some drivers will leak the GL surface. In this case, QX11PixmapData will + // call the cleanup hooks itself before deleting the native pixmap and set is_cached to + // false. + if (is_cached) { + QImagePixmapCleanupHooks::executePixmapDataDestructionHooks(this); + is_cached = false; + } } QPixmapData *QPixmapData::createCompatiblePixmapData() const diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h index 1125515..827fa18 100644 --- a/src/gui/image/qpixmapdata_p.h +++ b/src/gui/image/qpixmapdata_p.h @@ -117,6 +117,14 @@ public: inline int colorCount() const { return metric(QPaintDevice::PdmNumColors); } inline int depth() const { return d; } inline bool isNull() const { return is_null; } + inline qint64 cacheKey() const { + int classKey = id; + if (classKey >= 1024) + classKey = -(classKey >> 10); + return ((((qint64) classKey) << 56) + | (((qint64) ser_no) << 32) + | ((qint64) detach_no)); + } #if defined(Q_OS_SYMBIAN) virtual void* toNativeType(NativeType type); diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index ffad38b..4054d2a 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -6414,6 +6414,8 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second) first = fp; } + if (fp == second) + return; if (QWidget *sp = second->focusProxy()) second = sp; diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index cde6a2d..bf12c6b 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -7509,7 +7509,7 @@ QPaintDevice *QPainter::redirected(const QPaintDevice *device, QPoint *offset) return widgetPrivate->redirected(offset); } - if (*globalRedirectionAtomic() == 0) + if (!globalRedirectionAtomic() || *globalRedirectionAtomic() == 0) return 0; QMutexLocker locker(globalRedirectionsMutex()); @@ -7529,7 +7529,7 @@ QPaintDevice *QPainter::redirected(const QPaintDevice *device, QPoint *offset) void qt_painter_removePaintDevice(QPaintDevice *dev) { - if (*globalRedirectionAtomic() == 0) + if (!globalRedirectionAtomic() || *globalRedirectionAtomic() == 0) return; QMutex *mutex = 0; diff --git a/src/gui/widgets/qmainwindowlayout.cpp b/src/gui/widgets/qmainwindowlayout.cpp index d1e7285..fc75c92 100644 --- a/src/gui/widgets/qmainwindowlayout.cpp +++ b/src/gui/widgets/qmainwindowlayout.cpp @@ -1627,6 +1627,13 @@ void QMainWindowLayout::animationFinished(QWidget *widget) tb->d_func()->plug(currentGapRect); #endif + savedState.clear(); + currentGapPos.clear(); + pluggingWidget = 0; + //applying the state will make sure that the currentGap is updated correctly + //and all the geometries (especially the one from the central widget) is correct + layoutState.apply(false); + #ifndef QT_NO_DOCKWIDGET #ifndef QT_NO_TABBAR if (qobject_cast<QDockWidget*>(widget) != 0) { @@ -1637,13 +1644,6 @@ void QMainWindowLayout::animationFinished(QWidget *widget) } #endif #endif - - savedState.clear(); - currentGapPos.clear(); - pluggingWidget = 0; - //applying the state will make sure that the currentGap is updated correctly - //and all the geometries (especially the one from the central widget) is correct - layoutState.apply(false); } if (!widgetAnimator.animating()) { diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index b282676..07f3159 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -558,6 +558,12 @@ void QGL2PaintEngineExPrivate::resetGLState() glStencilMask(0xff); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc(GL_ALWAYS, 0, 0xff); + glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); + glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glDisableVertexAttribArray(QT_OPACITY_ATTR); +#ifndef QT_OPENGL_ES_2 + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // color may have been changed by glVertexAttrib() +#endif } void QGL2PaintEngineEx::endNativePainting() diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 2a60708..fce9fdb 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1590,10 +1590,8 @@ QGLTextureCache::QGLTextureCache() Q_ASSERT(qt_gl_texture_cache == 0); qt_gl_texture_cache = this; - QImagePixmapCleanupHooks::instance()->addPixmapModificationHook(cleanupTextures); -#ifdef Q_WS_X11 - QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(cleanupPixmapSurfaces); -#endif + QImagePixmapCleanupHooks::instance()->addPixmapDataModificationHook(cleanupTextures); + QImagePixmapCleanupHooks::instance()->addPixmapDataDestructionHook(cleanupBeforePixmapDestruction); QImagePixmapCleanupHooks::instance()->addImageHook(imageCleanupHook); } @@ -1601,10 +1599,8 @@ QGLTextureCache::~QGLTextureCache() { qt_gl_texture_cache = 0; - QImagePixmapCleanupHooks::instance()->removePixmapModificationHook(cleanupTextures); -#ifdef Q_WS_X11 - QImagePixmapCleanupHooks::instance()->removePixmapDestructionHook(cleanupPixmapSurfaces); -#endif + QImagePixmapCleanupHooks::instance()->removePixmapDataModificationHook(cleanupTextures); + QImagePixmapCleanupHooks::instance()->removePixmapDataDestructionHook(cleanupBeforePixmapDestruction); QImagePixmapCleanupHooks::instance()->removeImageHook(imageCleanupHook); } @@ -1672,30 +1668,29 @@ void QGLTextureCache::imageCleanupHook(qint64 cacheKey) } -void QGLTextureCache::cleanupTextures(QPixmap* pixmap) +void QGLTextureCache::cleanupTextures(QPixmapData* pmd) { // ### remove when the GL texture cache becomes thread-safe if (qApp->thread() == QThread::currentThread()) { - const qint64 cacheKey = pixmap->cacheKey(); + const qint64 cacheKey = pmd->cacheKey(); QGLTexture *texture = instance()->getTexture(cacheKey); if (texture && texture->options & QGLContext::MemoryManagedBindOption) instance()->remove(cacheKey); } } -#if defined(Q_WS_X11) -void QGLTextureCache::cleanupPixmapSurfaces(QPixmap* pixmap) +void QGLTextureCache::cleanupBeforePixmapDestruction(QPixmapData* pmd) { // Remove any bound textures first: - cleanupTextures(pixmap); + cleanupTextures(pmd); - QPixmapData *pd = pixmap->data_ptr().data(); - if (pd->classId() == QPixmapData::X11Class) { - Q_ASSERT(pd->ref == 1); // Make sure reference counting isn't broken - QGLContextPrivate::destroyGlSurfaceForPixmap(pd); +#if defined(Q_WS_X11) + if (pmd->classId() == QPixmapData::X11Class) { + Q_ASSERT(pmd->ref == 0); // Make sure reference counting isn't broken + QGLContextPrivate::destroyGlSurfaceForPixmap(pmd); } -} #endif +} void QGLTextureCache::deleteIfEmpty() { diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 0104f07..713b067 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -522,7 +522,7 @@ public: QSize bindCompressedTexturePVR(const char *buf, int len); }; -class QGLTextureCache { +class Q_AUTOTEST_EXPORT QGLTextureCache { public: QGLTextureCache(); ~QGLTextureCache(); @@ -539,11 +539,8 @@ public: static QGLTextureCache *instance(); static void deleteIfEmpty(); static void imageCleanupHook(qint64 cacheKey); - static void cleanupTextures(QPixmap* pixmap); -#ifdef Q_WS_X11 - // X11 needs to catch pixmap data destruction to delete EGL/GLX pixmap surfaces - static void cleanupPixmapSurfaces(QPixmap* pixmap); -#endif + static void cleanupTextures(QPixmapData* pixmap); + static void cleanupBeforePixmapDestruction(QPixmapData* pixmap); private: QCache<qint64, QGLTexture> m_cache; diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index 11011ee..37bb7c0 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -319,14 +319,14 @@ public: ~QGLBlurTextureCache(); QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap); - bool hasBlurTextureInfo(const QPixmap &pixmap) const; + bool hasBlurTextureInfo(quint64 cacheKey) const; void insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info); - void clearBlurTextureInfo(const QPixmap &pixmap); + void clearBlurTextureInfo(quint64 cacheKey); void timerEvent(QTimerEvent *event); private: - static void pixmapDestroyed(QPixmap *pixmap); + static void pixmapDestroyed(QPixmapData *pixmap); QCache<quint64, QGLBlurTextureInfo > cache; @@ -379,21 +379,21 @@ QGLBlurTextureInfo *QGLBlurTextureCache::takeBlurTextureInfo(const QPixmap &pixm return cache.take(pixmap.cacheKey()); } -void QGLBlurTextureCache::clearBlurTextureInfo(const QPixmap &pixmap) +void QGLBlurTextureCache::clearBlurTextureInfo(quint64 cacheKey) { - cache.remove(pixmap.cacheKey()); + cache.remove(cacheKey); } -bool QGLBlurTextureCache::hasBlurTextureInfo(const QPixmap &pixmap) const +bool QGLBlurTextureCache::hasBlurTextureInfo(quint64 cacheKey) const { - return cache.contains(pixmap.cacheKey()); + return cache.contains(cacheKey); } void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info) { static bool hookAdded = false; if (!hookAdded) { - QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(pixmapDestroyed); + QImagePixmapCleanupHooks::instance()->addPixmapDataDestructionHook(pixmapDestroyed); hookAdded = true; } @@ -406,11 +406,11 @@ void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTe timerId = startTimer(8000); } -void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap) +void QGLBlurTextureCache::pixmapDestroyed(QPixmapData *pmd) { foreach (QGLBlurTextureCache *cache, blurTextureCaches) { - if (cache->hasBlurTextureInfo(*pixmap)) - cache->clearBlurTextureInfo(*pixmap); + if (cache->hasBlurTextureInfo(pmd->cacheKey())) + cache->clearBlurTextureInfo(pmd->cacheKey()); } } diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp index 6f049be..6cd7841 100644 --- a/src/plugins/imageformats/gif/qgifhandler.cpp +++ b/src/plugins/imageformats/gif/qgifhandler.cpp @@ -72,6 +72,7 @@ public: int decode(QImage *image, const uchar* buffer, int length, int *nextFrameDelay, int *loopCount, QSize *nextSize); + static int imageCount(QIODevice *device); bool newFrame; bool partialNewFrame; @@ -645,6 +646,234 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, return initial-length; } +/*! + Returns the number of images that can be read from \a device. +*/ + +int QGIFFormat::imageCount(QIODevice *device) +{ + if (!device) + return 0; + + qint64 oldPos = device->pos(); + if (!device->seek(0)) + return 0; + + int colorCount = 0; + int localColorCount = 0; + int globalColorCount = 0; + int colorReadCount = 0; + bool localColormap = false; + bool globalColormap = false; + int count = 0; + int blockSize = 0; + bool done = false; + uchar hold[16]; + int imageCount = 0; + State state = Header; + + const int readBufferSize = 40960; // 40k read buffer + QByteArray readBuffer(device->read(readBufferSize)); + + if (readBuffer.isEmpty()) + return 0; + + // this is a specialized version of the state machine from decode(), + // which doesn't do any image decoding or mallocing, and has an + // optimized way of skipping SkipBlocks, ImageDataBlocks and + // Global/LocalColorMaps. + + while (!readBuffer.isEmpty()) { + int length = readBuffer.size(); + const uchar *buffer = (const uchar *) readBuffer.constData(); + while (!done && length) { + length--; + uchar ch = *buffer++; + switch (state) { + case Header: + hold[count++] = ch; + if (count == 6) { + state = LogicalScreenDescriptor; + count = 0; + } + break; + case LogicalScreenDescriptor: + hold[count++] = ch; + if (count == 7) { + globalColormap = !!(hold[4] & 0x80); + globalColorCount = 2 << (hold[4] & 0x7); + count = 0; + colorCount = globalColorCount; + if (globalColormap) { + int colorTableSize = 3 * globalColorCount; + if (length >= colorTableSize) { + // skip the global color table in one go + length -= colorTableSize; + buffer += colorTableSize; + state = Introducer; + } else { + colorReadCount = 0; + state = GlobalColorMap; + } + } else { + state=Introducer; + } + } + break; + case GlobalColorMap: + case LocalColorMap: + hold[count++] = ch; + if (count == 3) { + if (++colorReadCount >= colorCount) { + if (state == LocalColorMap) + state = TableImageLZWSize; + else + state = Introducer; + } + count = 0; + } + break; + case Introducer: + hold[count++] = ch; + switch (ch) { + case 0x2c: + state = ImageDescriptor; + break; + case 0x21: + state = ExtensionLabel; + break; + case 0x3b: + state = Done; + break; + default: + done = true; + state = Error; + } + break; + case ImageDescriptor: + hold[count++] = ch; + if (count == 10) { + localColormap = !!(hold[9] & 0x80); + localColorCount = localColormap ? (2 << (hold[9] & 0x7)) : 0; + if (localColorCount) + colorCount = localColorCount; + else + colorCount = globalColorCount; + imageCount++; + + count = 0; + if (localColormap) { + int colorTableSize = 3 * localColorCount; + if (length >= colorTableSize) { + // skip the local color table in one go + length -= colorTableSize; + buffer += colorTableSize; + state = TableImageLZWSize; + } else { + colorReadCount = 0; + state = LocalColorMap; + } + } else { + state = TableImageLZWSize; + } + } + break; + case TableImageLZWSize: + if (ch > max_lzw_bits) + state = Error; + else + state = ImageDataBlockSize; + count = 0; + break; + case ImageDataBlockSize: + blockSize = ch; + if (blockSize) { + if (length >= blockSize) { + // we can skip the block in one go + length -= blockSize; + buffer += blockSize; + count = 0; + } else { + state = ImageDataBlock; + } + } else { + state = Introducer; + } + break; + case ImageDataBlock: + ++count; + if (count == blockSize) { + count = 0; + state = ImageDataBlockSize; + } + break; + case ExtensionLabel: + switch (ch) { + case 0xf9: + state = GraphicControlExtension; + break; + case 0xff: + state = ApplicationExtension; + break; + default: + state = SkipBlockSize; + } + count = 0; + break; + case ApplicationExtension: + if (count < 11) + hold[count] = ch; + ++count; + if (count == hold[0] + 1) { + state = SkipBlockSize; + count = 0; + } + break; + case GraphicControlExtension: + if (count < 5) + hold[count] = ch; + ++count; + if (count == hold[0] + 1) { + count = 0; + state = SkipBlockSize; + } + break; + case NetscapeExtensionBlockSize: // fallthrough + case SkipBlockSize: + blockSize = ch; + count = 0; + if (blockSize) { + if (length >= blockSize) { + // we can skip the block in one go + length -= blockSize; + buffer += blockSize; + } else { + state = SkipBlock; + } + } else { + state = Introducer; + } + break; + case NetscapeExtensionBlock: // fallthrough + case SkipBlock: + ++count; + if (count == blockSize) + state = SkipBlockSize; + break; + case Done: + done = true; + break; + case Error: + device->seek(oldPos); + return 0; + } + } + readBuffer = device->read(readBufferSize); + } + device->seek(oldPos); + return imageCount; +} + void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb color) { if (w>0) { @@ -766,6 +995,7 @@ QGifHandler::QGifHandler() loopCnt = 0; frameNumber = -1; nextSize = QSize(); + imageCnt = -1; } QGifHandler::~QGifHandler() @@ -883,7 +1113,10 @@ int QGifHandler::nextImageDelay() const int QGifHandler::imageCount() const { - return 0; // Don't know + if (imageCnt != -1) + return imageCnt; + imageCnt = QGIFFormat::imageCount(device()); + return imageCnt; } int QGifHandler::loopCount() const diff --git a/src/plugins/imageformats/gif/qgifhandler.h b/src/plugins/imageformats/gif/qgifhandler.h index a6e520f..830cd38 100644 --- a/src/plugins/imageformats/gif/qgifhandler.h +++ b/src/plugins/imageformats/gif/qgifhandler.h @@ -88,6 +88,7 @@ private: mutable int loopCnt; int frameNumber; mutable QSize nextSize; + mutable int imageCnt; }; QT_END_NAMESPACE diff --git a/tests/auto/qgl/qgl.pro b/tests/auto/qgl/qgl.pro index 420c4bb..9116f39 100644 --- a/tests/auto/qgl/qgl.pro +++ b/tests/auto/qgl/qgl.pro @@ -6,6 +6,6 @@ load(qttest_p4) requires(contains(QT_CONFIG,opengl)) QT += opengl -SOURCES += tst_qgl.cpp - +SOURCES += tst_qgl.cpp +RESOURCES = qgl.qrc diff --git a/tests/auto/qgl/qgl.qrc b/tests/auto/qgl/qgl.qrc new file mode 100644 index 0000000..653794a --- /dev/null +++ b/tests/auto/qgl/qgl.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file alias="designer.png">../qpixmap/images/designer.png</file> +</qresource> +</RCC> diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp index cf4616e..d37d727 100644 --- a/tests/auto/qgl/tst_qgl.cpp +++ b/tests/auto/qgl/tst_qgl.cpp @@ -56,6 +56,7 @@ #ifdef QT_BUILD_INTERNAL #include <QtOpenGL/private/qgl_p.h> +#include <QtGui/private/qpixmapdata_p.h> #endif //TESTED_CLASS= @@ -91,6 +92,8 @@ private slots: void clipTest(); void destroyFBOAfterContext(); void shareRegister(); + void qglContextDefaultBindTexture(); + void textureCleanup(); }; tst_QGL::tst_QGL() @@ -1938,5 +1941,242 @@ void tst_QGL::shareRegister() #endif } +// Tests QGLContext::bindTexture with default options +void tst_QGL::qglContextDefaultBindTexture() +{ +#ifdef QT_BUILD_INTERNAL + QGLWidget w; + w.makeCurrent(); + + QGLContext *ctx = const_cast<QGLContext*>(w.context()); + + QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32); + boundImage->fill(0xFFFFFFFF); + QPixmap *boundPixmap = new QPixmap(256, 256); + boundPixmap->fill(Qt::red); + + // Check that calling QGLContext::bindTexture with default args adds textures to cache + int startCacheItemCount = QGLTextureCache::instance()->size(); + GLuint boundImageTextureId = ctx->bindTexture(*boundImage); + GLuint boundPixmapTextureId = ctx->bindTexture(*boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Make sure the texture IDs returned are valid: + QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_TRUE); + QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_TRUE); + + // Make sure the textures are still there after we delete the image/pixmap: + delete boundImage; + boundImage = 0; + delete boundPixmap; + boundPixmap = 0; + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Make sure the textures are deleted from the cache after calling QGLContext::deleteTexture() + ctx->deleteTexture(boundImageTextureId); + ctx->deleteTexture(boundPixmapTextureId); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + // Finally, make sure QGLContext::deleteTexture also deleted the texture IDs: + QCOMPARE((bool)glIsTexture(boundImageTextureId), GL_FALSE); + QCOMPARE((bool)glIsTexture(boundPixmapTextureId), GL_FALSE); +#endif +} + +void tst_QGL::textureCleanup() +{ +#ifdef QT_BUILD_INTERNAL + QGLWidget w; + w.resize(200,200); + w.show(); + w.makeCurrent(); + + // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache + // when the pixmap cache is cleared + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QPixmap boundPixmap(":designer.png"); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Check that the texture doesn't get removed from the cache when the pixmap is cleared + // as it should still be in the cache: + boundPixmap = QPixmap(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + QPixmapCache::clear(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache + // when they are explicitly removed from the pixmap cache + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QPixmap boundPixmap(128, 128); + QString cacheKey = QString::fromLatin1("myPixmap"); + QPixmapCache::insert(cacheKey, boundPixmap); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Check that the texture doesn't get removed from the cache when the pixmap is cleared + // as it should still be in the cache: + boundPixmap = QPixmap(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + // Finally, we check that the texture cache entry is removed when we remove the + // pixmap cache entry, which should hold the last reference: + QPixmapCache::remove(cacheKey); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Check images & pixmaps are removed from the cache when they are deleted + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32); + boundImage->fill(0xFFFFFFFF); + QPixmap *boundPixmap = new QPixmap(256, 256); + boundPixmap->fill(Qt::red); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawImage(0, 0, *boundImage); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + p.drawPixmap(0, 0, *boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + delete boundImage; + boundImage = 0; + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + delete boundPixmap; + boundPixmap = 0; + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Check images & pixmaps are removed from the cache when they are assigned to + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QImage boundImage(256, 256, QImage::Format_RGB32); + boundImage.fill(0xFFFFFFFF); + QPixmap boundPixmap(256, 256); + boundPixmap.fill(Qt::red); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawImage(0, 0, boundImage); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + boundImage = QImage(64, 64, QImage::Format_RGB32); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + boundPixmap = QPixmap(64, 64); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Check images & pixmaps are removed from the cache when they are modified (detached) + { + int startCacheItemCount = QGLTextureCache::instance()->size(); + QPainter p(&w); + + QImage boundImage(256, 256, QImage::Format_RGB32); + boundImage.fill(0xFFFFFFFF); + QPixmap boundPixmap(256, 256); + boundPixmap.fill(Qt::red); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawImage(0, 0, boundImage); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + boundImage.fill(0x00000000); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + boundPixmap.fill(Qt::blue); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + } + + // Check that images/pixmaps aren't removed from the cache if a shallow copy has been made + QImage copyOfImage; + QPixmap copyOfPixmap; + int startCacheItemCount = QGLTextureCache::instance()->size(); + { + QPainter p(&w); + + QImage boundImage(256, 256, QImage::Format_RGB32); + boundImage.fill(0xFFFFFFFF); + QPixmap boundPixmap(256, 256); + boundPixmap.fill(Qt::red); + + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); + + p.drawImage(0, 0, boundImage); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + p.drawPixmap(0, 0, boundPixmap); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + // Need to call end for the GL2 paint engine to release references to pixmap if using tfp + p.end(); + + copyOfImage = boundImage; + copyOfPixmap = boundPixmap; + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + } // boundImage & boundPixmap would have been deleted when they went out of scope + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2); + + copyOfImage = QImage(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1); + + copyOfPixmap = QPixmap(); + QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount); +#endif +} + QTEST_MAIN(tst_QGL) #include "tst_qgl.moc" diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 14b9ef0..7b54a3b 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -251,6 +251,21 @@ public: QBrush brush; }; +class MyGraphicsView : public QGraphicsView +{ +public: + int repaints; + QRegion paintedRegion; + MyGraphicsView(QGraphicsScene *scene) : QGraphicsView(scene), repaints(0) {} + void paintEvent(QPaintEvent *e) + { + paintedRegion += e->region(); + ++repaints; + QGraphicsView::paintEvent(e); + } + void reset() { repaints = 0; paintedRegion = QRegion(); } +}; + class tst_QGraphicsItem : public QObject { Q_OBJECT @@ -419,6 +434,8 @@ private slots: void QTBUG_4233_updateCachedWithSceneRect(); void QTBUG_5418_textItemSetDefaultColor(); void QTBUG_6738_missingUpdateWithSetParent(); + void QTBUG_7714_fullUpdateDiscardingOpacityUpdate2(); + void QT_2653_fullUpdateDiscardingOpacityUpdate(); private: QList<QGraphicsItem *> paintedItems; @@ -3165,7 +3182,6 @@ void tst_QGraphicsItem::childrenBoundingRect() childChild->setPos(500, 500); child->rotate(90); - scene.addPolygon(parent->mapToScene(parent->boundingRect() | parent->childrenBoundingRect()))->setPen(QPen(Qt::red));; QGraphicsView view(&scene); @@ -6252,13 +6268,6 @@ void tst_QGraphicsItem::opacity2() QGraphicsScene scene; scene.addItem(parent); - class MyGraphicsView : public QGraphicsView - { public: - int repaints; - MyGraphicsView(QGraphicsScene *scene) : QGraphicsView(scene), repaints(0) {} - void paintEvent(QPaintEvent *e) { ++repaints; QGraphicsView::paintEvent(e); } - }; - MyGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); @@ -6336,20 +6345,6 @@ void tst_QGraphicsItem::opacityZeroUpdates() QGraphicsScene scene; scene.addItem(parent); - class MyGraphicsView : public QGraphicsView - { public: - int repaints; - QRegion paintedRegion; - MyGraphicsView(QGraphicsScene *scene) : QGraphicsView(scene), repaints(0) {} - void paintEvent(QPaintEvent *e) - { - ++repaints; - paintedRegion += e->region(); - QGraphicsView::paintEvent(e); - } - void reset() { repaints = 0; paintedRegion = QRegion(); } - }; - MyGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); @@ -7076,21 +7071,6 @@ void tst_QGraphicsItem::deviceTransform() QCOMPARE(rect3->deviceTransform(deviceX).map(QPointF(50, 50)), mapResult3); } -class MyGraphicsView : public QGraphicsView -{ -public: - int repaints; - QRegion paintedRegion; - MyGraphicsView(QGraphicsScene *scene) : QGraphicsView(scene), repaints(0) {} - void paintEvent(QPaintEvent *e) - { - paintedRegion += e->region(); - ++repaints; - QGraphicsView::paintEvent(e); - } - void reset() { repaints = 0; paintedRegion = QRegion(); } -}; - void tst_QGraphicsItem::update() { QGraphicsScene scene; @@ -9835,7 +9815,7 @@ void tst_QGraphicsItem::scenePosChange() QCOMPARE(child2->changes.count(QGraphicsItem::ItemScenePositionHasChanged), 0); } -void tst_QGraphicsItem::QTBUG_5418_textItemSetDefaultColor() +void tst_QGraphicsItem::QTBUG_5418_textItemSetDefaultColor() { struct Item : public QGraphicsTextItem { @@ -9914,20 +9894,6 @@ void tst_QGraphicsItem::QTBUG_6738_missingUpdateWithSetParent() QGraphicsScene scene; scene.addItem(parent); - class MyGraphicsView : public QGraphicsView - { public: - int repaints; - QRegion paintedRegion; - MyGraphicsView(QGraphicsScene *scene) : QGraphicsView(scene), repaints(0) {} - void paintEvent(QPaintEvent *e) - { - ++repaints; - paintedRegion += e->region(); - QGraphicsView::paintEvent(e); - } - void reset() { repaints = 0; paintedRegion = QRegion(); } - }; - MyGraphicsView view(&scene); view.show(); QTest::qWaitForWindowShown(&view); @@ -9955,5 +9921,84 @@ void tst_QGraphicsItem::QTBUG_6738_missingUpdateWithSetParent() QTRY_VERIFY(view.repaints == 1); } +void tst_QGraphicsItem::QT_2653_fullUpdateDiscardingOpacityUpdate() +{ + QGraphicsScene scene(0, 0, 200, 200); + MyGraphicsView view(&scene); + + EventTester *parentGreen = new EventTester(); + parentGreen->setGeometry(QRectF(20, 20, 100, 100)); + parentGreen->brush = Qt::green; + + EventTester *childYellow = new EventTester(parentGreen); + childYellow->setGeometry(QRectF(10, 10, 50, 50)); + childYellow->brush = Qt::yellow; + + scene.addItem(parentGreen); + + childYellow->setOpacity(0.0); + parentGreen->setOpacity(0.0); + + // set any of the flags below to trigger a fullUpdate to reproduce the bug: + // ItemIgnoresTransformations, ItemClipsChildrenToShape, ItemIsSelectable + parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations); + + view.show(); + QTest::qWaitForWindowShown(&view); + view.reset(); + + parentGreen->setOpacity(1.0); + + QTRY_COMPARE(view.repaints, 1); + + view.reset(); + childYellow->repaints = 0; + + childYellow->setOpacity(1.0); + + QTRY_COMPARE(view.repaints, 1); + QTRY_COMPARE(childYellow->repaints, 1); +} + +void tst_QGraphicsItem::QTBUG_7714_fullUpdateDiscardingOpacityUpdate2() +{ + QGraphicsScene scene(0, 0, 200, 200); + MyGraphicsView view(&scene); + MyGraphicsView origView(&scene); + + EventTester *parentGreen = new EventTester(); + parentGreen->setGeometry(QRectF(20, 20, 100, 100)); + parentGreen->brush = Qt::green; + + EventTester *childYellow = new EventTester(parentGreen); + childYellow->setGeometry(QRectF(10, 10, 50, 50)); + childYellow->brush = Qt::yellow; + + scene.addItem(parentGreen); + + origView.show(); + QTest::qWaitForWindowShown(&origView); + origView.setGeometry(origView.width() + 20, 20, + origView.width(), origView.height()); + + parentGreen->setFlag(QGraphicsItem::ItemIgnoresTransformations); + + origView.reset(); + childYellow->setOpacity(0.0); + + QTRY_COMPARE(origView.repaints, 1); + + view.show(); + + QTest::qWaitForWindowShown(&view); + view.reset(); + origView.reset(); + + childYellow->setOpacity(1.0); + + QTRY_COMPARE(origView.repaints, 1); + QTRY_COMPARE(view.repaints, 1); +} + QTEST_MAIN(tst_QGraphicsItem) #include "tst_qgraphicsitem.moc" diff --git a/tests/auto/qimagereader/tst_qimagereader.cpp b/tests/auto/qimagereader/tst_qimagereader.cpp index e7cfe68..debc090 100644 --- a/tests/auto/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/qimagereader/tst_qimagereader.cpp @@ -765,6 +765,8 @@ void tst_QImageReader::gifImageCount() QVERIFY(io.canRead()); QImage greenFrame = io.read(); + QVERIFY(io.imageCount() == 4); + QVERIFY(io.canRead()); QImage blueFrame = io.read(); @@ -876,6 +878,10 @@ void tst_QImageReader::gifImageCount() QCOMPARE(blueFrame.size(), QSize(64,64)); QVERIFY(emptyFrame.isNull()); } + { + QImageReader io(":images/trolltech.gif"); + QVERIFY(io.imageCount() == 34); + } } #endif @@ -1641,10 +1647,16 @@ void tst_QImageReader::pixelCompareWithBaseline() { QFETCH(QString, fileName); + static int enteredCount = 0; // Used for better error diagnostics if something fails. We + static int loadFailCount = 0; // don't know if the reason load() fails is that the plugin + // does not exist or because of a bug in the plugin. But if at + // least one file succeeded we know that the plugin was built. + // The other failures are then real failures. QImage icoImg; const QString inputFileName(QString::fromAscii("images/%1").arg(fileName)); QFileInfo fi(inputFileName); + ++enteredCount; // might fail if the plugin does not exist, which is ok. if (icoImg.load(inputFileName)) { icoImg = icoImg.convertToFormat(QImage::Format_ARGB32_Premultiplied); @@ -1658,6 +1670,13 @@ void tst_QImageReader::pixelCompareWithBaseline() QCOMPARE(int(baseImg.format()), int(icoImg.format())); QCOMPARE(baseImg, icoImg); #endif + } else { + ++loadFailCount; + if (enteredCount != loadFailCount) { + QFAIL("Plugin is built, but some did not load properly"); + } else { + qWarning("loading failed, check if ico plugin is built"); + } } } diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp index ea90ae3..1fb323e 100644 --- a/tests/auto/qwidget/tst_qwidget.cpp +++ b/tests/auto/qwidget/tst_qwidget.cpp @@ -396,6 +396,8 @@ private slots: void focusProxyAndInputMethods(); void scrollWithoutBackingStore(); + void taskQTBUG_7532_tabOrderWithFocusProxy(); + private: bool ensureScreenSize(int width, int height); QWidget *testWidget; @@ -9783,5 +9785,17 @@ void tst_QWidget::scrollWithoutBackingStore() QCOMPARE(child.pos(),QPoint(25,25)); } +void tst_QWidget::taskQTBUG_7532_tabOrderWithFocusProxy() +{ + QWidget w; + w.setFocusPolicy(Qt::TabFocus); + QWidget *fp = new QWidget(&w); + fp->setFocusPolicy(Qt::TabFocus); + w.setFocusProxy(fp); + QWidget::setTabOrder(&w, fp); + + // No Q_ASSERT, then it's allright. +} + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" |