diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-09-23 07:25:18 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-09-23 07:25:18 (GMT) |
commit | 932e67e3e817f0e2625ff60594e6e536920a329a (patch) | |
tree | c63afe16124bb3af2429b7cf04afaa65760ad600 | |
parent | 979ab9bf9394210dc4812082fe40b083155447c5 (diff) | |
parent | 4f24b2fbe7fbbdae95b27381e258ec7b665445c5 (diff) | |
download | Qt-932e67e3e817f0e2625ff60594e6e536920a329a.zip Qt-932e67e3e817f0e2625ff60594e6e536920a329a.tar.gz Qt-932e67e3e817f0e2625ff60594e6e536920a329a.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/oslo-staging-2:
QPainter not restored correctly in Graphics View.
Setting QGraphicsItem::ItemClipsChildrenToShape forces ItemClipsToShape
Fix compilation
Fixed drawing of QPixmaps with masks in the GL 2 and X11 engines.
Fix warning on MSVC
QThread: make sure start works even if called after exit
Revert "Fixed painter path drawing on FBO without stencil buffer."
Fix a crash with D&d on mingw
Revert "Keep other text format with QTextOption::SuppressColors tag on"
Fixed stencil buffer on FBOs with OpenGL ES.
Keep other text format with QTextOption::SuppressColors tag on
QTreeView: do not scroll to top if last item is removed
-rw-r--r-- | src/corelib/thread/qthread_unix.cpp | 2 | ||||
-rw-r--r-- | src/corelib/thread/qthread_win.cpp | 2 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 126 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview.cpp | 3 | ||||
-rw-r--r-- | src/gui/image/qpixmap_x11.cpp | 11 | ||||
-rw-r--r-- | src/gui/image/qpixmap_x11_p.h | 1 | ||||
-rw-r--r-- | src/gui/image/qpixmapdata.cpp | 5 | ||||
-rw-r--r-- | src/gui/image/qpixmapdata_p.h | 1 | ||||
-rw-r--r-- | src/gui/itemviews/qtreeview.cpp | 4 | ||||
-rw-r--r-- | src/gui/kernel/qdnd_win.cpp | 12 | ||||
-rw-r--r-- | src/gui/styles/qstylehelper_p.h | 2 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 28 | ||||
-rw-r--r-- | src/opengl/qgl_x11.cpp | 4 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject.cpp | 105 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject_p.h | 5 | ||||
-rw-r--r-- | tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp | 188 | ||||
-rw-r--r-- | tests/auto/qgraphicsview/tst_qgraphicsview.cpp | 48 | ||||
-rw-r--r-- | tests/auto/qthread/tst_qthread.cpp | 41 | ||||
-rw-r--r-- | tests/auto/qtreeview/tst_qtreeview.cpp | 22 |
19 files changed, 493 insertions, 117 deletions
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 2824e15..a7601b6 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -514,6 +514,8 @@ void QThread::start(Priority priority) d->running = true; d->finished = false; d->terminated = false; + d->returnCode = 0; + d->exited = false; pthread_attr_t attr; pthread_attr_init(&attr); diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 37d5b87..f0cbe8d 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -405,6 +405,8 @@ void QThread::start(Priority priority) d->running = true; d->finished = false; d->terminated = false; + d->exited = false; + d->returnCode = 0; /* NOTE: we create the thread in the suspended state, set the diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 54fdf3f..8dc15bf 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -4814,6 +4814,27 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * } } +static inline void setClip(QPainter *painter, QGraphicsItem *item) +{ + painter->save(); + QRectF clipRect; + const QPainterPath clipPath(item->shape()); + if (QPathClipper::pathToRect(clipPath, &clipRect)) + painter->setClipRect(clipRect, Qt::IntersectClip); + else + painter->setClipPath(clipPath, Qt::IntersectClip); +} + +static inline void setWorldTransform(QPainter *painter, const QTransform *const transformPtr, + const QTransform *effectTransform) +{ + Q_ASSERT(transformPtr); + if (effectTransform) + painter->setWorldTransform(*transformPtr * *effectTransform); + else + painter->setWorldTransform(*transformPtr); +} + void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform, const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget, qreal opacity, const QTransform *effectTransform, @@ -4822,36 +4843,37 @@ void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const Q const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity); const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); const bool itemHasChildren = !item->d_ptr->children.isEmpty(); + bool setChildClip = itemClipsChildrenToShape; + bool itemHasChildrenStackedBehind = false; int i = 0; if (itemHasChildren) { + if (itemClipsChildrenToShape) + setWorldTransform(painter, transformPtr, effectTransform); + item->d_ptr->ensureSortedChildren(); + // Items with the 'ItemStacksBehindParent' flag are put in front of the list + // so all we have to do is to check the first item. + itemHasChildrenStackedBehind = (item->d_ptr->children.at(0)->d_ptr->flags + & QGraphicsItem::ItemStacksBehindParent); - if (itemClipsChildrenToShape) { - painter->save(); - Q_ASSERT(transformPtr); - if (effectTransform) - painter->setWorldTransform(*transformPtr * *effectTransform); - else - painter->setWorldTransform(*transformPtr); - QRectF clipRect; - const QPainterPath clipPath(item->shape()); - if (QPathClipper::pathToRect(clipPath, &clipRect)) - painter->setClipRect(clipRect, Qt::IntersectClip); - else - painter->setClipPath(clipPath, Qt::IntersectClip); - } + if (itemHasChildrenStackedBehind) { + if (itemClipsChildrenToShape) { + setClip(painter, item); + setChildClip = false; + } - // Draw children behind - for (i = 0; i < item->d_ptr->children.size(); ++i) { - QGraphicsItem *child = item->d_ptr->children.at(i); - if (wasDirtyParentSceneTransform) - child->d_ptr->dirtySceneTransform = 1; - if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) - break; - if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) - continue; - drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); + // Draw children behind + for (i = 0; i < item->d_ptr->children.size(); ++i) { + QGraphicsItem *child = item->d_ptr->children.at(i); + if (wasDirtyParentSceneTransform) + child->d_ptr->dirtySceneTransform = 1; + if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) + break; + if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) + continue; + drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); + } } } @@ -4864,38 +4886,50 @@ void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const Q ? *exposedRegion : QRegion(), exposedRegion == 0); const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape; - const bool savePainter = itemClipsToShape || painterStateProtection; - if (savePainter) - painter->save(); + bool restorePainterClip = false; if (!itemHasChildren || !itemClipsChildrenToShape) { - if (effectTransform) - painter->setWorldTransform(*transformPtr * *effectTransform); - else - painter->setWorldTransform(*transformPtr); + // Item does not have children or clip children to shape. + setWorldTransform(painter, transformPtr, effectTransform); + if ((restorePainterClip = itemClipsToShape)) + setClip(painter, item); + } else if (itemHasChildrenStackedBehind){ + // Item clips children to shape and has children stacked behind, which means + // the painter is already clipped to the item's shape. + if (itemClipsToShape) { + // The clip is already correct. Ensure correct world transform. + setWorldTransform(painter, transformPtr, effectTransform); + } else { + // Remove clip (this also ensures correct world transform). + painter->restore(); + setChildClip = true; + } + } else if (itemClipsToShape) { + // Item clips children and itself to shape. It does not have hildren stacked + // behind, which means the clip has not yet been set. We set it now and re-use it + // for the children. + setClip(painter, item); + setChildClip = false; } - if (itemClipsToShape) { - QRectF clipRect; - const QPainterPath clipPath(item->shape()); - if (QPathClipper::pathToRect(clipPath, &clipRect)) - painter->setClipRect(clipRect, Qt::IntersectClip); - else - painter->setClipPath(clipPath, Qt::IntersectClip); - } - painter->setOpacity(opacity); + if (painterStateProtection && !restorePainterClip) + painter->save(); + painter->setOpacity(opacity); if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget) item->paint(painter, &styleOptionTmp, widget); else drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection); - if (savePainter) + if (painterStateProtection || restorePainterClip) painter->restore(); } // Draw children in front if (itemHasChildren) { + if (setChildClip) + setClip(painter, item); + for (; i < item->d_ptr->children.size(); ++i) { QGraphicsItem *child = item->d_ptr->children.at(i); if (wasDirtyParentSceneTransform) @@ -4904,11 +4938,11 @@ void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const Q continue; drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); } - } - // Restore child clip - if (itemHasChildren && itemClipsChildrenToShape) - painter->restore(); + // Restore child clip + if (itemClipsChildrenToShape) + painter->restore(); + } } void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren, @@ -5271,6 +5305,7 @@ void QGraphicsScene::drawItems(QPainter *painter, if (!d->unpolishedItems.isEmpty()) d->_q_polishItems(); + const qreal opacity = painter->opacity(); QTransform viewTransform = painter->worldTransform(); Q_UNUSED(options); @@ -5304,6 +5339,7 @@ void QGraphicsScene::drawItems(QPainter *painter, topLevelItems.at(i)->d_ptr->itemDiscovered = 0; painter->setWorldTransform(viewTransform); + painter->setOpacity(opacity); } /*! diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index c8aca80..a566c8e 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -3475,7 +3475,8 @@ void QGraphicsView::paintEvent(QPaintEvent *event) // IndirectPainting (the else branch), because in that case we always save() // and restore() in QGraphicsScene::drawItems(). if (!d->scene->d_func()->painterStateProtection) - painter.setWorldTransform(viewTransform); + painter.setOpacity(1.0); + painter.setWorldTransform(viewTransform); } else { // Make sure we don't have unpolished items before we draw if (!d->scene->d_func()->unpolishedItems.isEmpty()) diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp index 3d9c363..32676ba 100644 --- a/src/gui/image/qpixmap_x11.cpp +++ b/src/gui/image/qpixmap_x11.cpp @@ -1321,6 +1321,15 @@ QBitmap QX11PixmapData::mask() const return mask; } +bool QX11PixmapData::hasMask() const +{ + return +#ifndef QT_NO_XRENDER + (picture && d == 32) || +#endif + (d == 1) || x11_mask; +} + /*! Sets a mask bitmap. @@ -1549,7 +1558,7 @@ QImage QX11PixmapData::toImage(const QRect &rect) const if (!xiWrapper.xi) return QImage(); - if (canTakeQImageFromXImage(xiWrapper)) + if (!x11_mask && canTakeQImageFromXImage(xiWrapper)) return takeQImageFromXImage(xiWrapper); QImage image = toImage(xiWrapper, rect); diff --git a/src/gui/image/qpixmap_x11_p.h b/src/gui/image/qpixmap_x11_p.h index 821fb69..fcad1a2 100644 --- a/src/gui/image/qpixmap_x11_p.h +++ b/src/gui/image/qpixmap_x11_p.h @@ -82,6 +82,7 @@ public: void fill(const QColor &color); QBitmap mask() const; + bool hasMask() const; void setMask(const QBitmap &mask); bool hasAlphaChannel() const; void setAlphaChannel(const QPixmap &alphaChannel); diff --git a/src/gui/image/qpixmapdata.cpp b/src/gui/image/qpixmapdata.cpp index ef1f6c4..2813ed1 100644 --- a/src/gui/image/qpixmapdata.cpp +++ b/src/gui/image/qpixmapdata.cpp @@ -239,6 +239,11 @@ QBitmap QPixmapData::mask() const return QBitmap::fromImage(mask); } +bool QPixmapData::hasMask() const +{ + return hasAlphaChannel(); +} + QPixmap QPixmapData::transformed(const QTransform &matrix, Qt::TransformationMode mode) const { diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h index ec62b0b..c341930 100644 --- a/src/gui/image/qpixmapdata_p.h +++ b/src/gui/image/qpixmapdata_p.h @@ -99,6 +99,7 @@ public: virtual int metric(QPaintDevice::PaintDeviceMetric metric) const = 0; virtual void fill(const QColor &color) = 0; virtual QBitmap mask() const; + virtual bool hasMask() const; virtual void setMask(const QBitmap &mask); virtual bool hasAlphaChannel() const = 0; virtual QPixmap transformed(const QTransform &matrix, diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index b797776..40b51fe 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -3435,6 +3435,10 @@ void QTreeViewPrivate::updateScrollBars() if (!viewportSize.isValid()) viewportSize = QSize(0, 0); + if (viewItems.isEmpty()) { + q->doItemsLayout(); + } + int itemsInViewport = 0; if (uniformRowHeights) { if (defaultItemHeight <= 0) diff --git a/src/gui/kernel/qdnd_win.cpp b/src/gui/kernel/qdnd_win.cpp index a164c2a..7083886 100644 --- a/src/gui/kernel/qdnd_win.cpp +++ b/src/gui/kernel/qdnd_win.cpp @@ -515,7 +515,7 @@ static inline Qt::MouseButtons keystate_to_mousebutton(DWORD grfKeyState) //--------------------------------------------------------------------- // IDropSource Methods //--------------------------------------------------------------------- -STDMETHODIMP +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) { #ifdef QDND_DEBUG @@ -545,7 +545,7 @@ QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) } } -STDMETHODIMP +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QOleDropSource::GiveFeedback(DWORD dwEffect) { Qt::DropAction action = translateToQDragDropAction(dwEffect); @@ -626,7 +626,7 @@ QOleDropTarget::Release(void) // IDropTarget Methods //--------------------------------------------------------------------- -STDMETHODIMP +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) { #ifdef QDND_DEBUG @@ -688,7 +688,7 @@ void QOleDropTarget::sendDragEnterEvent(QWidget *dragEnterWidget, DWORD grfKeySt } -STDMETHODIMP +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) { #ifdef QDND_DEBUG @@ -758,7 +758,7 @@ QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) return NOERROR; } -STDMETHODIMP +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QOleDropTarget::DragLeave() { #ifdef QDND_DEBUG @@ -785,7 +785,7 @@ QOleDropTarget::DragLeave() #define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) -STDMETHODIMP +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) { #ifdef QDND_DEBUG diff --git a/src/gui/styles/qstylehelper_p.h b/src/gui/styles/qstylehelper_p.h index 71fce55..3759929 100644 --- a/src/gui/styles/qstylehelper_p.h +++ b/src/gui/styles/qstylehelper_p.h @@ -108,7 +108,7 @@ template <typename T> { typedef HexString<T> type; enum { ExactSize = true }; - static int size(const HexString<T> &str) { return sizeof(str.val) * 2; } + static int size(const HexString<T> &) { return sizeof(T) * 2; } static inline void appendTo(const HexString<T> &str, QChar *&out) { str.write(out); } }; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 2347e66..6eb5a36 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -866,32 +866,6 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) if (do_vectorpath_cache) path.makeCacheable(); - if (!device->format().stencil()) { - // If there is no stencil buffer, triangulate the path instead. - - QRectF bbox = path.controlPointRect(); - // If the path doesn't fit within these limits, it is possible that the triangulation will fail. - bool withinLimits = (bbox.left() > -0x8000 * inverseScale) - && (bbox.right() < 0x8000 * inverseScale) - && (bbox.top() > -0x8000 * inverseScale) - && (bbox.bottom() < 0x8000 * inverseScale); - if (withinLimits) { - QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale)); - - QVarLengthArray<float> vertices(polys.vertices.size()); - for (int i = 0; i < polys.vertices.size(); ++i) - vertices[i] = float(inverseScale * polys.vertices.at(i)); - - prepareForDraw(currentBrush.isOpaque()); - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData()); - glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.constData()); - } else { - // We can't handle big, concave painter paths with OpenGL without stencil buffer. - qWarning("Painter path exceeds +/-32767 pixels."); - } - return; - } - // The path is too complicated & needs the stencil technique vertexCoordinateArray.clear(); vertexCoordinateArray.addPath(path, inverseScale, false); @@ -1340,7 +1314,7 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c QGLRect srcRect(src.left(), top, src.right(), bottom); bool isBitmap = pixmap.isQBitmap(); - bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel(); + bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel() && !pixmap.pixmapData()->hasMask(); d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index f3a4c95..7f4c670 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -1776,6 +1776,10 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pixmap, cons QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pixmap->data_ptr().data()); Q_ASSERT(pixmapData->classId() == QPixmapData::X11Class); + // We can't use TFP if the pixmap has a separate X11 mask + if (pixmapData->x11_mask) + return 0; + if (!qt_resolveTextureFromPixmap(paintDevice)) return 0; diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index adbba85..6c9b288 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -324,10 +324,6 @@ void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f, fboFormat.setStencil(true); } else if (attachment == QGLFramebufferObject::Depth) { fboFormat.setDepth(true); - fboFormat.setStencil(false); - } else { - fboFormat.setDepth(false); - fboFormat.setStencil(false); } GLenum format = f->format().internalTextureFormat(); @@ -472,13 +468,17 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples); } + // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a + // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer + // might not be supported while separate buffers are, according to QTBUG-12861. + if (attachment == QGLFramebufferObject::CombinedDepthStencil && (QGLExtensions::glExtensions() & QGLExtensions::PackedDepthStencil)) { // depth and stencil buffer needs another extension - glGenRenderbuffers(1, &depth_stencil_buffer); - Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer)); - glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer); - Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer)); + glGenRenderbuffers(1, &depth_buffer); + Q_ASSERT(!glIsRenderbuffer(depth_buffer)); + glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_buffer); + Q_ASSERT(glIsRenderbuffer(depth_buffer)); if (samples != 0 && glRenderbufferStorageMultisampleEXT) glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, GL_DEPTH24_STENCIL8_EXT, size.width(), size.height()); @@ -486,24 +486,26 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, size.width(), size.height()); - GLint i = 0; - glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i); + stencil_buffer = depth_buffer; glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, depth_stencil_buffer); + GL_RENDERBUFFER_EXT, depth_buffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, depth_stencil_buffer); - fbo_attachment = QGLFramebufferObject::CombinedDepthStencil; + GL_RENDERBUFFER_EXT, stencil_buffer); valid = checkFramebufferStatus(); - if (!valid) - glDeleteRenderbuffers(1, &depth_stencil_buffer); - } else if (attachment == QGLFramebufferObject::Depth - || attachment == QGLFramebufferObject::CombinedDepthStencil) + if (!valid) { + glDeleteRenderbuffers(1, &depth_buffer); + stencil_buffer = depth_buffer = 0; + } + } + + if (depth_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil + || (attachment == QGLFramebufferObject::Depth))) { - glGenRenderbuffers(1, &depth_stencil_buffer); - Q_ASSERT(!glIsRenderbuffer(depth_stencil_buffer)); - glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_stencil_buffer); - Q_ASSERT(glIsRenderbuffer(depth_stencil_buffer)); + glGenRenderbuffers(1, &depth_buffer); + Q_ASSERT(!glIsRenderbuffer(depth_buffer)); + glBindRenderbuffer(GL_RENDERBUFFER_EXT, depth_buffer); + Q_ASSERT(glIsRenderbuffer(depth_buffer)); if (samples != 0 && glRenderbufferStorageMultisampleEXT) { #ifdef QT_OPENGL_ES #define GL_DEPTH_COMPONENT16 0x81A5 @@ -521,14 +523,53 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height()); #endif } - GLint i = 0; - glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &i); glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, depth_stencil_buffer); - fbo_attachment = QGLFramebufferObject::Depth; + GL_RENDERBUFFER_EXT, depth_buffer); valid = checkFramebufferStatus(); - if (!valid) - glDeleteRenderbuffers(1, &depth_stencil_buffer); + if (!valid) { + glDeleteRenderbuffers(1, &depth_buffer); + depth_buffer = 0; + } + } + + if (stencil_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil)) { + glGenRenderbuffers(1, &stencil_buffer); + Q_ASSERT(!glIsRenderbuffer(stencil_buffer)); + glBindRenderbuffer(GL_RENDERBUFFER_EXT, stencil_buffer); + Q_ASSERT(glIsRenderbuffer(stencil_buffer)); + if (samples != 0 && glRenderbufferStorageMultisampleEXT) { +#ifdef QT_OPENGL_ES + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, + GL_STENCIL_INDEX8_EXT, size.width(), size.height()); +#else + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, + GL_STENCIL_INDEX, size.width(), size.height()); +#endif + } else { +#ifdef QT_OPENGL_ES + glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, + size.width(), size.height()); +#else + glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, + size.width(), size.height()); +#endif + } + glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, stencil_buffer); + valid = checkFramebufferStatus(); + if (!valid) { + glDeleteRenderbuffers(1, &stencil_buffer); + stencil_buffer = 0; + } + } + + // The FBO might have become valid after removing the depth or stencil buffer. + valid = checkFramebufferStatus(); + + if (depth_buffer && stencil_buffer) { + fbo_attachment = QGLFramebufferObject::CombinedDepthStencil; + } else if (depth_buffer) { + fbo_attachment = QGLFramebufferObject::Depth; } else { fbo_attachment = QGLFramebufferObject::NoAttachment; } @@ -539,6 +580,10 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, glDeleteRenderbuffers(1, &color_buffer); else glDeleteTextures(1, &texture); + if (depth_buffer) + glDeleteRenderbuffers(1, &depth_buffer); + if (stencil_buffer && depth_buffer != stencil_buffer) + glDeleteRenderbuffers(1, &stencil_buffer); glDeleteFramebuffers(1, &fbo); fbo_guard.setId(0); } @@ -821,8 +866,10 @@ QGLFramebufferObject::~QGLFramebufferObject() glDeleteTextures(1, &d->texture); if (d->color_buffer) glDeleteRenderbuffers(1, &d->color_buffer); - if (d->depth_stencil_buffer) - glDeleteRenderbuffers(1, &d->depth_stencil_buffer); + if (d->depth_buffer) + glDeleteRenderbuffers(1, &d->depth_buffer); + if (d->stencil_buffer && d->stencil_buffer != d->depth_buffer) + glDeleteRenderbuffers(1, &d->stencil_buffer); GLuint fbo = d->fbo(); glDeleteFramebuffers(1, &fbo); } diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h index d8ff012..58b4e9e 100644 --- a/src/opengl/qglframebufferobject_p.h +++ b/src/opengl/qglframebufferobject_p.h @@ -126,7 +126,7 @@ private: class QGLFramebufferObjectPrivate { public: - QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_stencil_buffer(0) + QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_buffer(0), stencil_buffer(0) , color_buffer(0), valid(false), engine(0) {} ~QGLFramebufferObjectPrivate() {} @@ -136,7 +136,8 @@ public: bool checkFramebufferStatus() const; QGLSharedResourceGuard fbo_guard; GLuint texture; - GLuint depth_stencil_buffer; + GLuint depth_buffer; + GLuint stencil_buffer; GLuint color_buffer; GLenum target; QSize size; diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp index 4476084..25ec040 100644 --- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp +++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp @@ -377,6 +377,7 @@ private slots: void itemClipsChildrenToShape2(); void itemClipsChildrenToShape3(); void itemClipsChildrenToShape4(); + void itemClipsChildrenToShape5(); void itemClipsTextChildToShape(); void itemClippingDiscovery(); void ancestorFlags(); @@ -5464,6 +5465,193 @@ void tst_QGraphicsItem::itemClipsChildrenToShape4() QTRY_COMPARE(innerWidget->painted, true); } +//#define DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5 +static inline void renderSceneToImage(QGraphicsScene *scene, QImage *image, const QString &filename) +{ + image->fill(0); + QPainter painter(image); + scene->render(&painter); + painter.end(); +#ifdef DEBUG_ITEM_CLIPS_CHILDREN_TO_SHAPE_5 + image->save(filename); +#else + Q_UNUSED(filename); +#endif +} + +void tst_QGraphicsItem::itemClipsChildrenToShape5() +{ + class ParentItem : public QGraphicsRectItem + { + public: + ParentItem(qreal x, qreal y, qreal width, qreal height) + : QGraphicsRectItem(x, y, width, height) {} + + QPainterPath shape() const + { + QPainterPath path; + path.addRect(50, 50, 200, 200); + return path; + } + }; + + ParentItem *parent = new ParentItem(0, 0, 300, 300); + parent->setBrush(Qt::blue); + parent->setOpacity(0.5); + + const QRegion parentRegion(0, 0, 300, 300); + const QRegion clippedParentRegion = parentRegion & QRect(50, 50, 200, 200); + QRegion childRegion; + QRegion grandChildRegion; + + QGraphicsRectItem *topLeftChild = new QGraphicsRectItem(0, 0, 100, 100); + topLeftChild->setBrush(Qt::red); + topLeftChild->setParentItem(parent); + childRegion += QRect(0, 0, 100, 100); + + QGraphicsRectItem *topRightChild = new QGraphicsRectItem(0, 0, 100, 100); + topRightChild->setBrush(Qt::red); + topRightChild->setParentItem(parent); + topRightChild->setFlag(QGraphicsItem::ItemClipsChildrenToShape); + topRightChild->setPos(200, 0); + childRegion += QRect(200, 0, 100, 100); + + QGraphicsRectItem *topRightGrandChild = new QGraphicsRectItem(0, 0, 100, 100); + topRightGrandChild->setBrush(Qt::green); + topRightGrandChild->setParentItem(topRightChild); + topRightGrandChild->setPos(-40, 40); + grandChildRegion += QRect(200 - 40, 0 + 40, 100, 100) & QRect(200, 0, 100, 100); + + QGraphicsRectItem *bottomLeftChild = new QGraphicsRectItem(0, 0, 100, 100); + bottomLeftChild->setBrush(Qt::red); + bottomLeftChild->setParentItem(parent); + bottomLeftChild->setFlag(QGraphicsItem::ItemClipsToShape); + bottomLeftChild->setPos(0, 200); + childRegion += QRect(0, 200, 100, 100); + + QGraphicsRectItem *bottomLeftGrandChild = new QGraphicsRectItem(0, 0, 160, 160); + bottomLeftGrandChild->setBrush(Qt::green); + bottomLeftGrandChild->setParentItem(bottomLeftChild); + bottomLeftGrandChild->setFlag(QGraphicsItem::ItemClipsToShape); + bottomLeftGrandChild->setPos(0, -60); + grandChildRegion += QRect(0, 200 - 60, 160, 160); + + QGraphicsRectItem *bottomRightChild = new QGraphicsRectItem(0, 0, 100, 100); + bottomRightChild->setBrush(Qt::red); + bottomRightChild->setParentItem(parent); + bottomRightChild->setPos(200, 200); + childRegion += QRect(200, 200, 100, 100); + + QPoint controlPoints[17] = { + QPoint(5, 5) , QPoint(95, 5) , QPoint(205, 5) , QPoint(295, 5) , + QPoint(5, 95) , QPoint(95, 95) , QPoint(205, 95) , QPoint(295, 95) , + QPoint(150, 150), + QPoint(5, 205), QPoint(95, 205), QPoint(205, 205), QPoint(295, 205), + QPoint(5, 295), QPoint(95, 295), QPoint(205, 295), QPoint(295, 295), + }; + + const QRegion clippedChildRegion = childRegion & QRect(50, 50, 200, 200); + const QRegion clippedGrandChildRegion = grandChildRegion & QRect(50, 50, 200, 200); + + QGraphicsScene scene; + scene.addItem(parent); + QImage sceneImage(300, 300, QImage::Format_ARGB32); + +#define VERIFY_CONTROL_POINTS(pRegion, cRegion, gRegion) \ + for (int i = 0; i < 17; ++i) { \ + QPoint controlPoint = controlPoints[i]; \ + QRgb pixel = sceneImage.pixel(controlPoint.x(), controlPoint.y()); \ + if (pRegion.contains(controlPoint)) \ + QVERIFY(qBlue(pixel) != 0); \ + else \ + QVERIFY(qBlue(pixel) == 0); \ + if (cRegion.contains(controlPoint)) \ + QVERIFY(qRed(pixel) != 0); \ + else \ + QVERIFY(qRed(pixel) == 0); \ + if (gRegion.contains(controlPoint)) \ + QVERIFY(qGreen(pixel) != 0); \ + else \ + QVERIFY(qGreen(pixel) == 0); \ + } + + const QList<QGraphicsItem *> children = parent->childItems(); + const int childrenCount = children.count(); + + for (int i = 0; i < 5; ++i) { + QString clipString; + QString childString; + switch (i) { + case 0: + // All children stacked in front. + childString = QLatin1String("ChildrenInFront.png"); + foreach (QGraphicsItem *child, children) + child->setFlag(QGraphicsItem::ItemStacksBehindParent, false); + break; + case 1: + // All children stacked behind. + childString = QLatin1String("ChildrenBehind.png"); + foreach (QGraphicsItem *child, children) + child->setFlag(QGraphicsItem::ItemStacksBehindParent, true); + break; + case 2: + // First half of the children behind, second half in front. + childString = QLatin1String("FirstHalfBehind_SecondHalfInFront.png"); + for (int j = 0; j < childrenCount; ++j) { + QGraphicsItem *child = children.at(j); + child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j < childrenCount / 2)); + } + break; + case 3: + // First half of the children in front, second half behind. + childString = QLatin1String("FirstHalfInFront_SecondHalfBehind.png"); + for (int j = 0; j < childrenCount; ++j) { + QGraphicsItem *child = children.at(j); + child->setFlag(QGraphicsItem::ItemStacksBehindParent, (j >= childrenCount / 2)); + } + break; + case 4: + // Child2 and child4 behind, rest in front. + childString = QLatin1String("Child2And4Behind_RestInFront.png"); + for (int j = 0; j < childrenCount; ++j) { + QGraphicsItem *child = children.at(j); + if (j == 1 || j == 3) + child->setFlag(QGraphicsItem::ItemStacksBehindParent, true); + else + child->setFlag(QGraphicsItem::ItemStacksBehindParent, false); + } + break; + default: + qFatal("internal error"); + } + + // Nothing is clipped. + parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false); + parent->setFlag(QGraphicsItem::ItemClipsToShape, false); + clipString = QLatin1String("nothingClipped_"); + renderSceneToImage(&scene, &sceneImage, clipString + childString); + VERIFY_CONTROL_POINTS(parentRegion, childRegion, grandChildRegion); + + // Parent clips children to shape. + parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape); + clipString = QLatin1String("parentClipsChildrenToShape_"); + renderSceneToImage(&scene, &sceneImage, clipString + childString); + VERIFY_CONTROL_POINTS(parentRegion, clippedChildRegion, clippedGrandChildRegion); + + // Parent clips itself and children to shape. + parent->setFlag(QGraphicsItem::ItemClipsToShape); + clipString = QLatin1String("parentClipsItselfAndChildrenToShape_"); + renderSceneToImage(&scene, &sceneImage, clipString + childString); + VERIFY_CONTROL_POINTS(clippedParentRegion, clippedChildRegion, clippedGrandChildRegion); + + // Parent clips itself to shape. + parent->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false); + clipString = QLatin1String("parentClipsItselfToShape_"); + renderSceneToImage(&scene, &sceneImage, clipString + childString); + VERIFY_CONTROL_POINTS(clippedParentRegion, childRegion, grandChildRegion); + } +} + void tst_QGraphicsItem::itemClipsTextChildToShape() { // Construct a scene with a rect that clips its children, with one text diff --git a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp index 7b5ac7a..af02c55 100644 --- a/tests/auto/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/qgraphicsview/tst_qgraphicsview.cpp @@ -2492,25 +2492,31 @@ void tst_QGraphicsView::optimizationFlags_dontSavePainterState() void tst_QGraphicsView::optimizationFlags_dontSavePainterState2_data() { QTest::addColumn<bool>("savePainter"); - QTest::newRow("With painter state protection") << true; - QTest::newRow("Without painter state protection") << false; + QTest::addColumn<bool>("indirectPainting"); + QTest::newRow("With painter state protection, without indirect painting") << true << false; + QTest::newRow("Without painter state protection, without indirect painting") << false << false; + QTest::newRow("With painter state protectionm, with indirect painting") << true << true; + QTest::newRow("Without painter state protection, with indirect painting") << false << true; } void tst_QGraphicsView::optimizationFlags_dontSavePainterState2() { QFETCH(bool, savePainter); + QFETCH(bool, indirectPainting); class MyScene : public QGraphicsScene { public: void drawBackground(QPainter *p, const QRectF &) - { transformInDrawBackground = p->worldTransform(); } + { transformInDrawBackground = p->worldTransform(); opacityInDrawBackground = p->opacity(); } void drawForeground(QPainter *p, const QRectF &) - { transformInDrawForeground = p->worldTransform(); } + { transformInDrawForeground = p->worldTransform(); opacityInDrawForeground = p->opacity(); } QTransform transformInDrawBackground; QTransform transformInDrawForeground; + qreal opacityInDrawBackground; + qreal opacityInDrawForeground; }; MyScene scene; @@ -2518,9 +2524,13 @@ void tst_QGraphicsView::optimizationFlags_dontSavePainterState2() scene.addRect(0, 0, 20, 20)->setTransform(QTransform::fromScale(2, 2)); scene.addRect(50, 50, 20, 20)->setTransform(QTransform::fromTranslate(200, 200)); + foreach (QGraphicsItem *item, scene.items()) + item->setOpacity(0.6); + CustomView view(&scene); if (!savePainter) view.setOptimizationFlag(QGraphicsView::DontSavePainterState); + view.setOptimizationFlag(QGraphicsView::IndirectPainting, indirectPainting); view.rotate(45); view.scale(1.5, 1.5); view.show(); @@ -2534,10 +2544,38 @@ void tst_QGraphicsView::optimizationFlags_dontSavePainterState2() QVERIFY(view.painted); // Make sure the painter's world transform is preserved after drawItems. - const QTransform expectedTransform = view.viewportTransform(); + QTransform expectedTransform = view.viewportTransform(); QVERIFY(!expectedTransform.isIdentity()); QCOMPARE(scene.transformInDrawForeground, expectedTransform); QCOMPARE(scene.transformInDrawBackground, expectedTransform); + + qreal expectedOpacity = 1.0; + QCOMPARE(scene.opacityInDrawBackground, expectedOpacity); + QCOMPARE(scene.opacityInDrawForeground, expectedOpacity); + + // Trigger more painting, this time from QGraphicsScene::render. + QImage image(scene.sceneRect().size().toSize(), QImage::Format_RGB32); + QPainter painter(&image); + scene.render(&painter); + painter.end(); + + expectedTransform = QTransform(); + QCOMPARE(scene.transformInDrawForeground, expectedTransform); + QCOMPARE(scene.transformInDrawBackground, expectedTransform); + QCOMPARE(scene.opacityInDrawBackground, expectedOpacity); + QCOMPARE(scene.opacityInDrawForeground, expectedOpacity); + + // Trigger more painting with another opacity on the painter. + painter.begin(&image); + painter.setOpacity(0.4); + expectedOpacity = 0.4; + scene.render(&painter); + painter.end(); + + QCOMPARE(scene.transformInDrawForeground, expectedTransform); + QCOMPARE(scene.transformInDrawBackground, expectedTransform); + QCOMPARE(scene.opacityInDrawBackground, expectedOpacity); + QCOMPARE(scene.opacityInDrawForeground, expectedOpacity); } class LodItem : public QGraphicsRectItem diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp index 7a5b053..843749a 100644 --- a/tests/auto/qthread/tst_qthread.cpp +++ b/tests/auto/qthread/tst_qthread.cpp @@ -49,6 +49,7 @@ #include <qtimer.h> #include <qwaitcondition.h> #include <qdebug.h> +#include <qmetaobject.h> #ifdef Q_OS_UNIX #include <pthread.h> @@ -104,6 +105,8 @@ private slots: void adoptedThreadFinished(); void adoptMultipleThreads(); + void QTBUG13810_exitAndStart(); + void stressTest(); }; @@ -934,6 +937,44 @@ void tst_QThread::stressTest() } } +class Syncronizer : public QObject +{ Q_OBJECT +public slots: + void setProp(int p) { + if(m_prop != p) { + m_prop = p; + emit propChanged(p); + } + } +signals: + void propChanged(int); +public: + Syncronizer() : m_prop(42) {} + int m_prop; +}; + +void tst_QThread::QTBUG13810_exitAndStart() +{ + QThread thread; + thread.exit(555); //should do nothing + + thread.start(); + + //test that the thread is running by executing queued connected signal there + Syncronizer sync1; + sync1.moveToThread(&thread); + Syncronizer sync2; + sync2.moveToThread(&thread); + connect(&sync2, SIGNAL(propChanged(int)), &sync1, SLOT(setProp(int)), Qt::QueuedConnection); + connect(&sync1, SIGNAL(propChanged(int)), &thread, SLOT(quit()), Qt::QueuedConnection); + QMetaObject::invokeMethod(&sync2, "setProp", Qt::QueuedConnection , Q_ARG(int, 89)); + QTest::qWait(50); + while(!thread.wait(10)) + QTest::qWait(10); + QCOMPARE(sync2.m_prop, 89); + QCOMPARE(sync1.m_prop, 89); +} + QTEST_MAIN(tst_QThread) #include "tst_qthread.moc" diff --git a/tests/auto/qtreeview/tst_qtreeview.cpp b/tests/auto/qtreeview/tst_qtreeview.cpp index 7e2e800..c7b53e9 100644 --- a/tests/auto/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/qtreeview/tst_qtreeview.cpp @@ -240,6 +240,7 @@ private slots: void taskQTBUG_6450_selectAllWith1stColumnHidden(); void taskQTBUG_9216_setSizeAndUniformRowHeightsWrongRepaint(); void taskQTBUG_11466_keyboardNavigationRegression(); + void taskQTBUG_13567_removeLastItemRegression(); }; class QtTestModel: public QAbstractItemModel @@ -3910,5 +3911,26 @@ void tst_QTreeView::taskQTBUG_11466_keyboardNavigationRegression() QTRY_COMPARE(treeView.currentIndex(), treeView.selectionModel()->selection().indexes().first()); } +void tst_QTreeView::taskQTBUG_13567_removeLastItemRegression() +{ + QtTestModel model(200, 1); + + QTreeView view; + view.setSelectionMode(QAbstractItemView::ExtendedSelection); + view.setModel(&model); + view.show(); + QTest::qWaitForWindowShown(&view); + + view.scrollToBottom(); + QTest::qWait(10); + CHECK_VISIBLE(199, 0); + + view.setCurrentIndex(model.index(199, 0)); + model.removeLastRow(); + QTest::qWait(10); + QCOMPARE(view.currentIndex(), model.index(198, 0)); + CHECK_VISIBLE(198, 0); +} + QTEST_MAIN(tst_QTreeView) #include "tst_qtreeview.moc" |