summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@theqtcompany.com>2016-01-28 15:33:25 +0100
committerJani Heikkinen <jani.heikkinen@theqtcompany.com>2016-02-04 12:58:06 +0000
commit32929885f44bb9621ac8cfa2b5c592b0977a123f (patch)
tree9102f9e61d299f9d5fdd1fafddc26b6030b736a8
parent46b561970579c08af6e2b2df0713f84396e0da0d (diff)
OS X: Fix crash when setting a custom default QSurfaceFormat.
Setting a new default QSurfaceFormat after QtWebEngineCore::initialize() is called, might lead to a crash. This happens when the new surface format has a different OpenGL profile, compared to the profile created by web engine in the RenderWidgetHostViewQtDelegateWidget constructor. The default constructed QSurfaceFormat has an OpenGL Compatibility profile. Inside the Cocoa platform plugin when a new shared OpenGL context is created, it fails to initialize the new context because of the difference in profiles, and thus ultimately creates an unshared context, which leads to a crash. Fix consists in using the shared context QSurfaceFormat in the RenderWidgetHostViewQtDelegateWidget constructor, and also printing a fatal warning to notify the developer only to set the new QSurfaceFormat before the application instance is declared. Bottom line, if the QSurfaceFormat OpenGL profile has to be changed, it should be done before QtWebEngineCore::initialize() is called. Doing so after initialize() is called, will lead to a crash. Change-Id: I8a07211b592143d736b001556b944d4759802396 Task-number: QTBUG-50665 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> Reviewed-by: Michal Klocek <michal.klocek@theqtcompany.com>
-rw-r--r--src/webengine/doc/src/qtwebengine-platform-notes.qdoc10
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.cpp15
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp21
-rw-r--r--tests/auto/quick/qquickwebenginedefaultsurfaceformat/qquickwebenginedefaultsurfaceformat.pro6
-rw-r--r--tests/auto/quick/qquickwebenginedefaultsurfaceformat/tst_qquickwebenginedefaultsurfaceformat.cpp148
-rw-r--r--tests/auto/quick/quick.pro1
-rw-r--r--tests/auto/widgets/qwebenginedefaultsurfaceformat/qwebenginedefaultsurfaceformat.pro1
-rw-r--r--tests/auto/widgets/qwebenginedefaultsurfaceformat/resources/index.html6
-rw-r--r--tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp77
-rw-r--r--tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.qrc5
-rw-r--r--tests/auto/widgets/widgets.pro1
11 files changed, 291 insertions, 0 deletions
diff --git a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc
index 3e30e960..f177c959 100644
--- a/src/webengine/doc/src/qtwebengine-platform-notes.qdoc
+++ b/src/webengine/doc/src/qtwebengine-platform-notes.qdoc
@@ -116,4 +116,14 @@
be configured for use with several codecs, which rises licensing issues during distribution
with the codec libraries. For some codecs, open source implementations, such as \l {OpenH264},
are available.
+
+ \section1 Default QSurfaceFormat OpenGL Profile Support
+
+ If a new default QSurfaceFormat with a modified OpenGL profile has to be set, it should be set
+ before the application instance is declared, to make sure that all created OpenGL contexts use
+ the same OpenGL profile.
+
+ On OS X, if the default QSurfaceFormat is set after the application instance, the application
+ will exit with qFatal(), and print a message that the default QSurfaceFormat should be set
+ before the application instance.
*/
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
index 508420cf..b667bbc5 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
@@ -41,6 +41,7 @@
#include <QGuiApplication>
#include <QQuickPaintedItem>
#include <QQuickWindow>
+#include <QSurfaceFormat>
#include <QVariant>
#include <QWindow>
#include <private/qquickwindow_p.h>
@@ -60,6 +61,20 @@ RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderW
return;
setFocus(true);
setActiveFocusOnTab(true);
+
+#ifdef Q_OS_OSX
+ // Check that the default QSurfaceFormat OpenGL profile matches the global OpenGL shared
+ // context profile, otherwise this could lead to a nasty crash.
+ QOpenGLContext *globalSharedContext = QOpenGLContext::globalShareContext();
+ if (globalSharedContext) {
+ QSurfaceFormat sharedFormat = globalSharedContext->format();
+ QSurfaceFormat defaultFormat = QSurfaceFormat::defaultFormat();
+ if (defaultFormat.profile() != sharedFormat.profile()) {
+ qFatal("QWebEngine: Default QSurfaceFormat OpenGL profile does not match global shared context OpenGL profile. Please make sure you set a new QSurfaceFormat before the QtGui application instance is created.");
+ }
+ }
+#endif
+
}
void RenderWidgetHostViewQtDelegateQuick::initAsChild(WebContentsAdapterClient* container)
diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
index 9871ecfb..7eca835d 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
@@ -64,9 +64,30 @@ RenderWidgetHostViewQtDelegateWidget::RenderWidgetHostViewQtDelegateWidget(Rende
setFocusPolicy(Qt::StrongFocus);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
+
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
+
+ QOpenGLContext *globalSharedContext = QOpenGLContext::globalShareContext();
+ if (globalSharedContext) {
+ QSurfaceFormat sharedFormat = globalSharedContext->format();
+
+#ifdef Q_OS_OSX
+ // Check that the default QSurfaceFormat OpenGL profile matches the global OpenGL shared
+ // context profile, otherwise this could lead to a nasty crash.
+ QSurfaceFormat defaultFormat = QSurfaceFormat::defaultFormat();
+ if (defaultFormat.profile() != sharedFormat.profile()) {
+ qFatal("QWebEngine: Default QSurfaceFormat OpenGL profile does not match global shared context OpenGL profile. Please make sure you set a new QSurfaceFormat before the QtGui application instance is created.");
+ }
+#endif
+
+ // Make sure the OpenGL profile of the QOpenGLWidget matches the shared context profile.
+ format.setMajorVersion(sharedFormat.majorVersion());
+ format.setMinorVersion(sharedFormat.minorVersion());
+ format.setProfile(sharedFormat.profile());
+ }
+
setFormat(format);
#endif
diff --git a/tests/auto/quick/qquickwebenginedefaultsurfaceformat/qquickwebenginedefaultsurfaceformat.pro b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/qquickwebenginedefaultsurfaceformat.pro
new file mode 100644
index 00000000..826b47de
--- /dev/null
+++ b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/qquickwebenginedefaultsurfaceformat.pro
@@ -0,0 +1,6 @@
+include(../tests.pri)
+
+exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc
+QT_PRIVATE += webengine-private
+
+HEADERS += ../shared/util.h
diff --git a/tests/auto/quick/qquickwebenginedefaultsurfaceformat/tst_qquickwebenginedefaultsurfaceformat.cpp b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/tst_qquickwebenginedefaultsurfaceformat.cpp
new file mode 100644
index 00000000..9f206089
--- /dev/null
+++ b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/tst_qquickwebenginedefaultsurfaceformat.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testwindow.h"
+#include "util.h"
+
+#include <QGuiApplication>
+#include <QtQml/QQmlEngine>
+#include <QScopedPointer>
+#include <QSurfaceFormat>
+#include <QtTest/QtTest>
+#include <QTimer>
+#include <private/qquickwebengineview_p.h>
+
+class tst_QQuickWebEngineDefaultSurfaceFormat : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void customDefaultSurfaceFormat();
+
+private:
+ inline void initEngineAndViewComponent();
+ inline void initWindow();
+ inline void deleteWindow();
+
+ inline QQuickWebEngineView *newWebEngineView();
+ inline QQuickWebEngineView *webEngineView() const;
+ QUrl urlFromTestPath(const char *localFilePath);
+
+ QQmlEngine *m_engine;
+ TestWindow *m_window;
+ QScopedPointer<QQmlComponent> m_component;
+};
+
+void tst_QQuickWebEngineDefaultSurfaceFormat::initEngineAndViewComponent() {
+ m_engine = new QQmlEngine(this);
+ m_component.reset(new QQmlComponent(m_engine, this));
+ m_component->setData(QByteArrayLiteral("import QtQuick 2.0\n"
+ "import QtWebEngine 1.2\n"
+ "WebEngineView {}")
+ , QUrl());
+}
+
+void tst_QQuickWebEngineDefaultSurfaceFormat::initWindow()
+{
+ m_window = new TestWindow(newWebEngineView());
+}
+
+void tst_QQuickWebEngineDefaultSurfaceFormat::deleteWindow()
+{
+ delete m_window;
+}
+
+QQuickWebEngineView *tst_QQuickWebEngineDefaultSurfaceFormat::newWebEngineView()
+{
+ QObject *viewInstance = m_component->create();
+ QQuickWebEngineView *webEngineView = qobject_cast<QQuickWebEngineView*>(viewInstance);
+ return webEngineView;
+}
+
+inline QQuickWebEngineView *tst_QQuickWebEngineDefaultSurfaceFormat::webEngineView() const
+{
+ return static_cast<QQuickWebEngineView*>(m_window->webEngineView.data());
+}
+
+QUrl tst_QQuickWebEngineDefaultSurfaceFormat::urlFromTestPath(const char *localFilePath)
+{
+ QString testSourceDirPath = QString::fromLocal8Bit(TESTS_SOURCE_DIR);
+ if (!testSourceDirPath.endsWith(QLatin1Char('/')))
+ testSourceDirPath.append(QLatin1Char('/'));
+
+ return QUrl::fromLocalFile(testSourceDirPath + QString::fromUtf8(localFilePath));
+}
+
+void tst_QQuickWebEngineDefaultSurfaceFormat::customDefaultSurfaceFormat()
+{
+ // Setting a new default QSurfaceFormat with a core OpenGL profile, before
+ // app instantiation should succeed, without abort() being called.
+ int argc = 1;
+ char *argv[] = { const_cast<char*>("tst_QQuickWebEngineDefaultSurfaceFormat") };
+
+ QSurfaceFormat format;
+ format.setVersion( 3, 3 );
+ format.setProfile( QSurfaceFormat::CoreProfile );
+ QSurfaceFormat::setDefaultFormat( format );
+
+ QGuiApplication app(argc, argv);
+ QtWebEngine::initialize();
+
+ initEngineAndViewComponent();
+ initWindow();
+ QQuickWebEngineView* view = webEngineView();
+ view->setUrl(urlFromTestPath("html/basic_page.html"));
+ m_window->show();
+
+ QObject::connect(
+ view,
+ &QQuickWebEngineView::loadingChanged, [](QQuickWebEngineLoadRequest* request)
+ {
+ if (request->status() == QQuickWebEngineView::LoadSucceededStatus
+ || request->status() == QQuickWebEngineView::LoadFailedStatus)
+ QTimer::singleShot(100, qApp, &QCoreApplication::quit);
+ }
+ );
+
+ QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this]() {
+ this->deleteWindow();
+ });
+
+ QCOMPARE(app.exec(), 0);
+}
+
+QTEST_APPLESS_MAIN(tst_QQuickWebEngineDefaultSurfaceFormat)
+#include "tst_qquickwebenginedefaultsurfaceformat.moc"
diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro
index 33821e20..b278808f 100644
--- a/tests/auto/quick/quick.pro
+++ b/tests/auto/quick/quick.pro
@@ -3,6 +3,7 @@ TEMPLATE = subdirs
SUBDIRS += \
inspectorserver \
publicapi \
+ qquickwebenginedefaultsurfaceformat \
qquickwebengineview \
qquickwebengineviewgraphics
diff --git a/tests/auto/widgets/qwebenginedefaultsurfaceformat/qwebenginedefaultsurfaceformat.pro b/tests/auto/widgets/qwebenginedefaultsurfaceformat/qwebenginedefaultsurfaceformat.pro
new file mode 100644
index 00000000..e99c7f49
--- /dev/null
+++ b/tests/auto/widgets/qwebenginedefaultsurfaceformat/qwebenginedefaultsurfaceformat.pro
@@ -0,0 +1 @@
+include(../tests.pri)
diff --git a/tests/auto/widgets/qwebenginedefaultsurfaceformat/resources/index.html b/tests/auto/widgets/qwebenginedefaultsurfaceformat/resources/index.html
new file mode 100644
index 00000000..53726e4a
--- /dev/null
+++ b/tests/auto/widgets/qwebenginedefaultsurfaceformat/resources/index.html
@@ -0,0 +1,6 @@
+<html>
+<head>
+<title> Basic Page </title>
+</head>
+<h1>Basic page</h1>
+</html>
diff --git a/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp b/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp
new file mode 100644
index 00000000..e42a8a75
--- /dev/null
+++ b/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qtest.h>
+#include "../util.h"
+
+#include <QSurfaceFormat>
+#include <QTimer>
+#include <qwebengineview.h>
+
+class tst_QWebEngineDefaultSurfaceFormat : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void customDefaultSurfaceFormat();
+};
+
+void tst_QWebEngineDefaultSurfaceFormat::customDefaultSurfaceFormat()
+{
+ // Setting a new default QSurfaceFormat with a core OpenGL profile before
+ // app instantiation should succeed, without abort() being called.
+ int argc = 1;
+ char *argv[] = { const_cast<char*>("tst_QWebEngineDefaultSurfaceFormat") };
+
+ QSurfaceFormat format;
+ format.setVersion( 3, 3 );
+ format.setProfile( QSurfaceFormat::CoreProfile );
+ QSurfaceFormat::setDefaultFormat( format );
+
+ QApplication app(argc, argv);
+
+ QWebEngineView view;
+ view.load(QUrl("qrc:///resources/index.html"));
+ view.show();
+ QObject::connect(&view, &QWebEngineView::loadFinished, []() {
+ QTimer::singleShot(100, qApp, &QCoreApplication::quit);
+ });
+
+ QCOMPARE(app.exec(), 0);
+}
+
+QTEST_APPLESS_MAIN(tst_QWebEngineDefaultSurfaceFormat)
+#include "tst_qwebenginedefaultsurfaceformat.moc"
diff --git a/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.qrc b/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.qrc
new file mode 100644
index 00000000..3d5f1b3b
--- /dev/null
+++ b/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>resources/index.html</file>
+</qresource>
+</RCC>
diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro
index 986d5bbe..3220b137 100644
--- a/tests/auto/widgets/widgets.pro
+++ b/tests/auto/widgets/widgets.pro
@@ -2,6 +2,7 @@ TEMPLATE = subdirs
SUBDIRS += \
qwebengineaccessibility \
+ qwebenginedefaultsurfaceformat \
qwebenginepage \
qwebenginehistory \
qwebenginehistoryinterface \