From e379147f9571af8c3af5768b9040e0180819a855 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Tue, 13 Apr 2021 17:16:44 +0200 Subject: [PATCH 1/3] CMake: Fix default architecture selection for macOS and iOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this change, we created a CMake toolchain file for iOS and macOS universal which propagated the initially configured CMAKE_OSX_ARCHITECTURES values to user projects. So if Qt was configured with 2 arches, configuring a CMake user project using the generated toolchain file would also build the user project targeting those 2 arches. The reason for this that the same toolchain file is used for configuring both Qt and users projects and we needed to ensure that other Qt repos are built with the same set of arches. That unfortunately led the multiple arches to carry over into user projects. This is different from qmake behavior which configured user projects with 1 arch only. Instead of the toolchain file explicitly setting CMAKE_OSX_ARCHITECTURES for all projects, save the initial list of arches into QT_OSX_ARCHITECTURES. Then if the toolchain file detects that we're building a Qt repo (by checking for the presence of QT_REPO_MODULE_VERSION) set CMAKE_OSX_ARCHITECTURES to QT_OSX_ARCHITECTURES to propagate the initial list of arches. For user projects we want to have some sensible defaults. For macOS projects, leave the decision of the architecture to build to CMake. For iOS Xcode projects, leave the decision to Xcode. For iOS Ninja projects, set the architecture to the first value of the architectures used when configuring Qt. As a side note this fixes an issue in our CI where we configured macOS Qt with 2 architectures and then tried to run CMake build tests for both architectures on a machine that doesn't have the universal SDK. This led to build failures. Because the CMake build tests act as regular user projects, now they are configured with a single architecture that is automtically detected by CMake. Pick-to: 6.1 Task-number: QTBUG-85447 Change-Id: Id1b7e78d7e67c1796efed10751416e5f857c16d2 Reviewed-by: Tor Arne Vestbø --- cmake/QtToolchainHelpers.cmake | 46 ++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/cmake/QtToolchainHelpers.cmake b/cmake/QtToolchainHelpers.cmake index f2ef6147e1f..f4ee35be317 100644 --- a/cmake/QtToolchainHelpers.cmake +++ b/cmake/QtToolchainHelpers.cmake @@ -112,12 +112,48 @@ function(qt_internal_create_toolchain_file) "set(CMAKE_OSX_DEPLOYMENT_TARGET \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" CACHE STRING \"\")") endif() - if(UIKIT OR (MACOS AND QT_IS_MACOS_UNIVERSAL)) - set(_qt_osx_architectures_escaped "${CMAKE_OSX_ARCHITECTURES}") - string(REPLACE ";" "LITERAL_SEMICOLON" - _qt_osx_architectures_escaped "${_qt_osx_architectures_escaped}") + # Save list of initial architectures Qt was configured with. + set(_qt_osx_architectures_escaped "${CMAKE_OSX_ARCHITECTURES}") + string(REPLACE ";" "LITERAL_SEMICOLON" + _qt_osx_architectures_escaped "${_qt_osx_architectures_escaped}") + set(docstring "List of architectures Qt was built with") + list(APPEND init_platform + "set(QT_OSX_ARCHITECTURES \"${_qt_osx_architectures_escaped}\" CACHE STRING \"${docstring}\")") + list(APPEND init_platform "") + + # When building another qt repo, ensure the same list of architectures is used by default. + # Detection of a qt repo is done by checking for QT_REPO_MODULE_VERSION which is set in + # the repo's .cmake.conf file. + # Standalone tests will be not be built with multiple architectures to avoid issues in the + # CI when trying to run cmake build tests on VMs that do not have a universal macOS + # SDK. + list(APPEND init_platform "# Only build multiple architectures when building Qt itself") + list(APPEND init_platform "if((QT_REPO_MODULE_VERSION AND NOT QT_BUILD_STANDALONE_TESTS) OR QT_FORCE_QT_OSX_ARCHITECTURES)") + list(APPEND init_platform " set(__qt_toolchain_building_qt_repo TRUE)") + list(APPEND init_platform " set(CMAKE_OSX_ARCHITECTURES \"\${QT_OSX_ARCHITECTURES}\" CACHE STRING \"\")") + list(APPEND init_platform "endif()") + list(APPEND init_platform "") + + # For macOS user projects, default to not specifying any architecture. This means CMake will + # not pass an -arch flag to the compiler and the compiler will choose the default + # architecture to build for. + # On Apple Silicon, CMake will introspect whether it's running under Rosetta and will + # pass the detected architecture (x86_64 under Rosetta or arm64 natively) to the compiler. + # This is line with default CMake behavior for user projects. + # + # For iOS, we provide a bit more convenience. + # When the user project is built using the Xcode generator, don't specify a default + # architecture and let Xcode and the developer handle it. + # When using the Ninja generator, specify the first architecture from QT_OSX_ARCHITECTURES + # (even with a simulator_and_device Qt build). This ensures that the default configuration + # at least tries to build something. + if(UIKIT) + qt_internal_get_first_osx_arch(osx_first_arch) + list(APPEND init_platform "if(NOT CMAKE_GENERATOR STREQUAL \"Xcode\" AND NOT __qt_toolchain_building_qt_repo)") list(APPEND init_platform - "set(CMAKE_OSX_ARCHITECTURES \"${_qt_osx_architectures_escaped}\" CACHE STRING \"\")") + " set(CMAKE_OSX_ARCHITECTURES \"${osx_first_arch}\" CACHE STRING \"\")") + list(APPEND init_platform "endif()") + list(APPEND init_platform "") endif() if(UIKIT) From a7dac8e35be35462973f2f3f653e5d1986005cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 14 Apr 2021 11:47:13 +0200 Subject: [PATCH 2/3] QNetworkCookie: Rename sameSite to sameSitePolicy As suggested in the API review. Amends 37bd7b5733c7f1a4eb6ac5458fdc46f94a91194a Pick-to: 6.1 6.1.0 Change-Id: Ic3e8567f349568dc3b4dbf79be27c304b39480cf Reviewed-by: Volker Hilsheimer --- src/network/access/qnetworkcookie.cpp | 12 ++++++------ src/network/access/qnetworkcookie.h | 4 ++-- .../access/qnetworkcookie/tst_qnetworkcookie.cpp | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp index cfc3b14c9e9..13fc147c15a 100644 --- a/src/network/access/qnetworkcookie.cpp +++ b/src/network/access/qnetworkcookie.cpp @@ -227,9 +227,9 @@ void QNetworkCookie::setSecure(bool enable) string, \c SameSite::Default if not present. \since 6.1 - \sa setSameSite() + \sa setSameSitePolicy() */ -QNetworkCookie::SameSite QNetworkCookie::sameSite() const +QNetworkCookie::SameSite QNetworkCookie::sameSitePolicy() const { return d->sameSite; } @@ -238,9 +238,9 @@ QNetworkCookie::SameSite QNetworkCookie::sameSite() const Sets the "SameSite" option of this cookie to \a sameSite. \since 6.1 - \sa sameSite() + \sa sameSitePolicy() */ -void QNetworkCookie::setSameSite(QNetworkCookie::SameSite sameSite) +void QNetworkCookie::setSameSitePolicy(QNetworkCookie::SameSite sameSite) { d->sameSite = sameSite; } @@ -469,7 +469,7 @@ static QPair nextField(const QByteArray &text, int &posi This is the default in modern browsers (since mid 2020). \value Strict Cookies will only be sent in a first-party context. - \sa setSameSite(), sameSite() + \sa setSameSitePolicy(), sameSitePolicy() */ namespace { @@ -1065,7 +1065,7 @@ QList QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt } else if (field.first == "httponly") { cookie.setHttpOnly(true); } else if (field.first == "samesite") { - cookie.setSameSite(sameSiteFromRawString(field.second)); + cookie.setSameSitePolicy(sameSiteFromRawString(field.second)); } else { // ignore unknown fields in the cookie (RFC6265 section 5.2, rule 6) } diff --git a/src/network/access/qnetworkcookie.h b/src/network/access/qnetworkcookie.h index 736a9d7149b..265f3a71245 100644 --- a/src/network/access/qnetworkcookie.h +++ b/src/network/access/qnetworkcookie.h @@ -87,8 +87,8 @@ public: void setSecure(bool enable); bool isHttpOnly() const; void setHttpOnly(bool enable); - SameSite sameSite() const; - void setSameSite(SameSite sameSite); + SameSite sameSitePolicy() const; + void setSameSitePolicy(SameSite sameSite); bool isSessionCookie() const; QDateTime expirationDate() const; diff --git a/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp index b71934fc15d..7f1b8e6369d 100644 --- a/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp +++ b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp @@ -688,11 +688,11 @@ void tst_QNetworkCookie::parseMultipleCookies() void tst_QNetworkCookie::sameSite() { QList result = QNetworkCookie::parseCookies(QByteArrayLiteral("a=b;domain=qt-project.org")); - QCOMPARE(result.first().sameSite(), QNetworkCookie::SameSite::Default); + QCOMPARE(result.first().sameSitePolicy(), QNetworkCookie::SameSite::Default); result = QNetworkCookie::parseCookies(QByteArrayLiteral("a=b;domain=qt-project.org;samesite=strict")); - QCOMPARE(result.first().sameSite(), QNetworkCookie::SameSite::Strict); + QCOMPARE(result.first().sameSitePolicy(), QNetworkCookie::SameSite::Strict); result = QNetworkCookie::parseCookies(QByteArrayLiteral("a=b;domain=qt-project.org;samesite=none;secure")); - QCOMPARE(result.first().sameSite(), QNetworkCookie::SameSite::None); + QCOMPARE(result.first().sameSitePolicy(), QNetworkCookie::SameSite::None); QCOMPARE(result.first().toRawForm(), QByteArrayLiteral("a=b; secure; SameSite=None; domain=qt-project.org")); } From f4d791b330d02777fcaf02938732892eb3167e9b Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Tue, 13 Apr 2021 14:23:45 +0200 Subject: [PATCH 3/3] Avoid processing-intensive painting of high number of tiny dashes When stroking a dashed path, an unnecessary amount of processing would be spent if there is a huge number of dashes visible, e.g. because of scaling. Since the dashes are too small to be indivdually visible anyway, just replace with a semi-transparent solid line for such cases. Pick-to: 6.1 6.0 5.15 Change-Id: I9e9f7861257ad5bce46a0cf113d1a9d7824911e6 Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qpaintengineex.cpp | 44 +++++++++++++++---- .../other/lancelot/scripts/tinydashes.qps | 34 ++++++++++++++ 2 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 tests/auto/other/lancelot/scripts/tinydashes.qps diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 7e26928e327..d752c01f6a7 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -385,7 +385,7 @@ QPainterState *QPaintEngineEx::createState(QPainterState *orig) const Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp -void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) +void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &inPen) { #ifdef QT_DEBUG_DRAW qDebug() << "QPaintEngineEx::stroke()" << pen; @@ -403,6 +403,38 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) d->stroker.setCubicToHook(qpaintengineex_cubicTo); } + QRectF clipRect; + QPen pen = inPen; + if (pen.style() > Qt::SolidLine) { + QRectF cpRect = path.controlPointRect(); + const QTransform &xf = state()->matrix; + if (pen.isCosmetic()) { + clipRect = d->exDeviceRect; + cpRect.translate(xf.dx(), xf.dy()); + } else { + clipRect = xf.inverted().mapRect(QRectF(d->exDeviceRect)); + } + // Check to avoid generating unwieldy amount of dashes that will not be visible anyway + QRectF extentRect = cpRect & clipRect; + qreal extent = qMax(extentRect.width(), extentRect.height()); + qreal patternLength = 0; + const QList pattern = pen.dashPattern(); + const int patternSize = qMin(pattern.size(), 32); + for (int i = 0; i < patternSize; i++) + patternLength += qMax(pattern.at(i), qreal(0)); + if (pen.widthF()) + patternLength *= pen.widthF(); + if (qFuzzyIsNull(patternLength)) { + pen.setStyle(Qt::NoPen); + } else if (extent / patternLength > 10000) { + // approximate stream of tiny dashes with semi-transparent solid line + pen.setStyle(Qt::SolidLine); + QColor color(pen.color()); + color.setAlpha(color.alpha() / 2); + pen.setColor(color); + } + } + if (!qpen_fast_equals(pen, d->strokerPen)) { d->strokerPen = pen; d->stroker.setJoinStyle(pen.joinStyle()); @@ -430,14 +462,8 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) return; } - if (pen.style() > Qt::SolidLine) { - if (pen.isCosmetic()) { - d->activeStroker->setClipRect(d->exDeviceRect); - } else { - QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect)); - d->activeStroker->setClipRect(clipRect); - } - } + if (!clipRect.isNull()) + d->activeStroker->setClipRect(clipRect); if (d->activeStroker == &d->stroker) d->stroker.setForceOpen(path.hasExplicitOpen()); diff --git a/tests/auto/other/lancelot/scripts/tinydashes.qps b/tests/auto/other/lancelot/scripts/tinydashes.qps new file mode 100644 index 00000000000..d41ced7f5f9 --- /dev/null +++ b/tests/auto/other/lancelot/scripts/tinydashes.qps @@ -0,0 +1,34 @@ +# Version: 1 +# CheckVsReference: 5% + +path_addEllipse mypath 20.0 20.0 200.0 200.0 + +save +setPen blue 20 SolidLine FlatCap +pen_setCosmetic true +pen_setDashPattern [ 0.0004 0.0004 ] +setBrush yellow + +drawPath mypath +translate 300 0 +setRenderHint Antialiasing true +drawPath mypath +restore + +path_addEllipse bigpath 200000.0 200000.0 2000000.0 2000000.0 + +setPen blue 20 DotLine FlatCap +setBrush yellow + +save +translate 0 300 +scale 0.0001 0.00011 +drawPath bigpath +restore + +save +translate 300 300 +setRenderHint Antialiasing true +scale 0.0001 0.00011 +drawPath bigpath +restore