From 857e4881c66b5db5c8cab654d33fafe5db55396c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 26 Jun 2019 12:56:12 +0200 Subject: macOS: Properly unpolish font and palette Explicitly setting the application font and palette will actually persist the current state of the application font and palette to the widget, and it will stop reacting to system style changes. Change-Id: Ib856fe86cd3edb618b7ee5819d6c6c892c61fd1d Reviewed-by: Timur Pocheptsov --- src/plugins/styles/mac/qmacstyle_mac.mm | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index ce08725684..e10aa33623 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -2139,10 +2139,9 @@ void QMacStyle::unpolish(QWidget* w) #if QT_CONFIG(menu) qobject_cast(w) && #endif - !w->testAttribute(Qt::WA_SetPalette)) { - QPalette pal = qApp->palette(w); - w->setPalette(pal); - w->setAttribute(Qt::WA_SetPalette, false); + !w->testAttribute(Qt::WA_SetPalette)) + { + w->setPalette(QPalette()); w->setWindowOpacity(1.0); } @@ -2158,9 +2157,9 @@ void QMacStyle::unpolish(QWidget* w) #if QT_CONFIG(tabbar) if (qobject_cast(w)) { if (!w->testAttribute(Qt::WA_SetFont)) - w->setFont(qApp->font(w)); + w->setFont(QFont()); if (!w->testAttribute(Qt::WA_SetPalette)) - w->setPalette(qApp->palette(w)); + w->setPalette(QPalette()); } #endif -- cgit v1.2.3 From b202d45026229e0517e80a6e82041d5fc89d9d23 Mon Sep 17 00:00:00 2001 From: Mike Krus Date: Fri, 19 Jul 2019 16:00:57 +0100 Subject: Make simulator detection work with Xcode 11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Beta version of Xcode 11 changes the format of the json object returned by simctl and used to detect running simulators. While multiple versions of Xcode can coexist on the same system, they share the same simulator infrastructure so installing Xcode 11 Beta affects projects using previous versions. Change-Id: Icf06a794aa5ba3624163ace2ce827c0ecf97c38c Reviewed-by: Frank Osterfeld Reviewed-by: Tor Arne Vestbø --- mkspecs/features/uikit/devices.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mkspecs/features/uikit/devices.py b/mkspecs/features/uikit/devices.py index 0443e838f2..8cdcb370a0 100755 --- a/mkspecs/features/uikit/devices.py +++ b/mkspecs/features/uikit/devices.py @@ -46,11 +46,17 @@ import json import subprocess from distutils.version import StrictVersion +def is_available(object): + if "isAvailable" in object: + return object["isAvailable"] # introduced in Xcode 11 + else: + return "unavailable" not in object["availability"] + def is_suitable_runtime(runtimes, runtime_name, platform, min_version): for runtime in runtimes: identifier = runtime["identifier"] if (runtime["name"] == runtime_name or identifier == runtime_name) \ - and "unavailable" not in runtime["availability"] \ + and is_available(runtime) \ and identifier.startswith("com.apple.CoreSimulator.SimRuntime.{}".format(platform)) \ and StrictVersion(runtime["version"]) >= min_version: return True @@ -77,6 +83,6 @@ if __name__ == "__main__": for runtime_name in device_dict: if is_suitable_runtime(runtimes, runtime_name, args.platform, args.minimum_deployment_target): for device in device_dict[runtime_name]: - if "unavailable" not in device["availability"] \ + if is_available(device) \ and (args.state is None or device["state"].lower() in args.state): print(device["udid"]) -- cgit v1.2.3 From 86f91bf0f707e34392fbdf424d6914e7cf6bb4e6 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Sun, 21 Jul 2019 22:15:45 +0200 Subject: Make the warning in QBackingStore::endPaint() a little more helpful MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Amends 2aa9908e24611fa6d321e694b8415ba7e8d364b0 Change-Id: I2883ca27b06b2b414b4991b2dab3f84100b4c853 Reviewed-by: Tor Arne Vestbø --- src/gui/painting/qbackingstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index d935deb4d6..b9ed3d4995 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -186,7 +186,7 @@ QPaintDevice *QBackingStore::paintDevice() void QBackingStore::endPaint() { if (paintDevice()->paintingActive()) - qWarning() << "QBackingStore::endPaint() called with active painter on backingstore paint device"; + qWarning("QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?"); handle()->endPaint(); } -- cgit v1.2.3 From 547f216efdef3667b0b23ecddce93e5184806800 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Tue, 16 Jul 2019 14:51:02 +1000 Subject: wasm: fix international dead keys Emscripten has changed the key code to include the string 'Digit' on numerals. We use this to detect and translate any Dead keys that may be pressed. Fixes: QTBUG-77041 Change-Id: I054e98a6cf66390b1154f25fe385e5b12840851f Reviewed-by: Volker Hilsheimer --- .../platforms/wasm/qwasmeventtranslator.cpp | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 3895646b89..43e82435cf 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -138,16 +138,16 @@ static constexpr const auto KeyTbl = qMakeArray( Emkb2Qt< Qt::Key_Minus, '-' >, Emkb2Qt< Qt::Key_Period, '.' >, Emkb2Qt< Qt::Key_Slash, '/' >, - Emkb2Qt< Qt::Key_0, '0' >, - Emkb2Qt< Qt::Key_1, '1' >, - Emkb2Qt< Qt::Key_2, '2' >, - Emkb2Qt< Qt::Key_3, '3' >, - Emkb2Qt< Qt::Key_4, '4' >, - Emkb2Qt< Qt::Key_5, '5' >, - Emkb2Qt< Qt::Key_6, '6' >, - Emkb2Qt< Qt::Key_7, '7' >, - Emkb2Qt< Qt::Key_8, '8' >, - Emkb2Qt< Qt::Key_9, '9' >, + Emkb2Qt< Qt::Key_0, 'D','i','g','i','t','0' >, + Emkb2Qt< Qt::Key_1, 'D','i','g','i','t','1' >, + Emkb2Qt< Qt::Key_2, 'D','i','g','i','t','2' >, + Emkb2Qt< Qt::Key_3, 'D','i','g','i','t','3' >, + Emkb2Qt< Qt::Key_4, 'D','i','g','i','t','4' >, + Emkb2Qt< Qt::Key_5, 'D','i','g','i','t','5' >, + Emkb2Qt< Qt::Key_6, 'D','i','g','i','t','6' >, + Emkb2Qt< Qt::Key_7, 'D','i','g','i','t','7' >, + Emkb2Qt< Qt::Key_8, 'D','i','g','i','t','8' >, + Emkb2Qt< Qt::Key_9, 'D','i','g','i','t','9' >, Emkb2Qt< Qt::Key_Semicolon, ';' >, Emkb2Qt< Qt::Key_Equal, '=' >, Emkb2Qt< Qt::Key_A, 'K','e','y','A' >, @@ -432,7 +432,8 @@ Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent { Qt::Key qtKey = Qt::Key_unknown; - if (qstrncmp(emscriptKey->code, "Key", 3) == 0 || qstrncmp(emscriptKey->code, "Numpad", 6) == 0) { + if (qstrncmp(emscriptKey->code, "Key", 3) == 0 || qstrncmp(emscriptKey->code, "Numpad", 6) == 0 || + qstrncmp(emscriptKey->code, "Digit", 5) == 0) { emkb2qt_t searchKey{emscriptKey->code, 0}; // search emcsripten code auto it1 = std::lower_bound(KeyTbl.cbegin(), KeyTbl.cend(), searchKey); @@ -808,11 +809,10 @@ Qt::Key QWasmEventTranslator::translateDeadKey(Qt::Key deadKey, Qt::Key accentBa case Qt::Key_Apostrophe:// linux wasmKey = circumflexKeyTable.value(accentBaseKey); break; - break; default: break; - }; + }; return wasmKey; } -- cgit v1.2.3 From c21cc647e98327856006701ee59b798ef2723e85 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 22 Jul 2019 14:00:20 +0200 Subject: Fix lancebench results oddness Imports were expanded in the list of commands every time they were evaluated. This meant any test with imports ran slower and slower the more iterations it got through. Fixed by creating a new PaintCommands object every time and living with initialization of it being part of the benchmark results. Change-Id: Ib53a3a25f1393437452bc5aede04ccb63e8715a6 Reviewed-by: Eirik Aavitsland --- .../gui/painting/lancebench/tst_lancebench.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/benchmarks/gui/painting/lancebench/tst_lancebench.cpp b/tests/benchmarks/gui/painting/lancebench/tst_lancebench.cpp index bd0889bf4a..d26ac016b9 100644 --- a/tests/benchmarks/gui/painting/lancebench/tst_lancebench.cpp +++ b/tests/benchmarks/gui/painting/lancebench/tst_lancebench.cpp @@ -305,17 +305,17 @@ void tst_LanceBench::runTestSuite(GraphicsEngine engine, QImage::Format format, void tst_LanceBench::paint(QPaintDevice *device, GraphicsEngine engine, QImage::Format format, const QStringList &script, const QString &filePath) { - PaintCommands pcmd(script, 800, 800, format); - switch (engine) { - case OpenGL: - pcmd.setType(OpenGLBufferType); // version/profile is communicated through the context's format() - break; - case Raster: - pcmd.setType(ImageType); - break; - } - pcmd.setFilePath(filePath); QBENCHMARK { + PaintCommands pcmd(script, 800, 800, format); + switch (engine) { + case OpenGL: + pcmd.setType(OpenGLBufferType); // version/profile is communicated through the context's format() + break; + case Raster: + pcmd.setType(ImageType); + break; + } + pcmd.setFilePath(filePath); QPainter p(device); pcmd.setPainter(&p); pcmd.runCommands(); -- cgit v1.2.3 From 589d96b9b06a4a7d0dca03a06c80716318761277 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Mon, 24 Jun 2019 15:38:45 +0200 Subject: winrt: Remove QWinrtScreen::pixelDensity so that the default of 1.0 is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Winrt does device independent scaling by default so that overwriting pixelDensity for QWinrtScreen will break the use case of setting Qt::AA_EnableHighDpiScaling. That mode is basically always active on winrt. Task-number: QTBUG-76363 Change-Id: Ib522201850d17757be4a80aa819c3f1245ca7147 Reviewed-by: Maurice Kalinowski Reviewed-by: André de la Rocha --- src/plugins/platforms/winrt/qwinrtscreen.cpp | 6 ------ src/plugins/platforms/winrt/qwinrtscreen.h | 1 - 2 files changed, 7 deletions(-) diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index e611c7be24..342e142a74 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -669,12 +669,6 @@ QDpi QWinRTScreen::logicalDpi() const return QDpi(d->logicalDpi, d->logicalDpi); } -qreal QWinRTScreen::pixelDensity() const -{ - Q_D(const QWinRTScreen); - return qMax(1, qRound(d->logicalDpi / 96)); -} - qreal QWinRTScreen::scaleFactor() const { Q_D(const QWinRTScreen); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index 63c254940d..6b57780fa1 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -96,7 +96,6 @@ public: QImage::Format format() const override; QSizeF physicalSize() const override; QDpi logicalDpi() const override; - qreal pixelDensity() const override; qreal scaleFactor() const; QPlatformCursor *cursor() const override; Qt::KeyboardModifiers keyboardModifiers() const; -- cgit v1.2.3 From e4c1feae5c0bec21e24edbf5acacd248dd121634 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 17 Jul 2019 15:10:49 +0200 Subject: Implement 'preconnect-https' and 'preconnect-http' for H2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QNetworkAccessManager::connectToHostEncrypted()/connectToHost() creates 'fake' requests with pseudo-schemes 'preconnect-https'/ 'preconnect-http'. QHttp2ProtocolHandler should handle this requests in a special way - reporting them immediately as finished (so that QNAM emits finished as it does in case of HTTP/1.1) and not trying to send anything. We also have to properly cache the connection - 'https' or 'http' scheme is too generic - it allows (unfortunately) mixing H2/HTTP/1.1 in a single connection in case an attribute was missing on a request, which is wrong. h2c is more complicated, since it needs a real request to negotiate the protocol switch to H2, with the current QNetworkHttpConnection(Channel)'s design it's not possible without large changes (aka regressions and new bugs introduced). Auto-test extended. Fixes: QTBUG-77082 Change-Id: I03467673a620c89784c2d36521020dc9d08aced7 Reviewed-by: Edward Welbourne Reviewed-by: Mårten Nordheim --- src/network/access/qhttp2protocolhandler.cpp | 25 +++++- src/network/access/qhttpthreaddelegate.cpp | 36 +++++--- src/network/access/qnetworkaccessmanager.cpp | 9 +- tests/auto/network/access/http2/tst_http2.cpp | 123 ++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 18 deletions(-) diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 87a70d8a55..5d7fc7506e 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -170,7 +170,6 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan encoder(HPack::FieldLookupTable::DefaultSize, true) { Q_ASSERT(channel && m_connection); - continuedFrames.reserve(20); const ProtocolParameters params(m_connection->http2Parameters()); @@ -322,10 +321,32 @@ bool QHttp2ProtocolHandler::sendRequest() return false; } + // Process 'fake' (created by QNetworkAccessManager::connectToHostEncrypted()) + // requests first: + auto &requests = m_channel->spdyRequestsToSend; + for (auto it = requests.begin(), endIt = requests.end(); it != endIt;) { + const auto &pair = *it; + const QString scheme(pair.first.url().scheme()); + if (scheme == QLatin1String("preconnect-http") + || scheme == QLatin1String("preconnect-https")) { + m_connection->preConnectFinished(); + emit pair.second->finished(); + it = requests.erase(it); + if (!requests.size()) { + // Normally, after a connection was established and H2 + // was negotiated, we send a client preface. connectToHostEncrypted + // though is not meant to send any data, it's just a 'preconnect'. + // Thus we return early: + return true; + } + } else { + ++it; + } + } + if (!prefaceSent && !sendClientPreface()) return false; - auto &requests = m_channel->spdyRequestsToSend; if (!requests.size()) return true; diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 0e97acdd9d..86ee6fd2eb 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -128,7 +128,8 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy) QString result; QUrl copy = url; QString scheme = copy.scheme(); - bool isEncrypted = scheme == QLatin1String("https"); + bool isEncrypted = scheme == QLatin1String("https") + || scheme == QLatin1String("preconnect-https"); copy.setPort(copy.port(isEncrypted ? 443 : 80)); if (scheme == QLatin1String("preconnect-http")) { copy.setScheme(QLatin1String("http")); @@ -295,17 +296,29 @@ void QHttpThreadDelegate::startRequest() connectionType = QHttpNetworkConnection::ConnectionTypeHTTP2Direct; } + const bool isH2 = httpRequest.isHTTP2Allowed() || httpRequest.isHTTP2Direct(); + if (isH2) { +#if QT_CONFIG(ssl) + if (ssl) { + if (!httpRequest.isHTTP2Direct()) { + QList protocols; + protocols << QSslConfiguration::ALPNProtocolHTTP2 + << QSslConfiguration::NextProtocolHttp1_1; + incomingSslConfiguration->setAllowedNextProtocols(protocols); + } + urlCopy.setScheme(QStringLiteral("h2s")); + } else +#endif // QT_CONFIG(ssl) + { + urlCopy.setScheme(QStringLiteral("h2")); + } + } + #ifndef QT_NO_SSL if (ssl && !incomingSslConfiguration.data()) incomingSslConfiguration.reset(new QSslConfiguration); - if (httpRequest.isHTTP2Allowed() && ssl) { - // With HTTP2Direct we do not try any protocol negotiation. - QList protocols; - protocols << QSslConfiguration::ALPNProtocolHTTP2 - << QSslConfiguration::NextProtocolHttp1_1; - incomingSslConfiguration->setAllowedNextProtocols(protocols); - } else if (httpRequest.isSPDYAllowed() && ssl) { + if (!isH2 && httpRequest.isSPDYAllowed() && ssl) { connectionType = QHttpNetworkConnection::ConnectionTypeSPDY; urlCopy.setScheme(QStringLiteral("spdy")); // to differentiate SPDY requests from HTTPS requests QList nextProtocols; @@ -322,12 +335,11 @@ void QHttpThreadDelegate::startRequest() cacheKey = makeCacheKey(urlCopy, &cacheProxy); else #endif - cacheKey = makeCacheKey(urlCopy, 0); - + cacheKey = makeCacheKey(urlCopy, nullptr); // the http object is actually a QHttpNetworkConnection httpConnection = static_cast(connections.localData()->requestEntryNow(cacheKey)); - if (httpConnection == 0) { + if (!httpConnection) { // no entry in cache; create an object // the http object is actually a QHttpNetworkConnection #ifdef QT_NO_BEARERMANAGEMENT @@ -357,7 +369,7 @@ void QHttpThreadDelegate::startRequest() connections.localData()->addEntry(cacheKey, httpConnection); } else { if (httpRequest.withCredentials()) { - QNetworkAuthenticationCredential credential = authenticationManager->fetchCachedCredentials(httpRequest.url(), 0); + QNetworkAuthenticationCredential credential = authenticationManager->fetchCachedCredentials(httpRequest.url(), nullptr); if (!credential.user.isEmpty() && !credential.password.isEmpty()) { QAuthenticator auth; auth.setUser(credential.user); diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 85e2c492e4..31b1dbf2a5 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1192,10 +1192,11 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin if (sslConfiguration != QSslConfiguration::defaultConfiguration()) request.setSslConfiguration(sslConfiguration); - // There is no way to enable SPDY via a request, so we need to check - // the ssl configuration whether SPDY is allowed here. - if (sslConfiguration.allowedNextProtocols().contains( - QSslConfiguration::NextProtocolSpdy3_0)) + // There is no way to enable SPDY/HTTP2 via a request, so we need to check + // the ssl configuration whether SPDY/HTTP2 is allowed here. + if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2)) + request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true); + else if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::NextProtocolSpdy3_0)) request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true); get(request); diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index f7d74e66b2..ce685a1b1c 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -84,6 +84,8 @@ private slots: void goaway_data(); void goaway(); void earlyResponse(); + void connectToHost_data(); + void connectToHost(); protected slots: // Slots to listen to our in-process server: @@ -544,6 +546,127 @@ void tst_Http2::earlyResponse() QVERIFY(serverGotSettingsACK); } +void tst_Http2::connectToHost_data() +{ + // The attribute to set on a new request: + QTest::addColumn("requestAttribute"); + // The corresponding (to the attribute above) connection type the + // server will use: + QTest::addColumn("connectionType"); + +#if QT_CONFIG(ssl) + QTest::addRow("encrypted-h2-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2Direct; + if (!clearTextHTTP2) + QTest::addRow("encrypted-h2-ALPN") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2Alpn; +#endif // QT_CONFIG(ssl) + // This works for all configurations, tests 'preconnect-http' scheme: + // h2 with protocol upgrade is not working for now (the logic is a bit + // complicated there ...). + QTest::addRow("h2-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2cDirect; +} + +void tst_Http2::connectToHost() +{ + // QNetworkAccessManager::connectToHostEncrypted() and connectToHost() + // creates a special request with 'preconnect-https' or 'preconnect-http' + // schemes. At the level of the protocol handler we are supposed to report + // these requests as finished and wait for the real requests. This test will + // connect to a server with the first reply 'finished' signal meaning we + // indeed connected. At this point we check that a client preface was not + // sent yet, and no response received. Then we send the second (the real) + // request and do our usual checks. Since our server closes its listening + // socket on the first incoming connection (would not accept a new one), + // the successful completion of the second requests also means we were able + // to find a cached connection and re-use it. + + QFETCH(const QNetworkRequest::Attribute, requestAttribute); + QFETCH(const H2Type, connectionType); + + clearHTTP2State(); + + serverPort = 0; + nRequests = 2; + + ServerPtr targetServer(newServer(defaultServerSettings, connectionType)); + +#if QT_CONFIG(ssl) + Q_ASSERT(!clearTextHTTP2 || connectionType != H2Type::h2Alpn); +#else + Q_ASSERT(connectionType == H2Type::h2c || connectionType == H2Type::h2cDirect); + Q_ASSERT(targetServer->isClearText()); +#endif // QT_CONFIG(ssl) + + QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + + QVERIFY(serverPort != 0); + + auto url = requestUrl(connectionType); + url.setPath("/index.html"); + + QNetworkReply *reply = nullptr; + // Here some mess with how we create this first reply: +#if QT_CONFIG(ssl) + if (!targetServer->isClearText()) { + // Let's emulate what QNetworkAccessManager::connectToHostEncrypted() does. + // Alas, we cannot use it directly, since it does not return the reply and + // also does not know the difference between H2 with ALPN or direct. + auto copyUrl = url; + copyUrl.setScheme(QLatin1String("preconnect-https")); + QNetworkRequest request(copyUrl); + request.setAttribute(requestAttribute, true); + reply = manager->get(request); + // Since we're using self-signed certificates, ignore SSL errors: + reply->ignoreSslErrors(); + } else +#endif // QT_CONFIG(ssl) + { + // Emulating what QNetworkAccessManager::connectToHost() does with + // additional information that it cannot provide (the attribute). + auto copyUrl = url; + copyUrl.setScheme(QLatin1String("preconnect-http")); + QNetworkRequest request(copyUrl); + request.setAttribute(requestAttribute, true); + reply = manager->get(request); + } + + connect(reply, &QNetworkReply::finished, [this, reply]() { + --nRequests; + eventLoop.exitLoop(); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(reply->isFinished()); + // Nothing must be sent yet: + QVERIFY(!prefaceOK); + QVERIFY(!serverGotSettingsACK); + // Nothing received back: + QVERIFY(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).isNull()); + QCOMPARE(reply->readAll().size(), 0); + }); + + runEventLoop(); + STOP_ON_FAILURE + + QCOMPARE(nRequests, 1); + + QNetworkRequest request(url); + request.setAttribute(requestAttribute, QVariant(true)); + reply = manager->get(request); + connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); + // Note, unlike the first request, when the connection is ecnrytped, we + // do not ignore TLS errors on this reply - we should re-use existing + // connection, there TLS errors were already ignored. + + runEventLoop(); + STOP_ON_FAILURE + + QVERIFY(nRequests == 0); + QVERIFY(prefaceOK); + QVERIFY(serverGotSettingsACK); + + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(reply->isFinished()); +} + void tst_Http2::serverStarted(quint16 port) { serverPort = port; -- cgit v1.2.3 From 65cdd0f36678a6b77caf9cf0007ad44c51f7f7af Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 4 Jun 2019 14:42:31 -0500 Subject: Enable shader cache for ES2 when GL_OES_get_program_binary is present Change-Id: I4fb71471a7dd22441def1eb837857d245c3e3c5a Reviewed-by: Laszlo Agocs --- src/gui/opengl/qopenglprogrambinarycache.cpp | 31 ++++++++++++++++++++++++++-- src/gui/opengl/qopenglprogrambinarycache_p.h | 6 ++++++ src/gui/opengl/qopenglshaderprogram.cpp | 8 ++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/gui/opengl/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp index c96021a969..7029cd5455 100644 --- a/src/gui/opengl/qopenglprogrambinarycache.cpp +++ b/src/gui/opengl/qopenglprogrambinarycache.cpp @@ -168,12 +168,19 @@ bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat, const void *p, uint blobSize) { - QOpenGLExtraFunctions *funcs = QOpenGLContext::currentContext()->extraFunctions(); + QOpenGLContext *context = QOpenGLContext::currentContext(); + QOpenGLExtraFunctions *funcs = context->extraFunctions(); while (true) { GLenum error = funcs->glGetError(); if (error == GL_NO_ERROR || error == GL_CONTEXT_LOST) break; } +#if defined(QT_OPENGL_ES_2) + if (context->isOpenGLES() && context->format().majorVersion() < 3) { + initializeProgramBinaryOES(context); + programBinaryOES(programId, blobFormat, p, blobSize); + } else +#endif funcs->glProgramBinary(programId, blobFormat, p, blobSize); GLenum err = funcs->glGetError(); @@ -347,7 +354,8 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId) GLEnvInfo info; - QOpenGLExtraFunctions *funcs = QOpenGLContext::currentContext()->extraFunctions(); + QOpenGLContext *context = QOpenGLContext::currentContext(); + QOpenGLExtraFunctions *funcs = context->extraFunctions(); GLint blobSize = 0; while (true) { GLenum error = funcs->glGetError(); @@ -390,6 +398,12 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId) *p++ = 0; GLint outSize = 0; +#if defined(QT_OPENGL_ES_2) + if (context->isOpenGLES() && context->format().majorVersion() < 3) { + initializeProgramBinaryOES(context); + getProgramBinaryOES(programId, blobSize, &outSize, &blobFormat, p); + } else +#endif funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p); if (blobSize != outSize) { qCDebug(DBG_SHADER_CACHE, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize); @@ -408,4 +422,17 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId) } } +#if defined(QT_OPENGL_ES_2) +void QOpenGLProgramBinaryCache::initializeProgramBinaryOES(QOpenGLContext *context) +{ + if (m_programBinaryOESInitialized) + return; + m_programBinaryOESInitialized = true; + + Q_ASSERT(context); + getProgramBinaryOES = (void (QOPENGLF_APIENTRYP)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary))context->getProcAddress("glGetProgramBinaryOES"); + programBinaryOES = (void (QOPENGLF_APIENTRYP)(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length))context->getProcAddress("glProgramBinaryOES"); +} +#endif + QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglprogrambinarycache_p.h b/src/gui/opengl/qopenglprogrambinarycache_p.h index a0e1f91e25..9fade08e66 100644 --- a/src/gui/opengl/qopenglprogrambinarycache_p.h +++ b/src/gui/opengl/qopenglprogrambinarycache_p.h @@ -93,6 +93,12 @@ private: uint format; }; QCache m_memCache; +#if defined(QT_OPENGL_ES_2) + void (QOPENGLF_APIENTRYP programBinaryOES)(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); + void (QOPENGLF_APIENTRYP getProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); + void initializeProgramBinaryOES(QOpenGLContext *context); + bool m_programBinaryOESInitialized = false; +#endif }; QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index c39177080d..3ce0cf230b 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -3753,8 +3753,14 @@ QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContex if (ctx) { if (ctx->isOpenGLES()) { qCDebug(DBG_SHADER_CACHE, "OpenGL ES v%d context", ctx->format().majorVersion()); - if (ctx->format().majorVersion() >= 3) + if (ctx->format().majorVersion() >= 3) { m_supported = true; + } else { + const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary"); + qCDebug(DBG_SHADER_CACHE, "GL_OES_get_program_binary support = %d", hasExt); + if (hasExt) + m_supported = true; + } } else { const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary"); qCDebug(DBG_SHADER_CACHE, "GL_ARB_get_program_binary support = %d", hasExt); -- cgit v1.2.3 From 0ce3f7d62b93427ca5d0f4284ba774691cbbd4a7 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 24 Jul 2019 15:47:28 +0200 Subject: QMacStyle: workaround NSSliderCell's cached/stale geometry It's a bit cheesy solution, but works as I've noticed first on QSlider's with a ticks direction 'both'. Works because we were already using numberOfTickMarks property to trigger a special behavior for HIG non-compliant widgets. Works for our case too - we trigger a geometry update. Fixes: QTBUG-76811 Change-Id: I2cbf00d42d98e78519b281d138a2f74227ef5449 Reviewed-by: Volker Hilsheimer --- src/plugins/styles/mac/qmacstyle_mac.mm | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index e10aa33623..1d88d2c647 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -137,6 +137,8 @@ #include #include +#include + QT_USE_NAMESPACE static QWindow *qt_getWindow(const QWidget *widget) @@ -514,6 +516,37 @@ static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl) return true; } +static void fixStaleGeometry(NSSlider *slider) +{ + // If it's later fixed in AppKit, this function is not needed. + // On macOS Mojave we suddenly have NSSliderCell with a cached + // (and stale) geometry, thus its -drawKnob, -drawBarInside:flipped:, + // -drawTickMarks fail to render the slider properly. Setting the number + // of tickmarks triggers an update in geometry. + + Q_ASSERT(slider); + + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave) + return; + + NSSliderCell *cell = slider.cell; + const NSRect barRect = [cell barRectFlipped:NO]; + const NSSize sliderSize = slider.frame.size; + CGFloat difference = 0.; + if (slider.vertical) + difference = std::abs(sliderSize.height - barRect.size.height); + else + difference = std::abs(sliderSize.width - barRect.size.width); + + if (difference > 6.) { + // Stale ... + const auto nOfTicks = slider.numberOfTickMarks; + // Non-zero, different from nOfTicks to force update + slider.numberOfTickMarks = nOfTicks + 10; + slider.numberOfTickMarks = nOfTicks; + } +} + static bool isInMacUnifiedToolbarArea(QWindow *window, int windowY) { QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); @@ -5318,6 +5351,8 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex #endif { [slider calcSize]; + if (!hasDoubleTicks) + fixStaleGeometry(slider); NSSliderCell *cell = slider.cell; const int numberOfTickMarks = slider.numberOfTickMarks; -- cgit v1.2.3