From 217f3d83d74507e40ee5a6f43b026bb440515d6e Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 6 Jun 2018 17:12:45 +0200 Subject: [PATCH 01/11] tst_QWidget: Skip based on capabilities instead of platform == wayland Skip based on support for window activation instead of platform. Makes it clear why the tests are skipped, and also enables them automatically if we implement a shell extension that adds support for it. Task-number: QTBUG-66849 Change-Id: I322aba5ce5f8db651db7b71f223ffacec037c920 Reviewed-by: Richard Moe Gustavsen --- .../widgets/kernel/qwidget/tst_qwidget.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 0ac8ccdbe7..9e30f17fa9 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -2418,8 +2418,8 @@ void tst_QWidget::showMinimizedKeepsFocus() { if (m_platform == QStringLiteral("xcb")) QSKIP("QTBUG-26424"); - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported."); if (m_platform == QStringLiteral("offscreen")) QSKIP("Platform offscreen does not support showMinimized()"); @@ -2625,8 +2625,8 @@ void tst_QWidget::icon() void tst_QWidget::hideWhenFocusWidgetIsChild() { - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported."); QScopedPointer testWidget(new QWidget); testWidget->setWindowTitle(__FUNCTION__); @@ -5433,8 +5433,8 @@ void tst_QWidget::multipleToplevelFocusCheck() QSKIP("QTBUG-52974"); #endif - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported"); else if (m_platform == QStringLiteral("winrt")) QSKIP("Winrt: Sometimes crashes in QTextLayout. - QTBUG-68297"); TopLevelFocusCheck w1; @@ -9535,8 +9535,8 @@ void tst_QWidget::setGraphicsEffect() void tst_QWidget::activateWindow() { - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported."); // Test case for QTBUG-26711 @@ -9603,8 +9603,8 @@ void tst_QWidget::openModal_taskQTBUG_5804() void tst_QWidget::focusProxyAndInputMethods() { - if (m_platform == QStringLiteral("wayland")) - QSKIP("Wayland: This fails. Figure out why."); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) + QSKIP("Window activation is not supported."); QScopedPointer toplevel(new QWidget(0, Qt::X11BypassWindowManagerHint)); toplevel->resize(200, 200); toplevel->setAttribute(Qt::WA_InputMethodEnabled, true); From e7e557cea2f35031cf3a51fcb8fa7a275625830f Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 29 Mar 2019 16:05:25 +0100 Subject: [PATCH 02/11] moc: Add a standard way of specifying a URI as part of Q_PLUGIN_METADATA Usually, when you load a plugin, you don't want to load just any plugin that fulfills a given interface, but rather a specific one. When loading dynamic plugins you can differentiate the plugins by file name. This doesn't work in the static case, and file names are also separate from the plugin metadata shipped inside the plugin files. To solve this problem, different hacks have been developed in various places. QML extension plugins add a special property "uri" via the -M option of moc, QML debug plugins expect you to add a json file with an array of "Keys", Qt Creator plugins have a "Name" in their json files, etc. By allowing the identifier for the plugin to be specified inline with the metadata declaration we can make many of the above workarounds obsolete and provide a clean way for users to find their plugins. Task-number: QTBUG-74775 Change-Id: Ie2af16c49d4c5aa5a77fab0fae1e0a4449bd7a39 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/plugin/qplugin_p.h | 6 ++++-- src/tools/moc/generator.cpp | 6 ++++++ src/tools/moc/moc.cpp | 4 ++++ src/tools/moc/moc.h | 1 + .../auto/corelib/plugin/qpluginloader/staticplugin/main.cpp | 2 +- .../auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp | 1 + 6 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/corelib/plugin/qplugin_p.h b/src/corelib/plugin/qplugin_p.h index 717129268b..ce45ebf700 100644 --- a/src/corelib/plugin/qplugin_p.h +++ b/src/corelib/plugin/qplugin_p.h @@ -60,7 +60,8 @@ enum class QtPluginMetaDataKeys { Requirements, IID, ClassName, - MetaData + MetaData, + URI }; // F(IntKey, StringKey, Description) @@ -68,7 +69,8 @@ enum class QtPluginMetaDataKeys { #define QT_PLUGIN_FOREACH_METADATA(F) \ F(QtPluginMetaDataKeys::IID, "IID", "Plugin's Interface ID") \ F(QtPluginMetaDataKeys::ClassName, "className", "Plugin class name") \ - F(QtPluginMetaDataKeys::MetaData, "MetaData", "Other meta data") + F(QtPluginMetaDataKeys::MetaData, "MetaData", "Other meta data") \ + F(QtPluginMetaDataKeys::URI, "URI", "Plugin URI") QT_END_NAMESPACE diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 02c1fbd394..ab7e400f47 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1652,6 +1652,12 @@ void Generator::generatePluginMetaData() jsonObjectToCbor(&map, o); } + if (!cdef->pluginData.uri.isEmpty()) { + dev.nextItem("\"URI\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::URI)); + cbor_encode_text_string(&map, cdef->pluginData.uri.constData(), cdef->pluginData.uri.size()); + } + // Add -M args from the command line: for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it) { const QJsonArray &a = it.value(); diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 2f52dd6ca0..7f43917f7e 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -1311,6 +1311,9 @@ void Moc::parsePluginData(ClassDef *def) if (l == "IID") { next(STRING_LITERAL); def->pluginData.iid = unquotedLexem(); + } else if (l == "URI") { + next(STRING_LITERAL); + def->pluginData.uri = unquotedLexem(); } else if (l == "FILE") { next(STRING_LITERAL); QByteArray metaDataFile = unquotedLexem(); @@ -1351,6 +1354,7 @@ void Moc::parsePluginData(ClassDef *def) + " does not contain a valid JSON object. Declaration will be ignored"; warning(msg.constData()); def->pluginData.iid = QByteArray(); + def->pluginData.uri = QByteArray(); return; } } diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h index 2bba8a5bb9..bb1c9501fe 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -167,6 +167,7 @@ struct ClassDef : BaseDef { struct PluginData { QByteArray iid; + QByteArray uri; QMap metaArgs; QJsonDocument metaData; } pluginData; diff --git a/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp b/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp index d891839b1e..6d163ea336 100644 --- a/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp @@ -31,7 +31,7 @@ class StaticPlugin : public QObject { Q_OBJECT - Q_PLUGIN_METADATA(IID "SomeIID") + Q_PLUGIN_METADATA(IID "SomeIID" URI "qt.test.pluginloader.staticplugin") public: StaticPlugin() {} }; diff --git a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp index 4316ea14ea..b06000d9c4 100644 --- a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp @@ -552,6 +552,7 @@ void tst_QPluginLoader::staticPlugins() QCOMPARE(metaData.value("version").toInt(), QT_VERSION); QCOMPARE(metaData.value("IID").toString(), "SomeIID"); QCOMPARE(metaData.value("ExtraMetaData"), QJsonArray({ "StaticPlugin", "foo" })); + QCOMPARE(metaData.value("URI").toString(), "qt.test.pluginloader.staticplugin"); } From d63a76af8c9bec213d6968627f6985b1267b409e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 9 Jan 2019 14:59:21 +0100 Subject: [PATCH 03/11] uic: Refactor WriteInitialization::writeIconProperties() and add Python Unfold the function with returns to reduce nesting and add language handling. Task-number: PYSIDE-797 Change-Id: Ie6c47745b118d75c0bb2c9eea7d52c8f0377f1a6 Reviewed-by: Cristian Maureira-Fredes --- src/tools/uic/cpp/cppwriteinitialization.cpp | 107 +++++++++++-------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index 6ff7323b3d..8aea864be5 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.cpp +++ b/src/tools/uic/cpp/cppwriteinitialization.cpp @@ -1760,55 +1760,76 @@ QString WriteInitialization::writeIconProperties(const DomResourceIcon *i) // check cache const IconHandle iconHandle(i); const IconPropertiesNameMap::const_iterator it = m_iconPropertiesNameMap.constFind(iconHandle); - if (it != m_iconPropertiesNameMap.constEnd()) { + if (it != m_iconPropertiesNameMap.constEnd()) return it.value(); - } // insert with new name const QString iconName = m_driver->unique(QLatin1String("icon")); m_iconPropertiesNameMap.insert(IconHandle(i), iconName); - if (isIconFormat44(i)) { - if (i->attributeTheme().isEmpty()) { - // No theme: Write resource icon as is - m_output << m_indent << "QIcon " << iconName << ";\n"; - if (m_uic->pixmapFunction().isEmpty()) - writeResourceIcon(m_output, iconName, m_indent, i); - else - writePixmapFunctionIcon(m_output, iconName, m_indent, i); - } else { - // Theme: Generate code to check the theme and default to resource - if (iconHasStatePixmaps(i)) { - // Theme + default state pixmaps: - // Generate code to check the theme and default to state pixmaps - m_output << m_indent << "QIcon " << iconName << ";\n"; - const char themeNameStringVariableC[] = "iconThemeName"; - // Store theme name in a variable - m_output << m_indent; - if (m_firstThemeIcon) { // Declare variable string - m_output << "QString "; - m_firstThemeIcon = false; - } - m_output << themeNameStringVariableC << " = " - << language::qstring(i->attributeTheme()) << ";\n"; - m_output << m_indent << "if (QIcon::hasThemeIcon(" - << themeNameStringVariableC - << ")) {\n" - << m_dindent << iconName << " = QIcon::fromTheme(" << themeNameStringVariableC << ");\n" - << m_indent << "} else {\n"; - if (m_uic->pixmapFunction().isEmpty()) - writeResourceIcon(m_output, iconName, m_dindent, i); - else - writePixmapFunctionIcon(m_output, iconName, m_dindent, i); - m_output << m_indent << "}\n"; - } else { - // Theme, but no state pixmaps: Construct from theme directly. - m_output << m_indent << "QIcon " << iconName << "(QIcon::fromTheme(" - << language::qstring(i->attributeTheme()) << "));\n"; - } // Theme, but not state - } // >= 4.4 - } else { // pre-4.4 legacy - m_output << m_indent << "const QIcon " << iconName << " = " << pixCall(QLatin1String("QIcon"), i->text())<< ";\n"; + + const bool isCpp = language::language() == Language::Cpp; + + if (Q_UNLIKELY(!isIconFormat44(i))) { // pre-4.4 legacy + m_output << m_indent; + if (isCpp) + m_output << "const QIcon "; + m_output << iconName << " = " << pixCall(QLatin1String("QIcon"), i->text()) + << language::eol; + return iconName; } + + // 4.4 onwards + if (i->attributeTheme().isEmpty()) { + // No theme: Write resource icon as is + m_output << m_indent << language::stackVariable("QIcon", iconName) + << language::eol; + if (m_uic->pixmapFunction().isEmpty()) + writeResourceIcon(m_output, iconName, m_indent, i); + else + writePixmapFunctionIcon(m_output, iconName, m_indent, i); + return iconName; + } + + // Theme: Generate code to check the theme and default to resource + if (iconHasStatePixmaps(i)) { + // Theme + default state pixmaps: + // Generate code to check the theme and default to state pixmaps + m_output << m_indent << language::stackVariable("QIcon", iconName) << ";\n"; + const char themeNameStringVariableC[] = "iconThemeName"; + // Store theme name in a variable + m_output << m_indent; + if (m_firstThemeIcon) { // Declare variable string + if (isCpp) + m_output << "QString "; + m_firstThemeIcon = false; + } + m_output << themeNameStringVariableC << " = " + << language::qstring(i->attributeTheme()) << language::eol; + m_output << m_indent << "if "; + if (isCpp) + m_output << '('; + m_output << "QIcon" << language::qualifier << "hasThemeIcon(" + << themeNameStringVariableC << ')' << (isCpp ? ") {" : ":") << '\n' + << m_dindent << iconName << " = QIcon" << language::qualifier << "fromTheme(" + << themeNameStringVariableC << ')' << language::eol + << m_indent << (isCpp ? "} else {" : "else:") << '\n'; + if (m_uic->pixmapFunction().isEmpty()) + writeResourceIcon(m_output, iconName, m_dindent, i); + else + writePixmapFunctionIcon(m_output, iconName, m_dindent, i); + m_output << m_indent; + if (isCpp) + m_output << '}'; + m_output << '\n'; + return iconName; + } + + // Theme, but no state pixmaps: Construct from theme directly. + m_output << m_indent + << language::stackVariableWithInitParameters("QIcon", iconName) + << "QIcon" << language::qualifier << "fromTheme(" + << language::qstring(i->attributeTheme()) << "))" + << language::eol; return iconName; } From 6dca11e1af05ddd06439709a210ec225c41276c4 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 10 Jan 2019 10:28:31 +0100 Subject: [PATCH 04/11] uic: Port WriteInitialization::writeBrush() be able to generate Python Task-number: PYSIDE-797 Change-Id: I7c4e204a5ac9be2dee8f06c38323a15a0372fe5c Reviewed-by: Cristian Maureira-Fredes --- src/tools/uic/cpp/cppwriteinitialization.cpp | 46 ++++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index 8aea864be5..afd0376643 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.cpp +++ b/src/tools/uic/cpp/cppwriteinitialization.cpp @@ -1931,31 +1931,36 @@ void WriteInitialization::writeBrush(const DomBrush *brush, const QString &brush const QString gradientType = gradient->attributeType(); const QString gradientName = m_driver->unique(QLatin1String("gradient")); if (gradientType == QLatin1String("LinearGradient")) { - m_output << m_indent << "QLinearGradient " << gradientName - << '(' << gradient->attributeStartX() + m_output << m_indent + << language::stackVariableWithInitParameters("QLinearGradient", gradientName) + << gradient->attributeStartX() << ", " << gradient->attributeStartY() << ", " << gradient->attributeEndX() - << ", " << gradient->attributeEndY() << ");\n"; + << ", " << gradient->attributeEndY() << ')' << language::eol; } else if (gradientType == QLatin1String("RadialGradient")) { - m_output << m_indent << "QRadialGradient " << gradientName - << '(' << gradient->attributeCentralX() + m_output << m_indent + << language::stackVariableWithInitParameters("QRadialGradient", gradientName) + << gradient->attributeCentralX() << ", " << gradient->attributeCentralY() << ", " << gradient->attributeRadius() << ", " << gradient->attributeFocalX() - << ", " << gradient->attributeFocalY() << ");\n"; + << ", " << gradient->attributeFocalY() << ')' << language::eol; } else if (gradientType == QLatin1String("ConicalGradient")) { - m_output << m_indent << "QConicalGradient " << gradientName - << '(' << gradient->attributeCentralX() + m_output << m_indent + << language::stackVariableWithInitParameters("QConicalGradient", gradientName) + << gradient->attributeCentralX() << ", " << gradient->attributeCentralY() - << ", " << gradient->attributeAngle() << ");\n"; + << ", " << gradient->attributeAngle() << ')' << language::eol; } - m_output << m_indent << gradientName << ".setSpread(QGradient::" - << gradient->attributeSpread() << ");\n"; + m_output << m_indent << gradientName << ".setSpread(QGradient" + << language::qualifier << gradient->attributeSpread() + << ')' << language::eol; if (gradient->hasAttributeCoordinateMode()) { - m_output << m_indent << gradientName << ".setCoordinateMode(QGradient::" - << gradient->attributeCoordinateMode() << ");\n"; + m_output << m_indent << gradientName << ".setCoordinateMode(QGradient" + << language::qualifier << gradient->attributeCoordinateMode() + << ')' << language::eol; } const auto &stops = gradient->elementGradientStop(); @@ -1963,19 +1968,22 @@ void WriteInitialization::writeBrush(const DomBrush *brush, const QString &brush const DomColor *color = stop->elementColor(); m_output << m_indent << gradientName << ".setColorAt(" << stop->attributePosition() << ", " - << domColor2QString(color) << ");\n"; + << domColor2QString(color) << ')' << language::eol; } - m_output << m_indent << "QBrush " << brushName << '(' - << gradientName << ");\n"; + m_output << m_indent + << language::stackVariableWithInitParameters("QBrush", brushName) + << gradientName << ')' << language::eol; } else if (style == QLatin1String("TexturePattern")) { const DomProperty *property = brush->elementTexture(); const QString iconValue = iconCall(property); - m_output << m_indent << "QBrush " << brushName << " = QBrush(" - << iconValue << ");\n"; + m_output << m_indent + << language::stackVariableWithInitParameters("QBrush", brushName) + << iconValue << ')' << language::eol; } else { const DomColor *color = brush->elementColor(); - m_output << m_indent << "QBrush " << brushName << '(' + m_output << m_indent + << language::stackVariableWithInitParameters("QBrush", brushName) << domColor2QString(color) << ')' << language::eol; m_output << m_indent << brushName << ".setStyle(" From 8f44aeb10317664dd7cae92e628fb0814e432e17 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 2 Jul 2018 13:20:39 +0200 Subject: [PATCH 05/11] Add Extended RGB model to QColor Can be used to represent wide-gamut and HDR colors. Change-Id: I1cca442069ce2f2c070f723fe930fe1f2f5580ad Reviewed-by: Lars Knoll --- src/gui/painting/qcolor.cpp | 226 +++++++++++++----- src/gui/painting/qcolor.h | 10 +- src/gui/painting/qcolortransform.cpp | 41 +++- src/gui/painting/qcolortrc_p.h | 21 +- tests/auto/gui/painting/qcolor/tst_qcolor.cpp | 215 ++++++++++------- .../painting/qcolorspace/tst_qcolorspace.cpp | 55 +++++ 6 files changed, 411 insertions(+), 157 deletions(-) diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index bb42660cf2..174350d884 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -39,6 +39,7 @@ #include "qcolor.h" #include "qcolor_p.h" +#include "qfloat16.h" #include "qnamespace.h" #include "qdatastream.h" #include "qvariant.h" @@ -494,6 +495,14 @@ static QStringList get_colornames() with this value, a pixel value will be used that is appropriate for the underlying pixel format in use. + \section1 The Extended RGB Color Model + + The extended RGB color model, also known as the scRGB color space, + is the same the RGB color model except it allows values under 0.0, + and over 1.0. This makes it possible to represent colors that would + otherwise be outside the range of the RGB colorspace but still use + the same values for colors inside the RGB colorspace. + \section1 The HSV Color Model The RGB model is hardware-oriented. Its representation is close to @@ -603,12 +612,13 @@ static QStringList get_colornames() /*! \enum QColor::Spec - The type of color specified, either RGB, HSV, CMYK or HSL. + The type of color specified, either RGB, extended RGB, HSV, CMYK or HSL. \value Rgb \value Hsv \value Cmyk \value Hsl + \value ExtendedRgb \value Invalid \sa spec(), convertTo() @@ -778,6 +788,10 @@ QColor::QColor(Spec spec) noexcept case Hsl: setHsl(0, 0, 0, 0); break; + case ExtendedRgb: + cspec = spec; + setRgbF(0, 0, 0, 0); + break; } } @@ -1211,6 +1225,17 @@ void QColor::setHsl(int h, int s, int l, int a) ct.ahsl.pad = 0; } +static inline qfloat16 &castF16(quint16 &v) +{ + // this works because qfloat16 internally is a quint16 + return *reinterpret_cast(&v); +} + +static inline const qfloat16 &castF16(const quint16 &v) +{ + return *reinterpret_cast(&v); +} + /*! Sets the contents pointed to by \a r, \a g, \a b, and \a a, to the red, green, blue, and alpha-channel (transparency) components of the color's @@ -1226,18 +1251,27 @@ void QColor::getRgbF(qreal *r, qreal *g, qreal *b, qreal *a) const if (!r || !g || !b) return; - if (cspec != Invalid && cspec != Rgb) { + if (cspec == Invalid) + return; + + if (cspec != Rgb && cspec != ExtendedRgb) { toRgb().getRgbF(r, g, b, a); return; } - *r = ct.argb.red / qreal(USHRT_MAX); - *g = ct.argb.green / qreal(USHRT_MAX); - *b = ct.argb.blue / qreal(USHRT_MAX); - - if (a) - *a = ct.argb.alpha / qreal(USHRT_MAX); - + if (cspec == Rgb) { + *r = ct.argb.red / qreal(USHRT_MAX); + *g = ct.argb.green / qreal(USHRT_MAX); + *b = ct.argb.blue / qreal(USHRT_MAX); + if (a) + *a = ct.argb.alpha / qreal(USHRT_MAX); + } else { + *r = castF16(ct.argbExtended.redF16); + *g = castF16(ct.argbExtended.greenF16); + *b = castF16(ct.argbExtended.blueF16); + if (a) + *a = castF16(ct.argbExtended.alphaF16); + } } /*! @@ -1274,26 +1308,35 @@ void QColor::getRgb(int *r, int *g, int *b, int *a) const Sets the color channels of this color to \a r (red), \a g (green), \a b (blue) and \a a (alpha, transparency). - All values must be in the range 0.0-1.0. + The alpha value must be in the range 0.0-1.0. + If any of the other values are outside the range of 0.0-1.0 the + color model will be set as \c ExtendedRgb. \sa rgb(), getRgbF(), setRgb() */ void QColor::setRgbF(qreal r, qreal g, qreal b, qreal a) { - if (r < qreal(0.0) || r > qreal(1.0) - || g < qreal(0.0) || g > qreal(1.0) - || b < qreal(0.0) || b > qreal(1.0) - || a < qreal(0.0) || a > qreal(1.0)) { - qWarning("QColor::setRgbF: RGB parameters out of range"); + if (a < qreal(0.0) || a > qreal(1.0)) { + qWarning("QColor::setRgbF: Alpha parameter is out of range"); invalidate(); return; } - + if (r < qreal(0.0) || r > qreal(1.0) || + g < qreal(0.0) || g > qreal(1.0) || + b < qreal(0.0) || b > qreal(1.0) || cspec == ExtendedRgb) { + cspec = ExtendedRgb; + castF16(ct.argbExtended.redF16) = qfloat16(r); + castF16(ct.argbExtended.greenF16) = qfloat16(g); + castF16(ct.argbExtended.blueF16) = qfloat16(b); + castF16(ct.argbExtended.alphaF16) = qfloat16(a); + ct.argbExtended.pad = 0; + return; + } cspec = Rgb; - ct.argb.alpha = qRound(a * USHRT_MAX); ct.argb.red = qRound(r * USHRT_MAX); ct.argb.green = qRound(g * USHRT_MAX); ct.argb.blue = qRound(b * USHRT_MAX); + ct.argb.alpha = qRound(a * USHRT_MAX); ct.argb.pad = 0; } @@ -1421,7 +1464,11 @@ void QColor::setRgb(QRgb rgb) noexcept \sa setAlpha(), alphaF(), {QColor#Alpha-Blended Drawing}{Alpha-Blended Drawing} */ int QColor::alpha() const noexcept -{ return ct.argb.alpha >> 8; } +{ + if (cspec == ExtendedRgb) + return qRound(qreal(castF16(ct.argbExtended.alphaF16)) * 255); + return ct.argb.alpha >> 8; +} /*! @@ -1434,6 +1481,11 @@ int QColor::alpha() const noexcept void QColor::setAlpha(int alpha) { QCOLOR_INT_RANGE_CHECK("QColor::setAlpha", alpha); + if (cspec == ExtendedRgb) { + constexpr qreal f = qreal(1.0) / 255; + castF16(ct.argbExtended.alphaF16) = alpha * f; + return; + } ct.argb.alpha = alpha * 0x101; } @@ -1443,7 +1495,11 @@ void QColor::setAlpha(int alpha) \sa setAlphaF(), alpha(), {QColor#Alpha-Blended Drawing}{Alpha-Blended Drawing} */ qreal QColor::alphaF() const noexcept -{ return ct.argb.alpha / qreal(USHRT_MAX); } +{ + if (cspec == ExtendedRgb) + return castF16(ct.argbExtended.alphaF16); + return ct.argb.alpha / qreal(USHRT_MAX); +} /*! Sets the alpha of this color to \a alpha. qreal alpha is specified in the @@ -1455,6 +1511,10 @@ qreal QColor::alphaF() const noexcept void QColor::setAlphaF(qreal alpha) { QCOLOR_REAL_RANGE_CHECK("QColor::setAlphaF", alpha); + if (cspec == ExtendedRgb) { + castF16(ct.argbExtended.alphaF16) = alpha; + return; + } qreal tmp = alpha * USHRT_MAX; ct.argb.alpha = qRound(tmp); } @@ -1550,25 +1610,29 @@ void QColor::setBlue(int blue) */ qreal QColor::redF() const noexcept { - if (cspec != Invalid && cspec != Rgb) - return toRgb().redF(); - return ct.argb.red / qreal(USHRT_MAX); + if (cspec == Rgb || cspec == Invalid) + return ct.argb.red / qreal(USHRT_MAX); + if (cspec == ExtendedRgb) + return castF16(ct.argbExtended.redF16); + + return toRgb().redF(); } /*! - Sets the red color component of this color to \a red. Float components - are specified in the range 0.0-1.0. + Sets the red color component of this color to \a red. If \a red lies outside + the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb. \sa redF(), red(), setRgbF() */ void QColor::setRedF(qreal red) { - QCOLOR_REAL_RANGE_CHECK("QColor::setRedF", red); - if (cspec != Rgb) - setRgbF(red, greenF(), blueF(), alphaF()); - else + if (cspec == Rgb && red >= qreal(0.0) && red <= qreal(1.0)) ct.argb.red = qRound(red * USHRT_MAX); + else if (cspec == ExtendedRgb) + castF16(ct.argbExtended.redF16) = red; + else + setRgbF(red, greenF(), blueF(), alphaF()); } /*! @@ -1578,25 +1642,29 @@ void QColor::setRedF(qreal red) */ qreal QColor::greenF() const noexcept { - if (cspec != Invalid && cspec != Rgb) - return toRgb().greenF(); - return ct.argb.green / qreal(USHRT_MAX); + if (cspec == Rgb || cspec == Invalid) + return ct.argb.green / qreal(USHRT_MAX); + if (cspec == ExtendedRgb) + return castF16(ct.argbExtended.greenF16); + + return toRgb().greenF(); } /*! - Sets the green color component of this color to \a green. Float components - are specified in the range 0.0-1.0. + Sets the green color component of this color to \a green. If \a green lies outside + the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb. \sa greenF(), green(), setRgbF() */ void QColor::setGreenF(qreal green) { - QCOLOR_REAL_RANGE_CHECK("QColor::setGreenF", green); - if (cspec != Rgb) - setRgbF(redF(), green, blueF(), alphaF()); - else + if (cspec == Rgb && green >= qreal(0.0) && green <= qreal(1.0)) ct.argb.green = qRound(green * USHRT_MAX); + else if (cspec == ExtendedRgb) + castF16(ct.argbExtended.greenF16) = green; + else + setRgbF(redF(), green, blueF(), alphaF()); } /*! @@ -1606,24 +1674,27 @@ void QColor::setGreenF(qreal green) */ qreal QColor::blueF() const noexcept { - if (cspec != Invalid && cspec != Rgb) - return toRgb().blueF(); - return ct.argb.blue / qreal(USHRT_MAX); + if (cspec == Rgb || cspec == Invalid) + return ct.argb.blue / qreal(USHRT_MAX); + if (cspec == ExtendedRgb) + return castF16(ct.argbExtended.blueF16); + + return toRgb().blueF(); } /*! - Sets the blue color component of this color to \a blue. Float components - are specified in the range 0.0-1.0. - + Sets the blue color component of this color to \a blue. If \a blue lies outside + the 0.0-1.0 range, the color model will be changed to \c ExtendedRgb. \sa blueF(), blue(), setRgbF() */ void QColor::setBlueF(qreal blue) { - QCOLOR_REAL_RANGE_CHECK("QColor::setBlueF", blue); - if (cspec != Rgb) - setRgbF(redF(), greenF(), blue, alphaF()); - else + if (cspec == Rgb && blue >= qreal(0.0) && blue <= qreal(1.0)) ct.argb.blue = qRound(blue * USHRT_MAX); + else if (cspec == ExtendedRgb) + castF16(ct.argbExtended.blueF16) = blue; + else + setRgbF(redF(), greenF(), blue, alphaF()); } /*! @@ -1932,6 +2003,30 @@ qreal QColor::blackF() const noexcept return ct.acmyk.black / qreal(USHRT_MAX); } +/*! + Create and returns an extended RGB QColor based on this color. + \since 5.14 + + \sa toRgb, convertTo() +*/ +QColor QColor::toExtendedRgb() const noexcept +{ + if (!isValid() || cspec == ExtendedRgb) + return *this; + if (cspec != Rgb) + return toRgb().toExtendedRgb(); + + constexpr qreal f = qreal(1.0) / USHRT_MAX; + QColor color; + color.cspec = ExtendedRgb; + castF16(color.ct.argbExtended.alphaF16) = qfloat16(ct.argb.alpha * f); + castF16(color.ct.argbExtended.redF16) = qfloat16(ct.argb.red * f); + castF16(color.ct.argbExtended.greenF16) = qfloat16(ct.argb.green * f); + castF16(color.ct.argbExtended.blueF16) = qfloat16(ct.argb.blue * f); + color.ct.argbExtended.pad = 0; + return color; +} + /*! Create and returns an RGB QColor based on this color. @@ -1944,7 +2039,8 @@ QColor QColor::toRgb() const noexcept QColor color; color.cspec = Rgb; - color.ct.argb.alpha = ct.argb.alpha; + if (cspec != ExtendedRgb) + color.ct.argb.alpha = ct.argb.alpha; color.ct.argb.pad = 0; switch (cspec) { @@ -2066,6 +2162,12 @@ QColor QColor::toRgb() const noexcept color.ct.argb.blue = qRound((qreal(1.0) - (y * (qreal(1.0) - k) + k)) * USHRT_MAX); break; } + case ExtendedRgb: + color.ct.argb.alpha = qRound(USHRT_MAX * qreal(castF16(ct.argbExtended.alphaF16))); + color.ct.argb.red = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.redF16)), qreal(1.0))); + color.ct.argb.green = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.greenF16)), qreal(1.0))); + color.ct.argb.blue = qRound(USHRT_MAX * qBound(qreal(0.0), qreal(castF16(ct.argbExtended.blueF16)), qreal(1.0))); + break; default: break; } @@ -2238,6 +2340,8 @@ QColor QColor::convertTo(QColor::Spec colorSpec) const noexcept switch (colorSpec) { case Rgb: return toRgb(); + case ExtendedRgb: + return toExtendedRgb(); case Hsv: return toHsv(); case Cmyk: @@ -2317,20 +2421,32 @@ QColor QColor::fromRgb(int r, int g, int b, int a) color values, \a r (red), \a g (green), \a b (blue), and \a a (alpha-channel, i.e. transparency). - All the values must be in the range 0.0-1.0. + The alpha value must be in the range 0.0-1.0. + If any of the other values are outside the range of 0.0-1.0 the + color model will be set as \c ExtendedRgb. \sa fromRgb(), fromRgba64(), toRgb(), isValid() */ QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a) { - if (r < qreal(0.0) || r > qreal(1.0) - || g < qreal(0.0) || g > qreal(1.0) - || b < qreal(0.0) || b > qreal(1.0) - || a < qreal(0.0) || a > qreal(1.0)) { - qWarning("QColor::fromRgbF: RGB parameters out of range"); + if (a < qreal(0.0) || a > qreal(1.0)) { + qWarning("QColor::fromRgbF: Alpha parameter out of range"); return QColor(); } + if (r < qreal(0.0) || r > qreal(1.0) + || g < qreal(0.0) || g > qreal(1.0) + || b < qreal(0.0) || b > qreal(1.0)) { + QColor color; + color.cspec = ExtendedRgb; + castF16(color.ct.argbExtended.alphaF16) = qfloat16(a); + castF16(color.ct.argbExtended.redF16) = qfloat16(r); + castF16(color.ct.argbExtended.greenF16) = qfloat16(g); + castF16(color.ct.argbExtended.blueF16) = qfloat16(b); + color.ct.argbExtended.pad = 0; + return color; + } + QColor color; color.cspec = Rgb; color.ct.argb.alpha = qRound(a * USHRT_MAX); @@ -2885,6 +3001,8 @@ QDebug operator<<(QDebug dbg, const QColor &c) dbg.nospace() << "QColor(Invalid)"; else if (c.spec() == QColor::Rgb) dbg.nospace() << "QColor(ARGB " << c.alphaF() << ", " << c.redF() << ", " << c.greenF() << ", " << c.blueF() << ')'; + else if (c.spec() == QColor::ExtendedRgb) + dbg.nospace() << "QColor(Ext. ARGB " << c.alphaF() << ", " << c.redF() << ", " << c.greenF() << ", " << c.blueF() << ')'; else if (c.spec() == QColor::Hsv) dbg.nospace() << "QColor(AHSV " << c.alphaF() << ", " << c.hueF() << ", " << c.saturationF() << ", " << c.valueF() << ')'; else if (c.spec() == QColor::Cmyk) diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h index cbc8b98f9c..77b2d43c40 100644 --- a/src/gui/painting/qcolor.h +++ b/src/gui/painting/qcolor.h @@ -64,7 +64,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QColor &); class Q_GUI_EXPORT QColor { public: - enum Spec { Invalid, Rgb, Hsv, Cmyk, Hsl }; + enum Spec { Invalid, Rgb, Hsv, Cmyk, Hsl, ExtendedRgb }; enum NameFormat { HexRgb, HexArgb }; inline QColor() noexcept; @@ -198,6 +198,7 @@ public: QColor toHsv() const noexcept; QColor toCmyk() const noexcept; QColor toHsl() const noexcept; + QColor toExtendedRgb() const noexcept; Q_REQUIRED_RESULT QColor convertTo(Spec colorSpec) const noexcept; @@ -275,6 +276,13 @@ private: ushort lightness; ushort pad; } ahsl; + struct { + ushort alphaF16; + ushort redF16; + ushort greenF16; + ushort blueF16; + ushort pad; + } argbExtended; ushort array[5]; } ct; diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp index b677c4b36b..c723e12f8a 100644 --- a/src/gui/painting/qcolortransform.cpp +++ b/src/gui/painting/qcolortransform.cpp @@ -204,19 +204,36 @@ QColor QColorTransform::map(const QColor &color) const if (!d_ptr) return color; Q_D(const QColorTransform); - QColorVector c = { (float)color.redF(), (float)color.greenF(), (float)color.blueF() }; - c.x = d->colorSpaceIn->trc[0].apply(c.x); - c.y = d->colorSpaceIn->trc[1].apply(c.y); - c.z = d->colorSpaceIn->trc[2].apply(c.z); - c = d->colorMatrix.map(c); - if (d_ptr->colorSpaceOut->lutsGenerated.loadAcquire()) { - c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x); - c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y); - c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z); + QColor clr = color; + if (color.spec() != QColor::ExtendedRgb || color.spec() != QColor::Rgb) + clr = clr.toRgb(); + + QColorVector c = { (float)clr.redF(), (float)clr.greenF(), (float)clr.blueF() }; + if (clr.spec() == QColor::ExtendedRgb) { + c.x = d->colorSpaceIn->trc[0].applyExtended(c.x); + c.y = d->colorSpaceIn->trc[1].applyExtended(c.y); + c.z = d->colorSpaceIn->trc[2].applyExtended(c.z); } else { - c.x = d->colorSpaceOut->trc[0].applyInverse(c.x); - c.y = d->colorSpaceOut->trc[1].applyInverse(c.y); - c.z = d->colorSpaceOut->trc[2].applyInverse(c.z); + c.x = d->colorSpaceIn->trc[0].apply(c.x); + c.y = d->colorSpaceIn->trc[1].apply(c.y); + c.z = d->colorSpaceIn->trc[2].apply(c.z); + } + c = d->colorMatrix.map(c); + bool inGamut = c.x >= 0.0f && c.x <= 1.0f && c.y >= 0.0f && c.y <= 1.0f && c.z >= 0.0f && c.z <= 1.0f; + if (inGamut) { + if (d_ptr->colorSpaceOut->lutsGenerated.loadAcquire()) { + c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x); + c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y); + c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z); + } else { + c.x = d->colorSpaceOut->trc[0].applyInverse(c.x); + c.y = d->colorSpaceOut->trc[1].applyInverse(c.y); + c.z = d->colorSpaceOut->trc[2].applyInverse(c.z); + } + } else { + c.x = d->colorSpaceOut->trc[0].applyInverseExtended(c.x); + c.y = d->colorSpaceOut->trc[1].applyInverseExtended(c.y); + c.z = d->colorSpaceOut->trc[2].applyInverseExtended(c.z); } QColor out; out.setRgbF(c.x, c.y, c.z, color.alphaF()); diff --git a/src/gui/painting/qcolortrc_p.h b/src/gui/painting/qcolortrc_p.h index 3a649f3756..3ef9d442fc 100644 --- a/src/gui/painting/qcolortrc_p.h +++ b/src/gui/painting/qcolortrc_p.h @@ -91,7 +91,16 @@ public: return m_fun.apply(x); return x; } - + float applyExtended(float x) const + { + if (x >= 0.0f && x <= 1.0f) + return apply(x); + if (m_type == Type::Function) + return std::copysign(m_fun.apply(std::abs(x)), x); + if (m_type == Type::Table) + return x < 0.0f ? 0.0f : 1.0f; + return x; + } float applyInverse(float x) const { if (m_type == Type::Table) @@ -100,6 +109,16 @@ public: return m_fun.inverted().apply(x); return x; } + float applyInverseExtended(float x) const + { + if (x >= 0.0f && x <= 1.0f) + return applyInverse(x); + if (m_type == Type::Function) + return std::copysign(applyInverse(x), x); + if (m_type == Type::Table) + return x < 0.0f ? 0.0f : 1.0f; + return x; + } friend inline bool operator!=(const QColorTrc &o1, const QColorTrc &o2); friend inline bool operator==(const QColorTrc &o1, const QColorTrc &o2); diff --git a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp index 13d0618bd9..4d92bdd382 100644 --- a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp +++ b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp @@ -70,6 +70,7 @@ private slots: void setBlue(); void setRgb(); + void setRgbF(); void setRgba(); void setHsv(); void setCmyk(); @@ -187,28 +188,28 @@ void tst_QColor::getSetCheck() // void QColor::setRedF(qreal) obj1.setRedF(0.0); QCOMPARE(obj1.redF(), qreal(0.0)); - obj1.setRedF(-0.2); - QCOMPARE(obj1.redF(), qreal(0.0)); // range<0.0, 1.0 - obj1.setRedF(1.1); - QCOMPARE(obj1.redF(), qreal(1.0)); // range<0.0, 1.0 + obj1.setRedF(-0.25); + QCOMPARE(obj1.redF(), qreal(-0.25)); + obj1.setRedF(1.25); + QCOMPARE(obj1.redF(), qreal(1.25)); // qreal QColor::greenF() // void QColor::setGreenF(qreal) obj1.setGreenF(0.0); QCOMPARE(obj1.greenF(), qreal(0.0)); - obj1.setGreenF(-0.2); - QCOMPARE(obj1.greenF(), qreal(0.0)); // range<0.0, 1.0 - obj1.setGreenF(1.1); - QCOMPARE(obj1.greenF(), qreal(1.0)); // range<0.0, 1.0 + obj1.setGreenF(-0.25); + QCOMPARE(obj1.greenF(), qreal(-0.25)); + obj1.setGreenF(1.5); + QCOMPARE(obj1.greenF(), qreal(1.5)); // qreal QColor::blueF() // void QColor::setBlueF(qreal) obj1.setBlueF(0.0); QCOMPARE(obj1.blueF(), qreal(0.0)); - obj1.setBlueF(-0.2); - QCOMPARE(obj1.blueF(), qreal(0.0)); // range<0.0, 1.0 - obj1.setBlueF(1.1); - QCOMPARE(obj1.blueF(), qreal(1.0)); // range<0.0, 1.0 + obj1.setBlueF(-0.5); + QCOMPARE(obj1.blueF(), qreal(-0.5)); + obj1.setBlueF(2.0); + QCOMPARE(obj1.blueF(), qreal(2.0)); // QRgb QColor::rgba() // void QColor::setRgba(QRgb) @@ -677,30 +678,81 @@ void tst_QColor::setRgb() { QColor color; + for (int a = 0; a <= 255; ++a) { + QRgb rgb = qRgba(0, 0, 0, a); + + color.setRgb(0, 0, 0, a); + QCOMPARE(color.alpha(), a); + QCOMPARE(color.rgb(), qRgb(0, 0, 0)); + + color.setRgb(rgb); + QCOMPARE(color.alpha(), 255); + QCOMPARE(color.rgb(), qRgb(0, 0, 0)); + + int r, g, b, a2; + color.setRgb(0, 0, 0, a); + color.getRgb(&r, &g, &b, &a2); + QCOMPARE(a2, a); + + QColor c(0, 0, 0); + c.setAlpha(a); + QCOMPARE(c.alpha(), a); + } + + for (int r = 0; r <= 255; ++r) { + QRgb rgb = qRgb(r, 0, 0); + + color.setRgb(r, 0, 0); + QCOMPARE(color.red(), r); + QCOMPARE(color.rgb(), rgb); + + color.setRgb(rgb); + QCOMPARE(color.red(), r); + QCOMPARE(color.rgb(), rgb); + + int r2, g, b, a; + color.getRgb(&r2, &g, &b, &a); + QCOMPARE(r2, r); + } + + for (int g = 0; g <= 255; ++g) { + QRgb rgb = qRgb(0, g, 0); + + color.setRgb(0, g, 0); + QCOMPARE(color.green(), g); + QCOMPARE(color.rgb(), rgb); + + color.setRgb(rgb); + QCOMPARE(color.green(), g); + QCOMPARE(color.rgb(), rgb); + + int r, g2, b, a; + color.getRgb(&r, &g2, &b, &a); + QCOMPARE(g2, g); + } + + for (int b = 0; b <= 255; ++b) { + QRgb rgb = qRgb(0, 0, b); + + color.setRgb(0, 0, b); + QCOMPARE(color.blue(), b); + QCOMPARE(color.rgb(), rgb); + + color.setRgb(rgb); + QCOMPARE(color.blue(), b); + QCOMPARE(color.rgb(), rgb); + + int r, g, b2, a; + color.getRgb(&r, &g, &b2, &a); + QCOMPARE(b2, b); + } +} + +void tst_QColor::setRgbF() +{ + QColor color; + for (int A = 0; A <= USHRT_MAX; ++A) { - { - // 0-255 - int a = A >> 8; - QRgb rgb = qRgba(0, 0, 0, a); - - color.setRgb(0, 0, 0, a); - QCOMPARE(color.alpha(), a); - QCOMPARE(color.rgb(), qRgb(0, 0, 0)); - - color.setRgb(rgb); - QCOMPARE(color.alpha(), 255); - QCOMPARE(color.rgb(), qRgb(0, 0, 0)); - - int r, g, b, a2; - color.setRgb(0, 0, 0, a); - color.getRgb(&r, &g, &b, &a2); - QCOMPARE(a2, a); - - QColor c(0, 0, 0); - c.setAlpha(a); - QCOMPARE(c.alpha(), a); - } - { // 0.0-1.0 qreal a = A / qreal(USHRT_MAX); @@ -719,24 +771,6 @@ void tst_QColor::setRgb() } for (int R = 0; R <= USHRT_MAX; ++R) { - { - // 0-255 - int r = R >> 8; - QRgb rgb = qRgb(r, 0, 0); - - color.setRgb(r, 0, 0); - QCOMPARE(color.red(), r); - QCOMPARE(color.rgb(), rgb); - - color.setRgb(rgb); - QCOMPARE(color.red(), r); - QCOMPARE(color.rgb(), rgb); - - int r2, g, b, a; - color.getRgb(&r2, &g, &b, &a); - QCOMPARE(r2, r); - } - { // 0.0-1.0 qreal r = R / qreal(USHRT_MAX); @@ -750,24 +784,6 @@ void tst_QColor::setRgb() } for (int G = 0; G <= USHRT_MAX; ++G) { - { - // 0-255 - int g = G >> 8; - QRgb rgb = qRgb(0, g, 0); - - color.setRgb(0, g, 0); - QCOMPARE(color.green(), g); - QCOMPARE(color.rgb(), rgb); - - color.setRgb(rgb); - QCOMPARE(color.green(), g); - QCOMPARE(color.rgb(), rgb); - - int r, g2, b, a; - color.getRgb(&r, &g2, &b, &a); - QCOMPARE(g2, g); - } - { // 0.0-1.0 qreal g = G / qreal(USHRT_MAX); @@ -781,24 +797,6 @@ void tst_QColor::setRgb() } for (int B = 0; B <= USHRT_MAX; ++B) { - { - // 0-255 - int b = B >> 8; - QRgb rgb = qRgb(0, 0, b); - - color.setRgb(0, 0, b); - QCOMPARE(color.blue(), b); - QCOMPARE(color.rgb(), rgb); - - color.setRgb(rgb); - QCOMPARE(color.blue(), b); - QCOMPARE(color.rgb(), rgb); - - int r, g, b2, a; - color.getRgb(&r, &g, &b2, &a); - QCOMPARE(b2, b); - } - { // 0.0-1.0 qreal b = B / qreal(USHRT_MAX); @@ -810,6 +808,45 @@ void tst_QColor::setRgb() QCOMPARE(b2, b); } } + + for (int R = -128; R <= 512; ++R) { + { + // extended RGB + qreal r = R / qreal(256); + color.setRgbF(r, 0.0, 0.0); + QCOMPARE(qfloat16(color.redF()), qfloat16(r)); + + qreal r2, g, b, a; + color.getRgbF(&r2, &g, &b, &a); + QCOMPARE(qfloat16(r2), qfloat16(r)); + } + } + + for (int G = -128; G <= 512; ++G) { + { + // extended RGB + qreal g = G / qreal(256); + color.setRgbF(0.0, g, 0.0); + QCOMPARE(qfloat16(color.greenF()), qfloat16(g)); + + qreal r, g2, b, a; + color.getRgbF(&r, &g2, &b, &a); + QCOMPARE(qfloat16(g2), qfloat16(g)); + } + } + + for (int B = -128; B <= 512; ++B) { + { + // extended RGB + qreal b = B / qreal(256); + color.setRgbF(0.0, 0.0, b); + QCOMPARE(qfloat16(color.blueF()), qfloat16(b)); + + qreal r, g, b2, a; + color.getRgbF(&r, &g, &b2, &a); + QCOMPARE(qfloat16(b2), qfloat16(b)); + } + } } void tst_QColor::setRgba() diff --git a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp index 9bd4b75443..35bca58854 100644 --- a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp +++ b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp @@ -57,6 +57,8 @@ private slots: void imageConversion(); void loadImage(); + + void gamut(); }; tst_QColorSpace::tst_QColorSpace() @@ -232,6 +234,59 @@ void tst_QColorSpace::loadImage() // Test the iccProfile getter returns the ICC profile from the image // which since we didn't write it, isn't identical to our defaults. QVERIFY(defaultProPhotoRgb.iccProfile() != image.colorSpace().iccProfile()); + + QColorTransform transform = image.colorSpace().transformationToColorSpace(QColorSpace::SRgb); + qreal maxRed = 0; + qreal maxBlue = 0; + qreal maxRed2 = 0; + qreal maxBlue2 = 0; + for (int y = 0; y < image.height(); ++y) { + for (int x = 0; x < image.width(); ++x) { + QColor p = image.pixelColor(x, y); + maxRed = std::max(maxRed, p.redF()); + maxBlue = std::max(maxBlue, p.blueF()); + p = transform.map(p); + maxRed2 = std::max(maxRed2, p.redF()); + maxBlue2 = std::max(maxBlue2, p.blueF()); + + } + } + // ProPhotoRgb can be a lot more red and blue than SRgb can, so it will have lower values. + QVERIFY(maxRed2 > maxRed); + QVERIFY(maxBlue2 > maxBlue); +} + +void tst_QColorSpace::gamut() +{ + QColor black = QColor::fromRgbF(0.0, 0.0, 0.0); + QColor white = QColor::fromRgbF(1.0, 1.0, 1.0); + QColor red = QColor::fromRgbF(1.0, 0.0, 0.0); + QColor green = QColor::fromRgbF(0.0, 1.0, 0.0); + QColor blue = QColor::fromRgbF(0.0, 0.0, 1.0); + + QColorTransform toAdobeRgb = QColorSpace(QColorSpace::SRgb).transformationToColorSpace(QColorSpace::AdobeRgb); + + QColor tblack = toAdobeRgb.map(black); + QColor twhite = toAdobeRgb.map(white); + QColor tred = toAdobeRgb.map(red); + QColor tgreen = toAdobeRgb.map(green); + QColor tblue = toAdobeRgb.map(blue); + + // Black is black + QCOMPARE(tblack, black); + + // This white hasn't changed + QCOMPARE(twhite, white); + + // Adobe's red and blue gamut corners are the same as sRGB's + // So, a color in the red corner, will stay in the red corner + // the same for blue, but not for green. + QVERIFY(tred.greenF() < 0.001); + QVERIFY(tred.blueF() < 0.001); + QVERIFY(tblue.redF() < 0.001); + QVERIFY(tblue.greenF() < 0.001); + QVERIFY(tgreen.redF() > 0.2); + QVERIFY(tgreen.blueF() > 0.2); } QTEST_MAIN(tst_QColorSpace) From cab6587e5e798d902d6656e2fdb431b476dc0a17 Mon Sep 17 00:00:00 2001 From: Martin Koller Date: Sun, 14 Apr 2019 12:47:58 +0200 Subject: [PATCH 06/11] Avoid debug messages for not implemented "grab" methods Change-Id: Ie32b5d261854703fa17bb844cf8354709b031a4c Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/qandroidplatformwindow.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index f2e51bd3df..5edd274759 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -65,6 +65,9 @@ public: void setParent(const QPlatformWindow *window) override; WId winId() const override { return m_windowId; } + bool setMouseGrabEnabled(bool grab) override { return false; } + bool setKeyboardGrabEnabled(bool grab) override { return false; } + QAndroidPlatformScreen *platformScreen() const; void propagateSizeHints() override; From 093a1a6232083e5b9c18a9e85e5759ba3ce280fb Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Mon, 25 Mar 2019 12:47:21 +0100 Subject: [PATCH 07/11] tslib: use ts_setup() to find the device This automatically searches for some default devices. This not only reduces the amount of code, it also makes sure that Qt will by default find the same input devices that tslib (e.g. ts_calibrate) will find. Fixes: QTBUG-74680 Change-Id: Ied3fff7e8ed9d6637d2b8cf32119660133d251a3 Reviewed-by: Laszlo Agocs --- src/gui/configure.json | 2 +- src/platformsupport/input/tslib/qtslib.cpp | 26 +++++----------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/gui/configure.json b/src/gui/configure.json index 5bcfbc88bf..7a1796041e 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -476,7 +476,7 @@ "tslib": { "label": "tslib", "test": { - "main": "ts_open(\"foo\", 0);" + "main": "ts_setup(nullptr, 0);" }, "headers": "tslib.h", "sources": [ diff --git a/src/platformsupport/input/tslib/qtslib.cpp b/src/platformsupport/input/tslib/qtslib.cpp index f8fdc151ec..c4caea5c80 100644 --- a/src/platformsupport/input/tslib/qtslib.cpp +++ b/src/platformsupport/input/tslib/qtslib.cpp @@ -62,31 +62,15 @@ QTsLibMouseHandler::QTsLibMouseHandler(const QString &key, qCDebug(qLcTsLib) << "Initializing tslib plugin" << key << specification; setObjectName(QLatin1String("TSLib Mouse Handler")); - QByteArray device = qgetenv("TSLIB_TSDEVICE"); - - if (specification.startsWith(QLatin1String("/dev/"))) - device = specification.toLocal8Bit(); - - if (device.isEmpty()) - device = QByteArrayLiteral("/dev/input/event1"); - - m_dev = ts_open(device.constData(), 1); + m_dev = ts_setup(nullptr, 1); if (!m_dev) { - qErrnoWarning(errno, "ts_open() failed"); + qErrnoWarning(errno, "ts_setup() failed"); return; } - if (ts_config(m_dev)) - qErrnoWarning(errno, "ts_config() failed"); - - int fd = ts_fd(m_dev); - if (fd >= 0) { - qCDebug(qLcTsLib) << "tslib device is" << device; - m_notify = new QSocketNotifier(fd, QSocketNotifier::Read, this); - connect(m_notify, &QSocketNotifier::activated, this, &QTsLibMouseHandler::readMouseData); - } else { - qErrnoWarning(errno, "tslib: Cannot open input device %s", device.constData()); - } + qCDebug(qLcTsLib) << "tslib device is" << ts_get_eventpath(m_dev); + m_notify = new QSocketNotifier(ts_fd(m_dev), QSocketNotifier::Read, this); + connect(m_notify, &QSocketNotifier::activated, this, &QTsLibMouseHandler::readMouseData); } QTsLibMouseHandler::~QTsLibMouseHandler() From 327c8a805e508303c245020123ec3ecbfd2c898b Mon Sep 17 00:00:00 2001 From: Rob Samblanet Date: Tue, 23 Oct 2018 12:52:06 -0500 Subject: [PATCH 08/11] android: Properly indicate successful Qt install This patch ensures that installed files are written to physical disk before the 'cache.version' file is written. QtLoader.java uses the 'cache.version' file written during self-installation to indicate whether re-installation is necessary. The 'cache.version' file, however, was being written at the start of installation, so its existence merely indicated that the installation was attempted. In the case of power loss during installation, the existence of 'cache.version' would prevent retrying installation on the next launch, so the bad installation was irrecoverable. [ChangeLog][Android] Fixed an issue where an application installation would be irrecoverably broken if power loss or a crash occurred during its first initialization run. Fixes: QTBUG-71523 Change-Id: If771b223a0a709a994c766eea5a4ba14ae95201e Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../qt5/android/bindings/QtLoader.java | 100 +++++++++++++----- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java index 9d5578ed6d..d3b0600b2f 100644 --- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java +++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java @@ -159,6 +159,9 @@ public abstract class QtLoader { protected ComponentInfo m_contextInfo; private Class m_delegateClass; + private static ArrayList m_fileOutputStreams = new ArrayList(); + // List of open file streams associated with files copied during installation. + QtLoader(ContextWrapper context, Class clazz) { m_context = context; m_delegateClass = clazz; @@ -357,7 +360,7 @@ public abstract class QtLoader { AssetManager assetsManager = m_context.getAssets(); InputStream inputStream = null; - OutputStream outputStream = null; + FileOutputStream outputStream = null; try { inputStream = assetsManager.open(source); outputStream = new FileOutputStream(destinationFile); @@ -369,8 +372,12 @@ public abstract class QtLoader { inputStream.close(); if (outputStream != null) - outputStream.close(); + // Ensure that the buffered data is flushed to the OS for writing. + outputStream.flush(); } + // Mark the output stream as still needing to be written to physical disk. + // The output stream will be closed after this sync completes. + m_fileOutputStreams.add(outputStream); } private static void createBundledBinary(String source, String destination) @@ -388,7 +395,7 @@ public abstract class QtLoader { destinationFile.createNewFile(); InputStream inputStream = null; - OutputStream outputStream = null; + FileOutputStream outputStream = null; try { inputStream = new FileInputStream(source); outputStream = new FileOutputStream(destinationFile); @@ -400,8 +407,12 @@ public abstract class QtLoader { inputStream.close(); if (outputStream != null) - outputStream.close(); + // Ensure that the buffered data is flushed to the OS for writing. + outputStream.flush(); } + // Mark the output stream as still needing to be written to physical disk. + // The output stream will be closed after this sync completes. + m_fileOutputStreams.add(outputStream); } private boolean cleanCacheIfNecessary(String pluginsPrefix, long packageVersion) @@ -449,27 +460,6 @@ public abstract class QtLoader { if (!cleanCacheIfNecessary(pluginsPrefix, packageVersion)) return; - { - File versionFile = new File(pluginsPrefix + "cache.version"); - - File parentDirectory = versionFile.getParentFile(); - if (!parentDirectory.exists()) - parentDirectory.mkdirs(); - - versionFile.createNewFile(); - - DataOutputStream outputStream = null; - try { - outputStream = new DataOutputStream(new FileOutputStream(versionFile)); - outputStream.writeLong(packageVersion); - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (outputStream != null) - outputStream.close(); - } - } - { // why can't we load the plugins directly from libs ?!?! String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY; @@ -499,6 +489,66 @@ public abstract class QtLoader { } } + + // The Java compiler must be assured that variables belonging to this parent thread will not + // go out of scope during the runtime of the spawned thread (since in general spawned + // threads can outlive their parent threads). Copy variables and declare as 'final' before + // passing into the spawned thread. + final String pluginsPrefixFinal = pluginsPrefix; + final long packageVersionFinal = packageVersion; + + // Spawn a worker thread to write all installed files to physical disk and indicate + // successful installation by creating the 'cache.version' file. + new Thread(new Runnable() { + @Override + public void run() { + try { + finalizeInstallation(pluginsPrefixFinal, packageVersionFinal); + } catch (Exception e) { + Log.e(QtApplication.QtTAG, e.getMessage()); + e.printStackTrace(); + return; + } + } + }).start(); + } + + private void finalizeInstallation(String pluginsPrefix, long packageVersion) + throws IOException + { + { + // Write all installed files to physical disk and close each output stream + for (FileOutputStream fileOutputStream : m_fileOutputStreams) { + fileOutputStream.getFD().sync(); + fileOutputStream.close(); + } + + m_fileOutputStreams.clear(); + } + + { + // Create 'cache.version' file + + File versionFile = new File(pluginsPrefix + "cache.version"); + + File parentDirectory = versionFile.getParentFile(); + if (!parentDirectory.exists()) + parentDirectory.mkdirs(); + + versionFile.createNewFile(); + + DataOutputStream outputStream = null; + try { + outputStream = new DataOutputStream(new FileOutputStream(versionFile)); + outputStream.writeLong(packageVersion); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (outputStream != null) + outputStream.close(); + } + } + } private void deleteRecursively(File directory) From 7fe52779f4fe1a9aa01abd1f0d75107bdb6757e8 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 3 Dec 2018 16:20:29 +0100 Subject: [PATCH 09/11] uic test: Pre-populate the test data array Task-number: PYSIDE-797 Change-Id: I2beed73f20bbfc8b5b4f2352cc53d80a64b95d8e Reviewed-by: Cristian Maureira-Fredes --- tests/auto/tools/uic/tst_uic.cpp | 64 ++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/tests/auto/tools/uic/tst_uic.cpp b/tests/auto/tools/uic/tst_uic.cpp index f9553028fe..946296b844 100644 --- a/tests/auto/tools/uic/tst_uic.cpp +++ b/tests/auto/tools/uic/tst_uic.cpp @@ -36,17 +36,27 @@ #include #include #include +#include #include static const char keepEnvVar[] = "UIC_KEEP_GENERATED_FILES"; static const char diffToStderrEnvVar[] = "UIC_STDERR_DIFF"; +struct TestEntry +{ + QByteArray name; + QString baselineBaseName; + QString generatedFileName; +}; + class tst_uic : public QObject { Q_OBJECT public: + using TestEntries = QVector; + tst_uic(); private Q_SLOTS: @@ -66,9 +76,12 @@ private Q_SLOTS: void runCompare(); private: + void populateTestEntries(); + const QString m_command; QString m_baseline; QTemporaryDir m_generated; + TestEntries m_testEntries; QRegularExpression m_versionRegexp; }; @@ -105,9 +118,28 @@ void tst_uic::initTestCase() arg(QDir::currentPath()); if (!outLines.empty()) msg += outLines.front(); + populateTestEntries(); + QVERIFY(!m_testEntries.isEmpty()); qDebug("%s", qPrintable(msg)); } +void tst_uic::populateTestEntries() +{ + const QString generatedPrefix = m_generated.path() + QLatin1Char('/'); + QDir baseline(m_baseline); + const QString baseLinePrefix = baseline.path() + QLatin1Char('/'); + const QFileInfoList baselineFiles = + baseline.entryInfoList(QStringList(QString::fromLatin1("*.ui")), QDir::Files); + m_testEntries.reserve(baselineFiles.size()); + for (const QFileInfo &baselineFile : baselineFiles) { + const QString baseName = baselineFile.baseName(); + const QString baselineBaseName = baseLinePrefix + baseName; + const QString generatedFile = generatedPrefix + baselineFile.fileName() + + QLatin1String(".h"); + m_testEntries.append(TestEntry{baseName.toLocal8Bit(), baselineBaseName, generatedFile}); + } +} + static const char helpFormat[] = R"( Note: The environment variable '%s' can be set to keep the temporary files for error analysis. @@ -171,22 +203,12 @@ void tst_uic::run_data() const QTest::addColumn("generatedFile"); QTest::addColumn("options"); - QDir generated(m_generated.path()); - QDir baseline(m_baseline); - const QFileInfoList baselineFiles = baseline.entryInfoList(QStringList("*.ui"), QDir::Files); - foreach (const QFileInfo &baselineFile, baselineFiles) { - const QString generatedFile = generated.absolutePath() - + QLatin1Char('/') + baselineFile.fileName() - + QLatin1String(".h"); - + for (const TestEntry &te : m_testEntries) { QStringList options; - if (baselineFile.fileName() == QLatin1String("qttrid.ui")) + if (te.name == QByteArrayLiteral("qttrid")) options << QStringList(QLatin1String("-idbased")); - - QTest::newRow(qPrintable(baselineFile.baseName())) - << baselineFile.absoluteFilePath() - << generatedFile - << options; + QTest::newRow(te.name.constData()) << (te.baselineBaseName + QLatin1String(".ui")) + << te.generatedFileName << options; } } @@ -264,15 +286,9 @@ void tst_uic::compare_data() const QTest::addColumn("originalFile"); QTest::addColumn("generatedFile"); - QDir generated(m_generated.path()); - QDir baseline(m_baseline); - const QFileInfoList baselineFiles = baseline.entryInfoList(QStringList("*.h"), QDir::Files); - foreach (const QFileInfo &baselineFile, baselineFiles) { - const QString generatedFile = generated.absolutePath() - + QLatin1Char('/') + baselineFile.fileName(); - QTest::newRow(qPrintable(baselineFile.baseName())) - << baselineFile.absoluteFilePath() - << generatedFile; + for (const TestEntry &te : m_testEntries) { + QTest::newRow(te.name.constData()) << (te.baselineBaseName + QLatin1String(".ui.h")) + << te.generatedFileName; } } @@ -280,7 +296,7 @@ void tst_uic::runTranslation() { QProcess process; - QDir baseline(m_baseline); + const QDir baseline(m_baseline); QDir generated(m_generated.path()); generated.mkdir(QLatin1String("translation")); From 7a84a0a6d18c7a9e7fc7c963561c561b3027c1e7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 3 Dec 2018 16:57:04 +0100 Subject: [PATCH 10/11] uic test: Test Python Add a test that checks for the Presence of Qt for Python and runs Python compile tests on the baseline files. Task-number: PYSIDE-797 Change-Id: I7e15c3c75261a7d94fc6654a95d49ba323cbe7d6 Reviewed-by: Cristian Maureira-Fredes --- tests/auto/tools/uic/tst_uic.cpp | 102 +++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tests/auto/tools/uic/tst_uic.cpp b/tests/auto/tools/uic/tst_uic.cpp index 946296b844..5b2f1f008b 100644 --- a/tests/auto/tools/uic/tst_uic.cpp +++ b/tests/auto/tools/uic/tst_uic.cpp @@ -73,6 +73,9 @@ private Q_SLOTS: void compare(); void compare_data() const; + void python(); + void python_data() const; + void runCompare(); private: @@ -83,6 +86,7 @@ private: QTemporaryDir m_generated; TestEntries m_testEntries; QRegularExpression m_versionRegexp; + QString m_python; }; tst_uic::tst_uic() @@ -98,6 +102,32 @@ static QByteArray msgProcessStartFailed(const QString &command, const QString &w return result.toLocal8Bit(); } +// Locate Python and check whether PySide2 is installed +static QString locatePython(QTemporaryDir &generatedDir) +{ + QString python = QStandardPaths::findExecutable(QLatin1String("python")); + if (python.isEmpty()) { + qWarning("Cannot locate python, skipping tests"); + return QString(); + } + QFile importTestFile(generatedDir.filePath(QLatin1String("import_test.py"))); + if (!importTestFile.open(QIODevice::WriteOnly| QIODevice::Text)) + return QString(); + importTestFile.write("import PySide2.QtCore\n"); + importTestFile.close(); + QProcess process; + process.start(python, {importTestFile.fileName()}); + if (!process.waitForStarted() || !process.waitForFinished()) + return QString(); + if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) { + const QString stdErr = QString::fromLocal8Bit(process.readAllStandardError()).simplified(); + qWarning("PySide2 is not installed (%s)", qPrintable(stdErr)); + return QString(); + } + importTestFile.remove(); + return python; +} + void tst_uic::initTestCase() { QVERIFY2(m_generated.isValid(), qPrintable(m_generated.errorString())); @@ -121,6 +151,8 @@ void tst_uic::initTestCase() populateTestEntries(); QVERIFY(!m_testEntries.isEmpty()); qDebug("%s", qPrintable(msg)); + + m_python = locatePython(m_generated); } void tst_uic::populateTestEntries() @@ -343,5 +375,75 @@ void tst_uic::runCompare() QCOMPARE(generatedFileContents, originalFileContents); } +// Let uic generate Python code and verify that it is syntactically +// correct by compiling it into .pyc. This test is executed only +// when python with an installed Qt for Python is detected (see locatePython()). + +static inline QByteArray msgCompilePythonFailed(const QByteArray &error) +{ + // If there is a line with blanks and caret indicating an error in the line + // above, insert the cursor into the offending line and remove the caret. + QByteArrayList lines = error.trimmed().split('\n'); + for (int i = lines.size() - 1; i > 0; --i) { + const auto &line = lines.at(i); + const int caret = line.indexOf('^'); + if (caret == 0 || (caret > 0 && line.at(caret - 1) == ' ')) { + lines.removeAt(i); + lines[i - 1].insert(caret, '|'); + break; + } + } + return lines.join('\n'); +} + +void tst_uic::python_data() const +{ + QTest::addColumn("originalFile"); + QTest::addColumn("generatedFile"); + + const int size = m_python.isEmpty() + ? qMin(1, m_testEntries.size()) : m_testEntries.size(); + for (int i = 0; i < size; ++i) { + const TestEntry &te = m_testEntries.at(i); + // qprintsettingsoutput: variable named 'from' clashes with Python + if (!te.baselineBaseName.endsWith(QLatin1String("/qprintsettingsoutput"))) { + QString generatedFile = te.generatedFileName; + generatedFile.chop(1); // foo.h -> foo.py + generatedFile.append(QLatin1String("py")); + QTest::newRow(te.name.constData()) + << (te.baselineBaseName + QLatin1String(".ui")) + << generatedFile; + } + } +} + +void tst_uic::python() +{ + QFETCH(QString, originalFile); + QFETCH(QString, generatedFile); + if (m_python.isEmpty()) + QSKIP("Python was not found"); + + QStringList uicArguments{QLatin1String("-g"), QLatin1String("python"), + originalFile, QLatin1String("-o"), generatedFile}; + QProcess process; + process.setWorkingDirectory(m_generated.path()); + process.start(m_command, uicArguments); + QVERIFY2(process.waitForStarted(), msgProcessStartFailed(m_command, process.errorString())); + QVERIFY(process.waitForFinished()); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + QCOMPARE(process.exitCode(), 0); + QVERIFY(QFileInfo::exists(generatedFile)); + + // Test Python code generation by compiling the file + QStringList compileArguments{QLatin1String("-m"), QLatin1String("py_compile"), generatedFile}; + process.start(m_python, compileArguments); + QVERIFY2(process.waitForStarted(), msgProcessStartFailed(m_command, process.errorString())); + QVERIFY(process.waitForFinished()); + const bool compiled = process.exitStatus() == QProcess::NormalExit + && process.exitCode() == 0; + QVERIFY2(compiled, msgCompilePythonFailed(process.readAllStandardError()).constData()); +} + QTEST_MAIN(tst_uic) #include "tst_uic.moc" From f363540580eabd5aa27f4c172da796d637e38dfa Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 16 Apr 2019 09:54:46 +0200 Subject: [PATCH 11/11] uic: Do not generate Q_UNUSED for Python Task-number: PYSIDE-797 Change-Id: Id269af024c03c2c586d440659bb6c49c3d6eedc6 Reviewed-by: Cristian Maureira-Fredes --- src/tools/uic/cpp/cppwriteinitialization.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index afd0376643..b8ff91f354 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.cpp +++ b/src/tools/uic/cpp/cppwriteinitialization.cpp @@ -556,7 +556,7 @@ void WriteInitialization::acceptUI(DomUI *node) m_output << m_option.indent << language::endFunctionDefinition("setupUi"); - if (!m_mainFormUsedInRetranslateUi) { + if (!m_mainFormUsedInRetranslateUi && language::language() == Language::Cpp) { m_refreshInitialization += m_indent; m_refreshInitialization += QLatin1String("Q_UNUSED("); m_refreshInitialization += varName ;