diff options
Diffstat (limited to 'tests/baseline/shared')
-rw-r--r-- | tests/baseline/shared/baselineprotocol.cpp | 78 | ||||
-rw-r--r-- | tests/baseline/shared/baselineprotocol.h | 32 | ||||
-rw-r--r-- | tests/baseline/shared/lookup3.cpp | 35 | ||||
-rw-r--r-- | tests/baseline/shared/paintcommands.cpp | 243 | ||||
-rw-r--r-- | tests/baseline/shared/paintcommands.h | 45 | ||||
-rw-r--r-- | tests/baseline/shared/qbaselinetest.cpp | 122 | ||||
-rw-r--r-- | tests/baseline/shared/qbaselinetest.h | 43 | ||||
-rw-r--r-- | tests/baseline/shared/qwidgetbaselinetest.cpp | 126 | ||||
-rw-r--r-- | tests/baseline/shared/qwidgetbaselinetest.h | 31 |
9 files changed, 381 insertions, 374 deletions
diff --git a/tests/baseline/shared/baselineprotocol.cpp b/tests/baseline/shared/baselineprotocol.cpp index ab6ced204a..311b003c07 100644 --- a/tests/baseline/shared/baselineprotocol.cpp +++ b/tests/baseline/shared/baselineprotocol.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "baselineprotocol.h" #include <QLibraryInfo> #include <QImage> @@ -70,24 +45,26 @@ PlatformInfo PlatformInfo::localHostInfo() #endif pi.insert(PI_OSVersion, QSysInfo::kernelVersion()); + QString gc = qEnvironmentVariable("BASELINE_GIT_COMMIT"); #if QT_CONFIG(process) - QProcess git; - QString cmd; - QStringList args; -#if defined(Q_OS_WIN) - cmd = QLS("cmd.exe"); - args << QLS("/c") << QLS("git"); -#else - cmd = QLS("git"); -#endif - args << QLS("log") << QLS("--max-count=1") << QLS("--pretty=%H [%an] [%ad] %s"); - git.start(cmd, args); - git.waitForFinished(3000); - if (!git.exitCode()) - pi.insert(PI_GitCommit, QString::fromLocal8Bit(git.readAllStandardOutput().constData()).simplified()); - else - pi.insert(PI_GitCommit, QLS("Unknown")); + if (gc.isEmpty()) { + QProcess git; + QString cmd; + QStringList args; + #if defined(Q_OS_WIN) + cmd = QLS("cmd.exe"); + args << QLS("/c") << QLS("git"); + #else + cmd = QLS("git"); + #endif + args << QLS("log") << QLS("--max-count=1") << QLS("--pretty=%H [%an] [%ad] %s"); + git.start(cmd, args); + git.waitForFinished(3000); + if (!git.exitCode()) + gc = QString::fromLocal8Bit(git.readAllStandardOutput().constData()).simplified(); + } #endif // QT_CONFIG(process) + pi.insert(PI_GitCommit, gc.isEmpty() ? QLS("Unknown") : gc); if (qEnvironmentVariableIsSet("JENKINS_HOME")) pi.setAdHocRun(false); @@ -284,18 +261,21 @@ bool BaselineProtocol::disconnect() } -bool BaselineProtocol::connect(const QString &testCase, bool *dryrun, const PlatformInfo& clientInfo) +bool BaselineProtocol::connect(const QString &testCase, bool *dryrun, const PlatformInfo &clientInfo, const QString &server) { errMsg.clear(); - QByteArray serverName(qgetenv("QT_LANCELOT_SERVER")); - if (serverName.isNull()) - serverName = "lancelot.test.qt-project.org"; + QString serverName = server; + if (serverName.isEmpty()) { + serverName = qEnvironmentVariable("QT_LANCELOT_SERVER"); + if (serverName.isEmpty()) + serverName = QStringLiteral("lancelot.test.qt-project.org"); + } socket.connectToHost(serverName, ServerPort); if (!socket.waitForConnected(Timeout)) { - QThread::msleep(3000); // Wait a bit and try again, the server might just be restarting + QThread::sleep(std::chrono::seconds{3}); // Wait a bit and try again, the server might just be restarting if (!socket.waitForConnected(Timeout)) { - errMsg += QLS("TCP connectToHost failed. Host:") + QLS(serverName) + QLS(" port:") + QString::number(ServerPort); + errMsg += QLS("TCP connectToHost failed. Host:") + serverName + QLS(" port:") + QString::number(ServerPort); return false; } } diff --git a/tests/baseline/shared/baselineprotocol.h b/tests/baseline/shared/baselineprotocol.h index a5cc6ba661..93d416fcd8 100644 --- a/tests/baseline/shared/baselineprotocol.h +++ b/tests/baseline/shared/baselineprotocol.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef BASELINEPROTOCOL_H #define BASELINEPROTOCOL_H @@ -140,7 +115,8 @@ public: // For client: // For advanced client: - bool connect(const QString &testCase, bool *dryrun = nullptr, const PlatformInfo& clientInfo = PlatformInfo()); + bool connect(const QString &testCase, bool *dryrun = nullptr, + const PlatformInfo &clientInfo = PlatformInfo(), const QString &server = QString()); bool disconnect(); bool requestBaselineChecksums(const QString &testFunction, ImageItemList *itemList); bool submitMatch(const ImageItem &item, QByteArray *serverMsg); diff --git a/tests/baseline/shared/lookup3.cpp b/tests/baseline/shared/lookup3.cpp index 1fbe6b499e..7964a184ae 100644 --- a/tests/baseline/shared/lookup3.cpp +++ b/tests/baseline/shared/lookup3.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only /* @@ -328,7 +303,7 @@ quint32 hashlittle( const void *key, size_t length, quint32 initval) * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash - * noticably faster for short strings (like English words). + * noticeably faster for short strings (like English words). */ #ifndef VALGRIND @@ -536,7 +511,7 @@ void hashlittle2( * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash - * noticably faster for short strings (like English words). + * noticeably faster for short strings (like English words). */ #ifndef VALGRIND @@ -736,7 +711,7 @@ quint32 hashbig( const void *key, size_t length, quint32 initval) * rest of the string. Every machine with memory protection I've seen * does it on word boundaries, so is OK with this. But VALGRIND will * still catch it and complain. The masking trick does make the hash - * noticably faster for short strings (like English words). + * noticeably faster for short strings (like English words). */ #ifndef VALGRIND diff --git a/tests/baseline/shared/paintcommands.cpp b/tests/baseline/shared/paintcommands.cpp index d2e48688f9..2cb3cd3bba 100644 --- a/tests/baseline/shared/paintcommands.cpp +++ b/tests/baseline/shared/paintcommands.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "paintcommands.h" #include <qdir.h> @@ -198,6 +173,13 @@ const char *PaintCommands::imageFormatTable[] = { "RGBx32FPx4", "RGBA32FPx4", "RGBA32FPx4_Premultiplied", + "CMYK32", +}; + +const char *PaintCommands::renderHintTable[] = { + "Antialiasing", + "SmoothPixmapTransform", + "NonCosmeticBrushPatterns" }; int PaintCommands::translateEnum(const char *table[], const QString &pattern, int limit) @@ -338,7 +320,7 @@ void PaintCommands::staticInit() "pen_setCosmetic true"); DECL_PAINTCOMMAND("setRenderHint", command_setRenderHint, "^setRenderHint\\s+([\\w_0-9]*)\\s*(\\w*)$", - "setRenderHint <Antialiasing|SmoothPixmapTransform> <true|false>", + "setRenderHint <hint> <true|false>", "setRenderHint Antialiasing true"); DECL_PAINTCOMMAND("clearRenderHint", command_clearRenderHint, "^clearRenderHint$", @@ -468,10 +450,12 @@ void PaintCommands::staticInit() "^drawGlyphRun\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$", "drawGlyphRun <x> <y> <text> - Will create glyph run using QTextLayout and draw this", "drawGlyphRun 10 10 \"my text\""); +#ifndef QT_NO_TEXTHTMLPARSER DECL_PAINTCOMMAND("drawTextDocument", command_drawTextDocument, "^drawTextDocument\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$", "drawTextDocument <x> <y> <html>", "drawTextDocument 10 10 \"html\""); +#endif DECL_PAINTCOMMAND("drawTiledPixmap", command_drawTiledPixmap, "^drawTiledPixmap\\s+([\\w.:\\/]*)" "\\s+(-?\\w*)\\s+(-?\\w*)\\s*(-?\\w*)\\s*(-?\\w*)" @@ -488,6 +472,20 @@ void PaintCommands::staticInit() "^fillRectF\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s*(\\w*)?$", "fillRectF <x> <y> <w> <h> [color]\n - Uses current brush if no color given", "fillRectF 10.5 10.5 20.2 20.2 blue"); + DECL_PAINTCOMMAND("drawPixmapFragments", command_drawPixmapFragments, + "^drawPixmapFragments\\s+([\\w.:\\/]*)" + "\\s+(-?\\w*)" + "\\s+(-?[.\\w]*)\\s*(-?[.\\w]*)" + "\\s+(-?[.\\w]*)\\s*(-?[.\\w]*)\\s*(-?[.\\w]*)\\s*(-?[.\\w]*)" + "\\s+(-?[.\\w]*)\\s*(-?[.\\w]*)\\s*(-?[.\\w]*)\\s*(-?[.\\w]*)" + "\\s*(-?[.\\w]*)?\\s*(-?[.\\w]*)?" + "\\s*(-?[.\\w]*)?\\s*(-?[.\\w]*)?\\s*(-?[.\\w]*)?\\s*(-?[.\\w]*)?" + "\\s*(-?[.\\w]*)?\\s*(-?[.\\w]*)\\s*(-?[.\\w]*)?\\s*(-?[.\\w]*)?$", + "drawPixmapFragments <image filename> <count>" + " <centerx0> <centery0> <x0> <y0> <w0> <h0> <sx0> <sy0> <r0> <o0>" + " <centerx1> <centery1> <x1> <y1> <w1> ..." + "\n - where count is 1 or 2, and followed by centerPos, sourceRect, scaleX, scaleY, rotation, opacity <count> times", + "drawPixmapFragments :/images/sign.png 1 50 50 10 10 60 60 10 10 30 1"); DECL_PAINTCOMMANDSECTION("painterPaths"); DECL_PAINTCOMMAND("path_moveTo", command_path_moveTo, @@ -564,8 +562,12 @@ void PaintCommands::staticInit() "setClipPath mypath ReplaceClip"); DECL_PAINTCOMMAND("setClipRect", command_setClipRect, "^setClipRect\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s+(-?\\w*)\\s*(\\w*)$", - "setClipRect <x1> <y1> <x2> <y2> <clip operation enum>", - "setClipRect 0.0 0.0 10.0 10.0 ReplaceClip"); + "setClipRect <x> <y> <w> <h> <clip operation enum>", + "setClipRect 0 0 10 10 ReplaceClip"); + DECL_PAINTCOMMAND("setClipRectF", command_setClipRectF, + "^setClipRectF\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s+(-?[.\\w]*)\\s*(\\w.*)$", + "setClipRectF <x> <y> <w> <h> <clip operation enum>", + "setClipRectF 0.1 0.2 10.3 10.4 ReplaceClip"); DECL_PAINTCOMMAND("setClipping", command_setClipping, "^setClipping\\s+(\\w*)$", "setClipping <true|false>", @@ -686,6 +688,7 @@ void PaintCommands::staticInit() ADD_ENUMLIST("image formats", imageFormatTable); ADD_ENUMLIST("coordinate modes", coordinateMethodTable); ADD_ENUMLIST("size modes", sizeModeTable); + ADD_ENUMLIST("render hints", renderHintTable); } #undef DECL_PAINTCOMMAND @@ -745,8 +748,8 @@ void PaintCommands::runCommand(const QString &scriptLine) return; } QString firstWord = scriptLine.section(separators, 0, 0); - QList<int> indices = s_commandHash.values(firstWord); - foreach(int idx, indices) { + const QList<int> indices = s_commandHash.values(firstWord); + for (int idx : indices) { PaintCommandInfos command = s_commandInfoTable.at(idx); Q_ASSERT(command.regExp.isValid()); QRegularExpressionMatch match = command.regExp.match(scriptLine); @@ -921,7 +924,7 @@ void PaintCommands::command_import(QRegularExpressionMatch re) if (m_verboseMode) { printf(" -(lance) Command buffer now looks like:\n"); - for (int i = 0; i < m_commands.count(); ++i) + for (int i = 0; i < m_commands.size(); ++i) printf(" ---> {%s}\n", qPrintable(m_commands.at(i))); } delete file; @@ -939,7 +942,7 @@ void PaintCommands::command_begin_block(QRegularExpressionMatch re) m_commands[m_currentCommandIndex] = QLatin1String("# begin block (") + blockName + QLatin1Char(')'); QStringList newBlock; int i = m_currentCommandIndex + 1; - for (; i < m_commands.count(); ++i) { + for (; i < m_commands.size(); ++i) { const QString &nextCmd = m_commands.at(i); if (nextCmd.startsWith("end_block")) { m_commands[i] = QLatin1String("# end block (") + blockName + QLatin1Char(')'); @@ -949,10 +952,10 @@ void PaintCommands::command_begin_block(QRegularExpressionMatch re) } if (m_verboseMode) - for (int j = 0; j < newBlock.count(); ++j) + for (int j = 0; j < newBlock.size(); ++j) printf(" %d: %s\n", j, qPrintable(newBlock.at(j))); - if (i >= m_commands.count()) + if (i >= m_commands.size()) printf(" - Warning! Block doesn't have an 'end_block' marker!\n"); m_blockMap.insert(blockName, newBlock); @@ -1403,6 +1406,7 @@ void PaintCommands::command_drawGlyphRun(QRegularExpressionMatch re) m_painter->drawGlyphRun(QPointF(x, y), glyphRun); } +#ifndef QT_NO_TEXTHTMLPARSER void PaintCommands::command_drawTextDocument(QRegularExpressionMatch re) { if (!m_shouldDrawText) @@ -1424,6 +1428,7 @@ void PaintCommands::command_drawTextDocument(QRegularExpressionMatch re) doc.drawContents(m_painter); m_painter->restore(); } +#endif /***************************************************************************************************/ void PaintCommands::command_fillRect(QRegularExpressionMatch re) @@ -1466,6 +1471,93 @@ void PaintCommands::command_fillRectF(QRegularExpressionMatch re) } } +void PaintCommands::command_drawPixmapFragments(QRegularExpressionMatch re) +{ + QPixmap pm; + pm = m_pixmapMap[re.captured(1)]; // try cache first + if (pm.isNull()) + pm = image_load<QPixmap>(re.captured(1)); + if (pm.isNull()) { + QFileInfo fi(m_filepath); + QDir dir = fi.absoluteDir(); + dir.cdUp(); + dir.cd("images"); + QString fileName = dir.absolutePath() + QLatin1Char('/') + re.captured(1); + pm = QPixmap(fileName); + if (pm.isNull() && !fileName.endsWith(".png")) { + fileName.append(".png"); + pm = QPixmap(fileName); + } + } + if (pm.isNull()) { + fprintf(stderr, "ERROR(drawPixmapFragments): failed to load pixmap: '%s'\n", + qPrintable(re.captured(1))); + return; + } + + int count = convertToInt(re.captured(2)); + + struct Fragment { + double posx; + double posy; + double srcx; + double srcy; + double srcw; + double srch; + double sx; + double sy; + double rotation; + double opacity; + }; + + QList<Fragment> fragments; + for (int i = 0; i < count; ++i) { + int captureIndexStart = 3 + i * 10; + if (re.hasCaptured(captureIndexStart)) { + Fragment f; + f.posx = convertToDouble(re.captured(captureIndexStart)); + f.posy = convertToDouble(re.captured(captureIndexStart + 1)); + f.srcx = convertToDouble(re.captured(captureIndexStart + 2)); + f.srcy = convertToDouble(re.captured(captureIndexStart + 3)); + f.srcw = convertToDouble(re.captured(captureIndexStart + 4)); + f.srch = convertToDouble(re.captured(captureIndexStart + 5)); + f.sx = convertToDouble(re.captured(captureIndexStart + 6)); + f.sy = convertToDouble(re.captured(captureIndexStart + 7)); + f.rotation = convertToDouble(re.captured(captureIndexStart + 8)); + f.opacity = convertToDouble(re.captured(captureIndexStart + 9)); + fragments.append(f); + } else { + break; + } + } + + if (m_verboseMode) { + printf(" -(lance) drawPixmapFragments('%s' count=%d ", + qPrintable(re.captured(1)), int(fragments.count())); + for (int i = 0; i < fragments.count(); ++i) { + printf("pos=(%.2f, %.2f) srcrect=(%.2f %.2f %.2f %.2f) scale=(%.2f %.2f) rotation=%.2f opacity=%.2f ", + fragments[i].posx, fragments[i].posy, + fragments[i].srcx, fragments[i].srcy, fragments[i].srcw, fragments[i].srch, + fragments[i].sx, fragments[i].sy, + fragments[i].rotation, + fragments[i].opacity); + } + printf("\n"); + } + + QList<QPainter::PixmapFragment> pixmapFragments; + for (int i = 0; i < fragments.count(); ++i) { + pixmapFragments.append( + QPainter::PixmapFragment::create(QPointF(fragments[i].posx, fragments[i].posy), + QRectF(fragments[i].srcx, fragments[i].srcy, fragments[i].srcw, fragments[i].srch), + fragments[i].sx, fragments[i].sy, + fragments[i].rotation, + fragments[i].opacity)); + } + + m_painter->drawPixmapFragments(pixmapFragments.constData(), pixmapFragments.count(), pm); +} + /***************************************************************************************************/ void PaintCommands::command_noop(QRegularExpressionMatch) { @@ -2082,6 +2174,25 @@ void PaintCommands::command_setClipRect(QRegularExpressionMatch re) } /***************************************************************************************************/ +void PaintCommands::command_setClipRectF(QRegularExpressionMatch re) +{ + QStringList caps = re.capturedTexts(); + double x = convertToDouble(caps.at(1)); + double y = convertToDouble(caps.at(2)); + double w = convertToDouble(caps.at(3)); + double h = convertToDouble(caps.at(4)); + + int combine = translateEnum(clipOperationTable, caps.at(5), Qt::IntersectClip + 1); + if (combine == -1) + combine = Qt::ReplaceClip; + + if (m_verboseMode) + printf(" -(lance) setClipRectF(%f, %f, %f, %f), %s\n", x, y, w, h, clipOperationTable[combine]); + + m_painter->setClipRect(QRectF(x, y, w, h), Qt::ClipOperation(combine)); +} + +/***************************************************************************************************/ void PaintCommands::command_setClipPath(QRegularExpressionMatch re) { int combine = translateEnum(clipOperationTable, re.captured(2), Qt::IntersectClip + 1); @@ -2121,19 +2232,27 @@ void PaintCommands::command_setFont(QRegularExpressionMatch re) { QStringList caps = re.capturedTexts(); QString family = caps.at(1); - int size = convertToInt(caps.at(2)); - - int weight = translateEnum(fontWeightTable, re.captured(3).toLower(), 5); - if (weight != -1) { - switch (weight) { - case 0: weight = QFont::Light; break; - case 1: weight = QFont::Normal; break; - case 2: weight = QFont::DemiBold; break; - case 3: weight = QFont::Bold; break; - case 4: weight = QFont::Black; break; - } - } else { - weight = convertToInt(re.captured(3)); + + int size = -1; // Default + QString sizeArg = caps.at(2); + if (!sizeArg.isEmpty()) + size = convertToInt(caps.at(2)); + + int weight = -1; // Default + QString weightArg = caps.at(3); + if (!weightArg.isEmpty()) { + weight = translateEnum(fontWeightTable, weightArg.toLower(), 5); + if (weight != -1) { + switch (weight) { + case 0: weight = QFont::Light; break; + case 1: weight = QFont::Normal; break; + case 2: weight = QFont::DemiBold; break; + case 3: weight = QFont::Bold; break; + case 4: weight = QFont::Black; break; + } + } else { + weight = convertToInt(weightArg); + } } bool italic = caps.at(4).toLower() == "true" || caps.at(4).toLower() == "italic"; @@ -2234,18 +2353,27 @@ void PaintCommands::command_setPen2(QRegularExpressionMatch re) void PaintCommands::command_setRenderHint(QRegularExpressionMatch re) { QString hintString = re.captured(1).toLower(); - bool on = re.captured(2).isEmpty() || re.captured(2).toLower() == "true"; - if (hintString.contains("antialiasing")) { - if (m_verboseMode) - printf(" -(lance) setRenderHint Antialiasing\n"); + QString setting = re.captured(2).toLower(); - m_painter->setRenderHint(QPainter::Antialiasing, on); + bool on = setting.isEmpty() || setting == "true" || setting == "on"; + QPainter::RenderHint hint; + int hintIdx = -1; + if (hintString.contains("antialiasing")) { + hintIdx = 0; + hint = QPainter::Antialiasing; } else if (hintString.contains("smoothpixmaptransform")) { + hintIdx = 1; + hint = QPainter::SmoothPixmapTransform; + } else if (hintString.contains("noncosmeticbrushpatterns")) { + hintIdx = 2; + hint = QPainter::NonCosmeticBrushPatterns; + } + if (hintIdx >= 0) { if (m_verboseMode) - printf(" -(lance) setRenderHint SmoothPixmapTransform\n"); - m_painter->setRenderHint(QPainter::SmoothPixmapTransform, on); + printf(" -(lance) setRenderHint %s %s\n", renderHintTable[hintIdx], on ? "true" : "false"); + m_painter->setRenderHint(hint, on); } else { - fprintf(stderr, "ERROR(setRenderHint): unknown hint '%s'\n", qPrintable(hintString)); + fprintf(stderr, "ERROR(setRenderHint): unknown hint '%s'\n", qPrintable(re.captured(1))); } } @@ -2254,6 +2382,7 @@ void PaintCommands::command_clearRenderHint(QRegularExpressionMatch /*re*/) { m_painter->setRenderHint(QPainter::Antialiasing, false); m_painter->setRenderHint(QPainter::SmoothPixmapTransform, false); + m_painter->setRenderHint(QPainter::NonCosmeticBrushPatterns, false); if (m_verboseMode) printf(" -(lance) clearRenderHint\n"); } diff --git a/tests/baseline/shared/paintcommands.h b/tests/baseline/shared/paintcommands.h index 15c6d3fa58..de412e246e 100644 --- a/tests/baseline/shared/paintcommands.h +++ b/tests/baseline/shared/paintcommands.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef PAINTCOMMANDS_H #define PAINTCOMMANDS_H @@ -68,15 +43,13 @@ class PaintCommands { public: // construction / initialization - PaintCommands(const QStringList &cmds, int w, int h, QImage::Format format) + PaintCommands(const QStringList &cmds, int /*w*/, int /*h*/, QImage::Format format) : m_painter(0) , m_surface_painter(0) , m_format(format) , m_commands(cmds) , m_gradientSpread(QGradient::PadSpread) , m_gradientCoordinate(QGradient::LogicalMode) - , m_width(w) - , m_height(h) , m_verboseMode(false) , m_type(WidgetType) , m_checkers_background(true) @@ -87,7 +60,9 @@ public: , m_surface_glbuffer(0) , m_surface_glpaintdevice(0) #endif - { staticInit(); } + { + staticInit(); + } public: void setCheckersBackground(bool b) { staticInit(); m_checkers_background = b; } @@ -162,7 +137,7 @@ private: void command_brushShear(QRegularExpressionMatch re); void command_setClipPath(QRegularExpressionMatch re); void command_setClipRect(QRegularExpressionMatch re); - void command_setClipRectangle(QRegularExpressionMatch re); + void command_setClipRectF(QRegularExpressionMatch re); void command_setClipRegion(QRegularExpressionMatch re); void command_setClipping(QRegularExpressionMatch re); void command_setCompositionMode(QRegularExpressionMatch re); @@ -204,10 +179,13 @@ private: void command_drawText(QRegularExpressionMatch re); void command_drawStaticText(QRegularExpressionMatch re); void command_drawGlyphRun(QRegularExpressionMatch re); +#ifndef QT_NO_TEXTHTMLPARSER void command_drawTextDocument(QRegularExpressionMatch re); +#endif void command_drawTiledPixmap(QRegularExpressionMatch re); void command_fillRect(QRegularExpressionMatch re); void command_fillRectF(QRegularExpressionMatch re); + void command_drawPixmapFragments(QRegularExpressionMatch re); // paths void command_path_addEllipse(QRegularExpressionMatch re); @@ -276,8 +254,6 @@ private: QGradient::Spread m_gradientSpread; QGradient::CoordinateMode m_gradientCoordinate; bool m_abort; - int m_width; - int m_height; bool m_verboseMode; DeviceType m_type; @@ -305,6 +281,7 @@ private: static const char *compositionModeTable[]; static const char *imageFormatTable[]; static const char *sizeModeTable[]; + static const char *renderHintTable[]; static int translateEnum(const char *table[], const QString &pattern, int limit); // utility diff --git a/tests/baseline/shared/qbaselinetest.cpp b/tests/baseline/shared/qbaselinetest.cpp index 493be4bd7a..964266f1b4 100644 --- a/tests/baseline/shared/qbaselinetest.cpp +++ b/tests/baseline/shared/qbaselinetest.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "qbaselinetest.h" #include "baselineprotocol.h" @@ -36,6 +11,7 @@ namespace QBaselineTest { static char *fargv[MAXCMDLINEARGS]; +static QString server; static bool simfail = false; static PlatformInfo customInfo; static bool customAutoModeSet = false; @@ -51,9 +27,6 @@ static QByteArray curFunction; static ImageItemList itemList; static bool gotBaselines; -static QString definedTestProject; -static QString definedTestCase; - void handleCmdLineArgs(int *argcp, char ***argvp) { @@ -61,6 +34,7 @@ void handleCmdLineArgs(int *argcp, char ***argvp) return; bool showHelp = false; + bool abortOnHelp = true; int fargc = 0; int numArgs = *argcp; @@ -69,7 +43,16 @@ void handleCmdLineArgs(int *argcp, char ***argvp) QByteArray arg = (*argvp)[i]; QByteArray nextArg = (i+1 < numArgs) ? (*argvp)[i+1] : nullptr; - if (arg == "-simfail") { + if (arg == "-server") { + i++; + if (!nextArg.isEmpty()) { + server = QString::fromLocal8Bit(nextArg); + } else { + qWarning() << "-server requires parameter"; + showHelp = true; + break; + } + } else if (arg == "-simfail") { simfail = true; } else if (arg == "-fuzzlevel") { i++; @@ -105,10 +88,13 @@ void handleCmdLineArgs(int *argcp, char ***argvp) } customInfo.addOverride(key, value); } else { - if ( (arg == "-help") || (arg == "--help") ) + if ( (arg == "-help") || (arg == "--help") ) { showHelp = true; + abortOnHelp = false; + } if (fargc >= MAXCMDLINEARGS) { qWarning() << "Too many command line arguments!"; + showHelp = true; break; } fargv[fargc++] = (*argvp)[i]; @@ -121,7 +107,9 @@ void handleCmdLineArgs(int *argcp, char ***argvp) // TBD: arrange for this to be printed *after* QTest's help QTextStream out(stdout); out << "\n Baseline testing (lancelot) options:\n"; - out << " -simfail : Force an image comparison mismatch. For testing purposes.\n"; + out << " -server <host> : Set the network baseline server to connect to.\n"; + out << " The default is taken from the environment variable QT_LANCELOT_SERVER.\n"; + out << " -simfail : Force an image comparison mismatch. For development purposes.\n"; out << " -fuzzlevel <int> : Specify the percentage of fuzziness in comparison. Overrides server default. 0 means exact match.\n"; out << " -auto : Inform server that this run is done by a daemon, CI system or similar.\n"; out << " -adhoc (default) : The inverse of -auto; this run is done by human, e.g. for testing.\n"; @@ -132,6 +120,9 @@ void handleCmdLineArgs(int *argcp, char ***argvp) out << " for example: -compareto QtVersion=4.8.0\n"; out << " Multiple -compareto client specifications may be given.\n"; out << "\n"; + out.flush(); + if (abortOnHelp) + std::exit(1); } } @@ -167,7 +158,7 @@ void fetchCustomClientProperties() key = line.left(colonPos).simplified().replace(' ', '_'); val = line.mid(colonPos+1).trimmed(); } - if (!key.isEmpty() && key.length() < 64 && val.length() < 256) // ###TBD: maximum 256 chars in value? + if (!key.isEmpty() && key.size() < 64 && val.size() < 256) // ###TBD: maximum 256 chars in value? addClientProperty(key, val); else qDebug() << "Unparseable script output ignored:" << line; @@ -200,10 +191,7 @@ bool connect(QByteArray *msg, bool *error) if (!customAutoModeSet) clientInfo.setAdHocRun(defaultInfo.isAdHocRun()); - if (!definedTestProject.isEmpty()) - clientInfo.insert(PI_Project, definedTestProject); - - QString testCase = definedTestCase; + QString testCase = clientInfo.value(PI_TestCase); if (testCase.isEmpty() && QTest::testObject() && QTest::testObject()->metaObject()) { //qDebug() << "Trying to Read TestCaseName from Testlib!"; testCase = QTest::testObject()->metaObject()->className(); @@ -213,7 +201,7 @@ bool connect(QByteArray *msg, bool *error) return false; } - if (!proto.connect(testCase, &dryRunMode, clientInfo)) { + if (!proto.connect(testCase, &dryRunMode, clientInfo, server)) { *msg += "Failed to connect to baseline server: " + proto.errorMessage().toLatin1(); *error = true; return false; @@ -233,16 +221,10 @@ bool disconnectFromBaselineServer() return false; } -bool connectToBaselineServer(QByteArray *msg, const QString &testProject, const QString &testCase) +bool connectToBaselineServer(QByteArray *msg) { bool dummy; QByteArray dummyMsg; - - if (!testProject.isEmpty()) - definedTestProject = testProject; - if (!testCase.isEmpty()) - definedTestCase = testCase; - return connect(msg ? msg : &dummyMsg, &dummy); } @@ -259,7 +241,7 @@ void setSimFail(bool fail) void setProject(const QString &projectName) { - definedTestProject = projectName; + addClientProperty(PI_Project, projectName); } void setProjectImageKeys(const QStringList &keys) @@ -286,6 +268,7 @@ void modifyImage(QImage *img) bool compareItem(const ImageItem &baseline, const QImage &img, QByteArray *msg, bool *error) { + *error = false; ImageItem item = baseline; if (simfail) { // Simulate test failure by forcing image mismatch; for testing purposes @@ -296,6 +279,7 @@ bool compareItem(const ImageItem &baseline, const QImage &img, QByteArray *msg, } else { item.image = img; } + bool isNewItem = false; item.imageChecksums.clear(); item.imageChecksums.prepend(ImageItem::computeChecksum(item.image)); QByteArray srvMsg; @@ -307,9 +291,11 @@ bool compareItem(const ImageItem &baseline, const QImage &img, QByteArray *msg, return true; break; case ImageItem::BaselineNotFound: - if (!customInfo.overrides().isEmpty() || baselinePolicy == UploadNone) { - qWarning() << "Cannot compare to baseline: No such baseline found on server."; + if (!customInfo.overrides().isEmpty()) return true; + if (baselinePolicy == UploadNone) { + isNewItem = true; + break; } if (proto.submitNewBaseline(item, &srvMsg)) qDebug() << msg->constData() << "Baseline not found on server. New baseline uploaded."; @@ -322,7 +308,6 @@ bool compareItem(const ImageItem &baseline, const QImage &img, QByteArray *msg, return true; break; } - *error = false; // The actual comparison of the given image with the baseline: if (baseline.imageChecksums.contains(item.imageChecksums.at(0))) { if (!proto.submitMatch(item, &srvMsg)) @@ -343,7 +328,11 @@ bool compareItem(const ImageItem &baseline, const QImage &img, QByteArray *msg, qInfo() << "Baseline server reports:" << srvMsg; return true; // The server decides: a fuzzy match means no mismatch } - *msg += "Mismatch. See report:\n " + srvMsg; + if (isNewItem) + *msg += "No baseline on server, so cannot compare."; + else + *msg += "Mismatch."; + *msg += " See report:\n " + srvMsg; if (dryRunMode) { qDebug() << "Dryrun, so ignoring" << *msg; return true; @@ -409,22 +398,21 @@ QTestData &newRow(const char *dataTag, quint16 checksum) return QTest::newRow(dataTag); } - -bool testImage(const QImage& img, QByteArray *msg, bool *error) +const ImageItem *findCurrentItem(QByteArray *msg, bool *error) { if (!connected && !connect(msg, error)) - return true; + return nullptr; if (QTest::currentTestFunction() != curFunction || itemList.isEmpty()) { - qWarning() << "Usage error: QBASELINE_TEST used without corresponding QBaselineTest::newRow()"; - return true; + qWarning() << "Usage error: QBASELINE_ macro used without corresponding QBaselineTest::newRow()"; + return nullptr; } if (!gotBaselines) { if (!proto.requestBaselineChecksums(QString::fromLatin1(QTest::currentTestFunction()), &itemList) || itemList.isEmpty()) { *msg = "Communication with baseline server failed: " + proto.errorMessage().toLatin1(); *error = true; - return true; + return nullptr; } gotBaselines = true; } @@ -434,10 +422,24 @@ bool testImage(const QImage& img, QByteArray *msg, bool *error) while (it != itemList.constEnd() && it->itemName != curTag) ++it; if (it == itemList.constEnd()) { - qWarning() << "Usage error: QBASELINE_TEST used without corresponding QBaselineTest::newRow() for row" << curTag; - return true; + qWarning() << "Usage error: QBASELINE_ macro used without corresponding QBaselineTest::newRow() for row" << curTag; + return nullptr; } - return compareItem(*it, img, msg, error); + return &(*it); +} + +bool testImage(const QImage &img, QByteArray *msg, bool *error) +{ + const ImageItem *item = findCurrentItem(msg, error); + return item ? compareItem(*item, img, msg, error) : true; +} + +bool isCurrentItemBlacklisted() +{ + QByteArray msg; + bool error = false; + const ImageItem *item = findCurrentItem(&msg, &error); + return item ? (item->status == ImageItem::IgnoreItem) : false; } } diff --git a/tests/baseline/shared/qbaselinetest.h b/tests/baseline/shared/qbaselinetest.h index 68f2efe461..73bb5dfda9 100644 --- a/tests/baseline/shared/qbaselinetest.h +++ b/tests/baseline/shared/qbaselinetest.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef BASELINETEST_H #define BASELINETEST_H @@ -39,10 +14,11 @@ void handleCmdLineArgs(int *argcp, char ***argvp); void setProject(const QString &projectName); // Selects server config settings and top level dir void setProjectImageKeys(const QStringList &keys); // Overrides the ItemPathKeys config setting void addClientProperty(const QString& key, const QString& value); -bool connectToBaselineServer(QByteArray *msg = nullptr, const QString &testProject = QString(), const QString &testCase = QString()); +bool connectToBaselineServer(QByteArray *msg = nullptr); bool checkImage(const QImage& img, const char *name, quint16 checksum, QByteArray *msg, bool *error, int manualdatatag = 0); bool testImage(const QImage& img, QByteArray *msg, bool *error); QTestData &newRow(const char *dataTag, quint16 checksum = 0); +bool isCurrentItemBlacklisted(); bool disconnectFromBaselineServer(); bool shouldAbortIfUnstable(); } @@ -84,4 +60,15 @@ do {\ }\ } while (0) +#define QBASELINE_SKIP_IF_BLACKLISTED \ +do {\ + if (QBaselineTest::isCurrentItemBlacklisted())\ + QSKIP("Blacklisted on baseline server.");\ +} while (0) + +#define QBASELINETEST_MAIN(TestObject) QTEST_MAIN_WRAPPER(TestObject, \ + QHashSeed::setDeterministicGlobalSeed(); \ + QBaselineTest::handleCmdLineArgs(&argc, &argv); \ + QTEST_MAIN_SETUP()) + #endif // BASELINETEST_H diff --git a/tests/baseline/shared/qwidgetbaselinetest.cpp b/tests/baseline/shared/qwidgetbaselinetest.cpp index e4b36ddb69..72a074e268 100644 --- a/tests/baseline/shared/qwidgetbaselinetest.cpp +++ b/tests/baseline/shared/qwidgetbaselinetest.cpp @@ -1,38 +1,16 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "qwidgetbaselinetest.h" #include <qbaselinetest.h> #include <QApplication> #include <QStyle> +#include <QStyleHints> #include <QScreen> +#include <QtWidgets/private/qapplication_p.h> + QT_BEGIN_NAMESPACE QWidgetBaselineTest::QWidgetBaselineTest() @@ -47,18 +25,25 @@ QWidgetBaselineTest::QWidgetBaselineTest() // Encode a number of parameters that impact the UI QPalette palette; QFont font; - QByteArray appearanceBytes; - { - QDataStream appearanceStream(&appearanceBytes, QIODevice::WriteOnly); - appearanceStream << palette << font << + const QString styleName = #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QApplication::style()->metaObject()->className(); #else QApplication::style()->name(); #endif + // turn off animations and make the cursor flash time really long to avoid blinking + QApplication::style()->setProperty("_qt_animation_time", QTime()); + QGuiApplication::styleHints()->setCursorFlashTime(50000); + + QByteArray appearanceBytes; + { + QDataStream appearanceStream(&appearanceBytes, QIODevice::WriteOnly); + appearanceStream << palette << font; const qreal screenDpr = QApplication::primaryScreen()->devicePixelRatio(); - if (screenDpr != 1.0) - qWarning() << "DPR is" << screenDpr << "- images will be scaled"; + if (screenDpr != 1.0) { + qWarning() << "DPR is" << screenDpr << "- images will not be compared to 1.0 baseline!"; + appearanceStream << screenDpr; + } } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) const quint16 appearanceId = qChecksum(appearanceBytes, appearanceBytes.size()); @@ -72,8 +57,8 @@ QWidgetBaselineTest::QWidgetBaselineTest() const QColor windowColor = palette.window().color(); const QColor textColor = palette.text().color(); const QString appearanceIdString = (windowColor.value() > textColor.value() - ? QString("light-%1") : QString("dark-%1")) - .arg(appearanceId, 0, 16); + ? QString("light-%1-%2") : QString("dark-%1-%2")) + .arg(styleName).arg(appearanceId, 0, 16); QBaselineTest::addClientProperty("AppearanceID", appearanceIdString); // let users know where they can find the results @@ -92,11 +77,15 @@ void QWidgetBaselineTest::initTestCase() void QWidgetBaselineTest::init() { QVERIFY(!window); - window = new QWidget; + background = new QWidget(nullptr, Qt::FramelessWindowHint); + window = new QWidget(background, Qt::Window); window->setWindowTitle(QTest::currentDataTag()); + window->setFocusPolicy(Qt::StrongFocus); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + background->setScreen(QGuiApplication::primaryScreen()); window->setScreen(QGuiApplication::primaryScreen()); #endif + background->move(QGuiApplication::primaryScreen()->availableGeometry().topLeft()); window->move(QGuiApplication::primaryScreen()->availableGeometry().topLeft()); doInit(); @@ -106,33 +95,46 @@ void QWidgetBaselineTest::cleanup() { doCleanup(); - delete window; + delete background; + background = nullptr; window = nullptr; } void QWidgetBaselineTest::makeVisible() { Q_ASSERT(window); + background->showMaximized(); window->show(); - QApplication::setActiveWindow(window); + QApplicationPrivate::setActiveWindow(window); QVERIFY(QTest::qWaitForWindowActive(window)); - // explicitly unset focus, the test needs to control when focus is shown - if (window->focusWidget()) - window->focusWidget()->clearFocus(); + // explicitly set focus on the window so that the test widget doesn't have it + window->setFocus(Qt::OtherFocusReason); + QTRY_COMPARE(window->focusWidget(), window); } /* - Always return images scaled to a DPR of 1.0. - - This might produce some fuzzy differences, but lets us - compare those. + Grabs the test window and returns the resulting QImage, without + compensating for DPR differences. */ QImage QWidgetBaselineTest::takeSnapshot() { - QGuiApplication::processEvents(); - QPixmap pm = window->grab(); - QTransform scaleTransform = QTransform::fromScale(1.0 / pm.devicePixelRatioF(), 1.0 / pm.devicePixelRatioF()); - return pm.toImage().transformed(scaleTransform, Qt::SmoothTransformation); + // make sure all effects are done + QTest::qWait(250); + return window->grab().toImage(); +} + +/* + Grabs the test window screen and returns the resulting QImage, without + compensating for DPR differences. + This can be used for popup windows. +*/ +QImage QWidgetBaselineTest::takeScreenSnapshot(const QRect& windowRect) +{ + // make sure all effects are done - wait longer here because entire + // windows might be fading in and out. + QTest::qWait(750); + return window->screen()->grabWindow(0, windowRect.x(), windowRect.y(), + windowRect.width(), windowRect.height()).toImage(); } /*! @@ -145,23 +147,25 @@ QImage QWidgetBaselineTest::takeSnapshot() void QWidgetBaselineTest::takeStandardSnapshots() { makeVisible(); - struct PublicWidget : QWidget { - bool focusNextPrevChild(bool next) override { return QWidget::focusNextPrevChild(next); } - }; + QWidget *oldFocusWidget = testWindow()->focusWidget(); + QCOMPARE(oldFocusWidget, testWindow()); QBASELINE_CHECK_DEFERRED(takeSnapshot(), "default"); // try hard to set focus - static_cast<PublicWidget*>(window)->focusNextPrevChild(true); - if (!window->focusWidget()) { - QWidget *firstChild = window->findChild<QWidget*>(); - if (firstChild) - firstChild->setFocus(); - } - - if (testWindow()->focusWidget()) { + QWidget *testWidget = window->nextInFocusChain(); + if (!testWidget) + testWidget = window->findChild<QWidget*>(); + QVERIFY(testWidget); + // use TabFocusReason, some widgets handle that specifically to e.g. select + testWidget->setFocus(Qt::TabFocusReason); + + if (testWindow()->focusWidget() != oldFocusWidget) { QBASELINE_CHECK_DEFERRED(takeSnapshot(), "focused"); - testWindow()->focusWidget()->clearFocus(); + // set focus back + oldFocusWidget->setFocus(Qt::OtherFocusReason); + } else { + qWarning() << "Couldn't set focus on tested widget" << testWidget; } // this disables all children diff --git a/tests/baseline/shared/qwidgetbaselinetest.h b/tests/baseline/shared/qwidgetbaselinetest.h index db73dd0540..2142217c09 100644 --- a/tests/baseline/shared/qwidgetbaselinetest.h +++ b/tests/baseline/shared/qwidgetbaselinetest.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #pragma once @@ -57,8 +32,10 @@ private slots: protected: void makeVisible(); QImage takeSnapshot(); + QImage takeScreenSnapshot(const QRect& rect = QRect()); private: + QWidget *background = nullptr; QWidget *window = nullptr; }; |