Fix crash when combining QOpenGLWidget, QStaticText and Qt Quick

Under certain circumstances, if you had a widget with a QOpenGLPaintEngine,
and drew QStaticText into this, and then later had Qt Quick access the same
cache and try to resize it, we would get a crash because the resize function
would have a pointer to the paint engine and try to access its shader manager
(which would now be null, since this is outside the begin()/end() phase of the
paint engine.

The solution is to reset the paint engine pointer to null on the cache once it
has been populated and it is no longer needed.

[ChangeLog][QtGui][Text] Fixed a possible crash when combining QStaticText,
QOpenGLWidget and Qt Quick in the same application.

Task-number: QTBUG-70096
Change-Id: I7383ad7456d1a72499cfcd2da09a5a808d4b3eff
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2018-08-22 13:02:04 +02:00
parent 981b16d9ba
commit f71048a531
3 changed files with 60 additions and 0 deletions

View File

@ -1741,6 +1741,7 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
// we may have to re-bind brush textures after filling in the cache.
brushTextureDirty = (QT_BRUSH_TEXTURE_UNIT == glypchCacheTextureUnit);
}
cache->setPaintEnginePrivate(nullptr);
}
if (cache->width() == 0 || cache->height() == 0)

View File

@ -152,6 +152,11 @@ public:
void clear();
QOpenGL2PaintEngineExPrivate *paintEnginePrivate() const
{
return pex;
}
private:
void setupVertexAttribs();

View File

@ -30,6 +30,7 @@
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QPainter>
#include <QtGui/QScreen>
#include <QtGui/QStaticText>
#include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QGraphicsView>
#include <QtWidgets/QGraphicsScene>
@ -40,6 +41,8 @@
#include <QtTest/QtTest>
#include <QSignalSpy>
#include <private/qguiapplication_p.h>
#include <private/qstatictext_p.h>
#include <private/qopengltextureglyphcache_p.h>
#include <qpa/qplatformintegration.h>
class tst_QOpenGLWidget : public QObject
@ -64,6 +67,10 @@ private slots:
void stackWidgetOpaqueChildIsVisible();
void offscreen();
void offscreenThenOnscreen();
#ifdef QT_BUILD_INTERNAL
void staticTextDanglingPointer();
#endif
};
void tst_QOpenGLWidget::initTestCase()
@ -675,6 +682,53 @@ void tst_QOpenGLWidget::offscreenThenOnscreen()
QVERIFY(image.pixel(30, 40) == qRgb(0, 0, 255));
}
class StaticTextPainterWidget : public QOpenGLWidget
{
public:
StaticTextPainterWidget(QWidget *parent = nullptr)
: QOpenGLWidget(parent)
{
}
void paintEvent(QPaintEvent *)
{
QPainter p(this);
text.setText(QStringLiteral("test"));
p.drawStaticText(0, 0, text);
ctx = QOpenGLContext::currentContext();
}
QStaticText text;
QOpenGLContext *ctx;
};
#ifdef QT_BUILD_INTERNAL
void tst_QOpenGLWidget::staticTextDanglingPointer()
{
QWidget w;
StaticTextPainterWidget *glw = new StaticTextPainterWidget(&w);
w.resize(640, 480);
glw->resize(320, 200);
w.show();
QVERIFY(QTest::qWaitForWindowExposed(&w));
QStaticTextPrivate *d = QStaticTextPrivate::get(&glw->text);
QCOMPARE(d->itemCount, 1);
QFontEngine *fe = d->items->fontEngine();
for (int i = QFontEngine::Format_None; i <= QFontEngine::Format_ARGB; ++i) {
QOpenGLTextureGlyphCache *cache =
(QOpenGLTextureGlyphCache *) fe->glyphCache(glw->ctx,
QFontEngine::GlyphFormat(i),
QTransform());
if (cache != nullptr)
QCOMPARE(cache->paintEnginePrivate(), nullptr);
}
}
#endif
QTEST_MAIN(tst_QOpenGLWidget)
#include "tst_qopenglwidget.moc"