From 78e335408303380310dd59fab421e495cf517ead Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 1 Jun 2015 11:44:37 +0200 Subject: Clip QOpenGLWidget and QQuickWidget correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce support for the widgets' clipRect(). Right now render-to-texture widgets in scroll areas placed close to each other result in broken (non-existent) clipping. Similarly, stack-on-top widgets fail to clip when placed inside a scroll area. This is now corrected and the qopenglwidget example is enhanced to utilize a scroll area. Task-number: QTBUG-45860 Change-Id: I859a63d61a50d64ba9e87244f83c5969dce12337 Reviewed-by: Jørgen Lind --- src/gui/painting/qplatformbackingstore.cpp | 59 ++++++++++++++++++++++-------- src/gui/painting/qplatformbackingstore.h | 4 +- 2 files changed, 47 insertions(+), 16 deletions(-) (limited to 'src/gui') diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 14a9429c71..83077f38ca 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -86,6 +86,7 @@ struct QBackingstoreTextureInfo QWidget *widget; // may be null GLuint textureId; QRect rect; + QRect clipRect; QPlatformTextureList::Flags flags; }; @@ -142,6 +143,12 @@ QRect QPlatformTextureList::geometry(int index) const return d->textures.at(index).rect; } +QRect QPlatformTextureList::clipRect(int index) const +{ + Q_D(const QPlatformTextureList); + return d->textures.at(index).clipRect; +} + void QPlatformTextureList::lock(bool on) { Q_D(QPlatformTextureList); @@ -157,13 +164,15 @@ bool QPlatformTextureList::isLocked() const return d->locked; } -void QPlatformTextureList::appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags) +void QPlatformTextureList::appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, + const QRect &clipRect, Flags flags) { Q_D(QPlatformTextureList); QBackingstoreTextureInfo bi; bi.widget = widget; bi.textureId = textureId; bi.rect = geometry; + bi.clipRect = clipRect; bi.flags = flags; d->textures.append(bi); } @@ -198,7 +207,7 @@ void QPlatformTextureList::clear() #ifndef QT_NO_OPENGL -static QRect deviceRect(const QRect &rect, QWindow *window) +static inline QRect deviceRect(const QRect &rect, QWindow *window) { QRect deviceRect(rect.topLeft() * window->devicePixelRatio(), rect.size() * window->devicePixelRatio()); @@ -219,6 +228,32 @@ static QRegion deviceRegion(const QRegion ®ion, QWindow *window) return deviceRegion; } +static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight) +{ + return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1, + topLeftRect.width(), topLeftRect.height()); +} + +static void blit(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect, + QOpenGLTextureBlitter *blitter) +{ + const QRect rectInWindow = textures->geometry(idx); + QRect clipRect = textures->clipRect(idx); + if (clipRect.isEmpty()) + clipRect = QRect(QPoint(0, 0), rectInWindow.size()); + const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft()); + const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height()); + + const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(deviceRect(clippedRectInWindow, window), + deviceWindowRect); + + const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(deviceRect(srcRect, window), + deviceRect(rectInWindow, window).size(), + QOpenGLTextureBlitter::OriginBottomLeft); + + blitter->blit(textures->textureId(idx), target, source); +} + /*! Flushes the given \a region from the specified \a window onto the screen, and composes it with the specified \a textures. @@ -254,15 +289,12 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i d_ptr->blitter->bind(); - QRect windowRect(QPoint(), window->size() * window->devicePixelRatio()); + const QRect deviceWindowRect = deviceRect(QRect(QPoint(), window->size()), window); // Textures for renderToTexture widgets. for (int i = 0; i < textures->count(); ++i) { - if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { - QRect targetRect = deviceRect(textures->geometry(i), window); - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); - d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); - } + if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) + blit(textures, i, window, deviceWindowRect, d_ptr->blitter); } funcs->glEnable(GL_BLEND); @@ -272,6 +304,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // semi-transparency even when it is not wanted. funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + // Backingstore texture with the normal widgets. GLuint textureId = 0; QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft; if (QPlatformGraphicsBuffer *graphicsBuffer = this->graphicsBuffer()) { @@ -307,7 +340,6 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i origin = QOpenGLTextureBlitter::OriginBottomLeft; textureId = d_ptr->textureId; } else { - // Backingstore texture with the normal widgets. TextureFlags flags = 0; textureId = toTexture(deviceRegion(region, window), &d_ptr->textureSize, &flags); d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0; @@ -316,7 +348,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i } if (textureId) { - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(), d_ptr->textureSize), windowRect); + QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(QRect(QPoint(), d_ptr->textureSize), deviceWindowRect); if (d_ptr->needsSwizzle) d_ptr->blitter->setSwizzleRB(true); d_ptr->blitter->blit(textureId, target, origin); @@ -326,11 +358,8 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. for (int i = 0; i < textures->count(); ++i) { - if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { - QRect targetRect = deviceRect(textures->geometry(i), window); - QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, windowRect); - d_ptr->blitter->blit(textures->textureId(i), target, QOpenGLTextureBlitter::OriginBottomLeft); - } + if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) + blit(textures, i, window, deviceWindowRect, d_ptr->blitter); } funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index ae7314b6d0..5fa7e6dac0 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -82,12 +82,14 @@ public: bool isEmpty() const { return count() == 0; } GLuint textureId(int index) const; QRect geometry(int index) const; + QRect clipRect(int index) const; QWidget *widget(int index); Flags flags(int index) const; void lock(bool on); bool isLocked() const; - void appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, Flags flags = 0); + void appendTexture(QWidget *widget, GLuint textureId, const QRect &geometry, + const QRect &clipRect = QRect(), Flags flags = 0); void clear(); Q_SIGNALS: -- cgit v1.2.3