Merge remote-tracking branch 'origin/5.13' into dev

Conflicts:
	src/widgets/styles/qstyle_p.h

Change-Id: I0e6e856bd6628da1135b3ba674dddffabbeb5c09
This commit is contained in:
Liang Qi 2019-04-11 07:47:21 +02:00
commit c7af193d2e
31 changed files with 838 additions and 385 deletions

View File

@ -242,7 +242,8 @@ static int doLink(int argc, char **argv)
#endif
static int installFile(const QString &source, const QString &target, bool exe = false)
static int installFile(const QString &source, const QString &target, bool exe = false,
bool preservePermissions = false)
{
QFile sourceFile(source);
QFile targetFile(target);
@ -260,35 +261,32 @@ static int installFile(const QString &source, const QString &target, bool exe =
return 3;
}
QFileDevice::Permissions targetPermissions = preservePermissions
? sourceFile.permissions()
: (QFileDevice::ReadOwner | QFileDevice::WriteOwner
| QFileDevice::ReadUser | QFileDevice::WriteUser
| QFileDevice::ReadGroup | QFileDevice::ReadOther);
if (exe) {
if (!targetFile.setPermissions(sourceFile.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeUser |
QFileDevice::ExeGroup | QFileDevice::ExeOther)) {
fprintf(stderr, "Error setting execute permissions on %s: %s\n",
qPrintable(target), qPrintable(targetFile.errorString()));
return 3;
}
targetPermissions |= QFileDevice::ExeOwner | QFileDevice::ExeUser |
QFileDevice::ExeGroup | QFileDevice::ExeOther;
}
if (!targetFile.setPermissions(targetPermissions)) {
fprintf(stderr, "Error setting permissions on %s: %s\n",
qPrintable(target), qPrintable(targetFile.errorString()));
return 3;
}
// Copy file times
QString error;
#ifdef Q_OS_WIN
const QFile::Permissions permissions = targetFile.permissions();
const bool readOnly = !(permissions & QFile::WriteUser);
if (readOnly)
targetFile.setPermissions(permissions | QFile::WriteUser);
#endif
if (!IoUtils::touchFile(target, sourceFile.fileName(), &error)) {
fprintf(stderr, "%s", qPrintable(error));
return 3;
}
#ifdef Q_OS_WIN
if (readOnly)
targetFile.setPermissions(permissions);
#endif
return 0;
}
static int installFileOrDirectory(const QString &source, const QString &target)
static int installFileOrDirectory(const QString &source, const QString &target,
bool preservePermissions = false)
{
QFileInfo fi(source);
if (false) {
@ -308,18 +306,18 @@ static int installFileOrDirectory(const QString &source, const QString &target)
} else if (fi.isDir()) {
QDir::current().mkpath(target);
QDirIterator it(source, QDir::AllEntries | QDir::NoDotAndDotDot);
QDirIterator it(source, QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
while (it.hasNext()) {
it.next();
const QFileInfo &entry = it.fileInfo();
const QString &entryTarget = target + QDir::separator() + entry.fileName();
const int recursionResult = installFileOrDirectory(entry.filePath(), entryTarget);
const int recursionResult = installFileOrDirectory(entry.filePath(), entryTarget, true);
if (recursionResult != 0)
return recursionResult;
}
} else {
const int fileCopyResult = installFile(source, target);
const int fileCopyResult = installFile(source, target, /*exe*/ false, preservePermissions);
if (fileCopyResult != 0)
return fileCopyResult;
}

View File

@ -257,6 +257,7 @@ CBOR_INLINE_API CborError cbor_encode_undefined(CborEncoder *encoder)
CBOR_INLINE_API CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
{ return cbor_encode_floating_point(encoder, CborHalfFloatType, value); }
CBOR_API CborError cbor_encode_float_as_half_float(CborEncoder *encoder, float value);
CBOR_INLINE_API CborError cbor_encode_float(CborEncoder *encoder, float value)
{ return cbor_encode_floating_point(encoder, CborFloatType, &value); }
CBOR_INLINE_API CborError cbor_encode_double(CborEncoder *encoder, double value)
@ -593,12 +594,13 @@ CBOR_API CborError cbor_value_map_find_value(const CborValue *map, const char *s
/* Floating point */
CBOR_INLINE_API bool cbor_value_is_half_float(const CborValue *value)
{ return value->type == CborHalfFloatType; }
CBOR_API CborError cbor_value_get_half_float_as_float(const CborValue *value, float *result);
CBOR_INLINE_API CborError cbor_value_get_half_float(const CborValue *value, void *result)
{
assert(cbor_value_is_half_float(value));
assert((value->flags & CborIteratorFlag_IntegerValueTooLarge) == 0);
/* size has been computed already */
/* size has already been computed */
memcpy(result, &value->extra, sizeof(value->extra));
return CborNoError;
}

View File

@ -76,7 +76,7 @@
* \code
* uint8_t buf[16];
* CborEncoder encoder, mapEncoder;
* cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
* cbor_encoder_init(&encoder, buf, sizeof(buf), 0);
* cbor_encoder_create_map(&encoder, &mapEncoder, 1);
* cbor_encode_text_stringz(&mapEncoder, "foo");
* cbor_encode_boolean(&mapEncoder, some_value);
@ -115,7 +115,7 @@
* uint8_t buf[16];
* CborError err;
* CborEncoder encoder, mapEncoder;
* cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
* cbor_encoder_init(&encoder, buf, sizeof(buf), 0);
* err = cbor_encoder_create_map(&encoder, &mapEncoder, 1);
* if (!err)
* return err;
@ -155,7 +155,7 @@
* goto error;
* buf = nbuf;
*
* cbor_encoder_init(&encoder, &buf, size, 0);
* cbor_encoder_init(&encoder, buf, size, 0);
* err = cbor_encoder_create_array(&encoder, &arrayEncoder, n);
* cbor_assert(err); // can't fail, the buffer is always big enough
*
@ -411,7 +411,7 @@ CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value)
* This function is useful for code that needs to pass through floating point
* values but does not wish to have the actual floating-point code.
*
* \sa cbor_encode_half_float, cbor_encode_float, cbor_encode_double
* \sa cbor_encode_half_float, cbor_encode_float_as_half_float, cbor_encode_float, cbor_encode_double
*/
CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value)
{
@ -621,13 +621,25 @@ CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *
* \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double()
*/
/**
* \fn CborError cbor_encode_float_as_half_float(CborEncoder *encoder, float value)
*
* Convert the IEEE 754 single-precision (32-bit) floating point value \a value
* to the IEEE 754 half-precision (16-bit) floating point value and append it
* to the CBOR stream provided by \a encoder.
* The \a value should be in the range of the IEEE 754 half-precision floating point type,
* INFINITY, -INFINITY, or NAN, otherwise the behavior of this function is undefined.
*
* \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double()
*/
/**
* \fn CborError cbor_encode_float(CborEncoder *encoder, float value)
*
* Appends the IEEE 754 single-precision (32-bit) floating point value \a value
* to the CBOR stream provided by \a encoder.
*
* \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_double()
* \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float_as_half_float(), cbor_encode_double()
*/
/**
@ -636,7 +648,7 @@ CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *
* Appends the IEEE 754 double-precision (64-bit) floating point value \a value
* to the CBOR stream provided by \a encoder.
*
* \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float()
* \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float_as_half_float(), cbor_encode_float()
*/
/**

View File

@ -1520,7 +1520,7 @@ error:
* floating point, this function takes a \c{void *} as a parameter for the
* storage area, which must be at least 16 bits wide.
*
* \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_float()
* \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_half_float_as_float(), cbor_value_get_float()
*/
/** @} */

View File

@ -106,7 +106,7 @@
# define cbor_ntohs __builtin_bswap16
# define cbor_htons __builtin_bswap16
# else
# define cbor_ntohs(x) (((uint16_t)x >> 8) | ((uint16_t)x << 8))
# define cbor_ntohs(x) (((uint16_t)(x) >> 8) | ((uint16_t)(x) << 8))
# define cbor_htons cbor_ntohs
# endif
# else

View File

@ -123,6 +123,42 @@ QVariant make_ilmap(const std::initializer_list<QPair<QVariant, QVariant>> &list
return QVariant::fromValue(IndeterminateLengthMap(list));
}
void addHalfFloat()
{
QTest::addColumn<QByteArray>("output");
QTest::addColumn<unsigned>("rawInput");
QTest::addColumn<double>("floatInput");
QTest::newRow("+0") << raw("\x00\x00") << 0U << 0.0;
QTest::newRow("-0") << raw("\x80\x00") << 0x8000U << 0.0;
QTest::newRow("min.denorm") << raw("\x00\x01") << 1U << ldexp(1.0, -14) * ldexp(1.0, -10);
QTest::newRow("-min.denorm") << raw("\x80\x01") << 0x8001U << ldexp(-1.0, -14) * ldexp(1.0, -10);
QTest::newRow("max.denorm") << raw("\x03\xff") << 0x03ffU << ldexp(1.0, -14) * (1.0 - ldexp(1.0, -10));
QTest::newRow("-max.denorm") << raw("\x83\xff") << 0x83ffU << ldexp(-1.0, -14) * (1.0 - ldexp(1.0, -10));
QTest::newRow("min.norm") << raw("\x04\x00") << 0x0400U << ldexp(1.0, -14);
QTest::newRow("-min.norm") << raw("\x84\x00") << 0x8400U << ldexp(-1.0, -14);
QTest::newRow("1.0") << raw("\x3c\x00") << 0x3c00U << 1.0;
QTest::newRow("-1.0") << raw("\xbc\x00") << 0xbc00U << -1.0;
QTest::newRow("1.5") << raw("\x3e\x00") << 0x3e00U << 1.5;
QTest::newRow("-1.5") << raw("\xbe\x00") << 0xbe00U << -1.5;
QTest::newRow("max") << raw("\x7b\xff") << 0x7bffU << ldexp(1.0, 15) * (2.0 - ldexp(1.0, -10));
QTest::newRow("-max") << raw("\xfb\xff") << 0xfbffU << ldexp(-1.0, 15) * (2.0 - ldexp(1.0, -10));
QTest::newRow("inf") << raw("\x7c\x00") << 0x7c00U << myInf();
QTest::newRow("-inf") << raw("\xfc\x00") << 0xfc00U << myNInf();
QTest::newRow("nan1") << raw("\x7c\x01") << 0x7c01U << myNaN();
QTest::newRow("nan2") << raw("\xfc\x01") << 0xfc01U << myNaN();
QTest::newRow("nan3") << raw("\x7e\x00") << 0x7e00U << myNaN();
QTest::newRow("nan4") << raw("\xfe\x00") << 0xfe00U << myNaN();
}
void addColumns()
{
QTest::addColumn<QByteArray>("output");

View File

@ -41,6 +41,13 @@ class tst_Encoder : public QObject
{
Q_OBJECT
private slots:
void floatAsHalfFloat_data();
void floatAsHalfFloat();
void halfFloat_data();
void halfFloat();
void floatAsHalfFloatCloseToZero_data();
void floatAsHalfFloatCloseToZero();
void floatAsHalfFloatNaN();
void fixed_data();
void fixed();
void strings_data();
@ -178,21 +185,127 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v)
return CborErrorUnknownType;
}
void compare(const QVariant &input, const QByteArray &output)
template <typename Input, typename FnUnderTest>
void encodeOne(Input input, FnUnderTest fn_under_test, QByteArray &buffer, CborError &error)
{
QByteArray buffer(output.length(), Qt::Uninitialized);
uint8_t *bufptr = reinterpret_cast<quint8 *>(buffer.data());
CborEncoder encoder;
cbor_encoder_init(&encoder, bufptr, buffer.length(), 0);
QCOMPARE(encodeVariant(&encoder, input), CborNoError);
QCOMPARE(encoder.remaining, size_t(1));
QCOMPARE(cbor_encoder_get_extra_bytes_needed(&encoder), size_t(0));
error = fn_under_test(&encoder, input);
buffer.resize(int(cbor_encoder_get_buffer_size(&encoder, bufptr)));
if (error == CborNoError) {
QCOMPARE(encoder.remaining, size_t(1));
QCOMPARE(cbor_encoder_get_extra_bytes_needed(&encoder), size_t(0));
buffer.resize(int(cbor_encoder_get_buffer_size(&encoder, bufptr)));
}
}
template <typename Input, typename FnUnderTest>
void compare(Input input, FnUnderTest fn_under_test, const QByteArray &output)
{
QByteArray buffer(output.length(), Qt::Uninitialized);
CborError error;
encodeOne(input, fn_under_test, buffer, error);
if (QTest::currentTestFailed())
return;
QCOMPARE(error, CborNoError);
QCOMPARE(buffer, output);
}
void compare(const QVariant &input, const QByteArray &output)
{
compare(input, encodeVariant, output);
}
void tst_Encoder::floatAsHalfFloat_data()
{
addHalfFloat();
}
void tst_Encoder::floatAsHalfFloat()
{
QFETCH(unsigned, rawInput);
QFETCH(double, floatInput);
QFETCH(QByteArray, output);
if (rawInput == 0U || rawInput == 0x8000U)
QSKIP("zero values are out of scope of this test case", QTest::SkipSingle);
if (qIsNaN(floatInput))
QSKIP("NaN values are out of scope of this test case", QTest::SkipSingle);
output.prepend('\xf9');
compare((float)floatInput, cbor_encode_float_as_half_float, output);
}
void tst_Encoder::halfFloat_data()
{
addHalfFloat();
}
void tst_Encoder::halfFloat()
{
QFETCH(unsigned, rawInput);
QFETCH(QByteArray, output);
uint16_t v = (uint16_t)rawInput;
output.prepend('\xf9');
compare(&v, cbor_encode_half_float, output);
}
void tst_Encoder::floatAsHalfFloatCloseToZero_data()
{
QTest::addColumn<double>("floatInput");
QTest::newRow("+0") << 0.0;
QTest::newRow("-0") << -0.0;
QTest::newRow("below min.denorm") << ldexp(1.0, -14) * ldexp(1.0, -11);
QTest::newRow("above -min.denorm") << ldexp(-1.0, -14) * ldexp(1.0, -11);
}
void tst_Encoder::floatAsHalfFloatCloseToZero()
{
QFETCH(double, floatInput);
QByteArray buffer(4, Qt::Uninitialized);
CborError error;
encodeOne((float)floatInput, cbor_encode_float_as_half_float, buffer, error);
QCOMPARE(error, CborNoError);
QVERIFY2(
buffer == raw("\xf9\x00\x00") || buffer == raw("\xf9\x80\x00"),
"Got value " + QByteArray::number(floatInput) + " encoded to: " + buffer);
}
void tst_Encoder::floatAsHalfFloatNaN()
{
QByteArray buffer(4, Qt::Uninitialized);
CborError error;
encodeOne(myNaNf(), cbor_encode_float_as_half_float, buffer, error);
QCOMPARE(error, CborNoError);
QCOMPARE(buffer.size(), 3);
uint8_t ini_byte = (uint8_t)buffer[0],
exp = (uint8_t)buffer[1] & 0x7cU,
manth = (uint8_t)buffer[1] & 0x03U,
mantl = (uint8_t)buffer[2];
QCOMPARE((unsigned)ini_byte, 0xf9U);
QCOMPARE((unsigned)exp, 0x7cU);
QVERIFY((manth | mantl) != 0);
}
void tst_Encoder::fixed_data()
{
addColumns();

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2017 Intel Corporation
** Copyright (C) 2019 Intel Corporation
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
@ -23,11 +23,22 @@
****************************************************************************/
#define _XOPEN_SOURCE 700
#define _DARWIN_C_SOURCE 1 /* need MAP_ANON */
#include <QtTest>
#include "cbor.h"
#include <stdio.h>
#include <stdarg.h>
#if defined(Q_OS_UNIX)
# include <sys/mman.h>
# include <unistd.h>
#elif defined(Q_OS_WIN)
# define WIN32_LEAN_AND_MEAN 1
# define NOMINMAX 1
# include <windows.h>
#endif
namespace QTest {
template<> char *toString<CborError>(const CborError &err)
{
@ -44,6 +55,8 @@ private slots:
// parsing API
void integers_data();
void integers();
void halfFloat_data();
void halfFloat();
void fixed_data();
void fixed();
void strings_data();
@ -105,6 +118,100 @@ private slots:
void recursionLimit();
};
struct ParserWrapper
{
void *realdata = nullptr;
uint8_t *data;
size_t len;
CborParser parser;
CborValue first;
~ParserWrapper() { freeMemory(); }
CborError init(const QByteArray &ba, uint32_t flags = 0)
{
return init(ba.constData(), ba.size(), flags);
}
CborError init(const char *ptr, int n, uint32_t flags = 0)
{
freeMemory();
data = allocateMemory(n);
memcpy(data, ptr, len);
return cbor_parser_init(data, len, flags, &parser, &first);
}
uint8_t *begin() { return data; }
uint8_t *end() { return data + len; }
uint8_t *allocateMemory(size_t);
void freeMemory();
static const size_t PageSize = 4096;
static inline size_t mmapAllocation(size_t n)
{
// round up and add one page
return (n + 2*PageSize) & ~(PageSize - 1);
}
static bool shouldUseMmap();
};
bool ParserWrapper::shouldUseMmap()
{
static int v = qEnvironmentVariableIntValue("PARSER_NO_MMAP");
return !v;
}
uint8_t *ParserWrapper::allocateMemory(size_t n)
{
len = n;
if (shouldUseMmap()) {
size_t alloc = mmapAllocation(n);
#if defined(Q_OS_UNIX)
realdata = mmap(nullptr, alloc, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
Q_ASSERT_X(realdata != MAP_FAILED, "allocateMemory", "mmap failed!");
// mark last page inaccessible
uint8_t *ptr = static_cast<uint8_t *>(realdata);
ptr += alloc - PageSize;
mprotect(ptr, PageSize, PROT_NONE);
ptr -= n;
return ptr;
#elif defined(Q_OS_WIN)
DWORD flAllocationType = MEM_COMMIT | MEM_RESERVE;
DWORD flProtect = PAGE_READWRITE;
realdata = VirtualAlloc(nullptr, alloc, flAllocationType, flProtect);
Q_ASSERT_X(realdata, "allocateMemory", "VirtualAlloc failed!");
// mark last page inaccessible
uint8_t *ptr = static_cast<uint8_t *>(realdata);
ptr += alloc - PageSize;
VirtualProtect(ptr, PageSize, PAGE_NOACCESS, nullptr);
ptr -= n;
return ptr;
#endif
}
realdata = malloc(n);
return static_cast<uint8_t *>(realdata);
}
void ParserWrapper::freeMemory()
{
if (shouldUseMmap()) {
if (realdata) {
#if defined(Q_OS_UNIX)
size_t alloc = mmapAllocation(len);
munmap(realdata, alloc);
#elif defined(Q_OS_WIN)
VirtualFree(realdata, 0, MEM_RELEASE);
#endif
}
return;
}
free(realdata);
}
static CborError qstring_printf(void *out, const char *fmt, ...)
{
auto str = static_cast<QString *>(out);
@ -166,47 +273,46 @@ bool compareFailed = true;
void compareOne_real(const QByteArray &data, const QString &expected, int line, int n = -1)
{
compareFailed = true;
CborParser parser;
CborValue first;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
if (cbor_value_get_type(&first) == CborArrayType) {
if (cbor_value_get_type(&w.first) == CborArrayType) {
size_t len;
if (n >= 0) {
QVERIFY(cbor_value_is_length_known(&first));
QCOMPARE(cbor_value_get_array_length(&first, &len), CborNoError);
QVERIFY(cbor_value_is_length_known(&w.first));
QCOMPARE(cbor_value_get_array_length(&w.first, &len), CborNoError);
QCOMPARE(len, size_t(len));
} else {
QVERIFY(!cbor_value_is_length_known(&first));
QCOMPARE(cbor_value_get_array_length(&first, &len), CborErrorUnknownLength);
QVERIFY(!cbor_value_is_length_known(&w.first));
QCOMPARE(cbor_value_get_array_length(&w.first, &len), CborErrorUnknownLength);
}
} else if (cbor_value_get_type(&first) == CborMapType) {
} else if (cbor_value_get_type(&w.first) == CborMapType) {
size_t len;
if (n >= 0) {
QVERIFY(cbor_value_is_length_known(&first));
QCOMPARE(cbor_value_get_map_length(&first, &len), CborNoError);
QVERIFY(cbor_value_is_length_known(&w.first));
QCOMPARE(cbor_value_get_map_length(&w.first, &len), CborNoError);
QCOMPARE(len, size_t(len));
} else {
QVERIFY(!cbor_value_is_length_known(&first));
QCOMPARE(cbor_value_get_map_length(&first, &len), CborErrorUnknownLength);
QVERIFY(!cbor_value_is_length_known(&w.first));
QCOMPARE(cbor_value_get_map_length(&w.first, &len), CborErrorUnknownLength);
}
} else if (cbor_value_is_text_string(&first) || cbor_value_is_byte_string(&first)) {
} else if (cbor_value_is_text_string(&w.first) || cbor_value_is_byte_string(&w.first)) {
size_t len;
QCOMPARE(cbor_value_calculate_string_length(&first, &len), CborNoError);
if (cbor_value_is_length_known(&first)) {
QCOMPARE(cbor_value_calculate_string_length(&w.first, &len), CborNoError);
if (cbor_value_is_length_known(&w.first)) {
size_t len2;
QCOMPARE(cbor_value_get_string_length(&first, &len2), CborNoError);
QCOMPARE(cbor_value_get_string_length(&w.first, &len2), CborNoError);
QCOMPARE(len2, len);
} else {
QCOMPARE(cbor_value_get_string_length(&first, &len), CborErrorUnknownLength);
QCOMPARE(cbor_value_get_string_length(&w.first, &len), CborErrorUnknownLength);
}
}
CborError err2 = cbor_value_validate_basic(&first);
CborError err2 = cbor_value_validate_basic(&w.first);
QString decoded;
err = parseOne(&first, &decoded);
err = parseOne(&w.first, &decoded);
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) +
"\"; decoded stream:\n" + decoded.toLatin1());
QCOMPARE(decoded, expected);
@ -215,7 +321,7 @@ void compareOne_real(const QByteArray &data, const QString &expected, int line,
QCOMPARE(err2, err);
// check that we consumed everything
QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd());
QCOMPARE((void*)cbor_value_get_next_byte(&w.first), (void*)w.end());
compareFailed = false;
}
@ -237,39 +343,112 @@ void tst_Parser::integers()
QFETCH(qint64, expectedValue);
QFETCH(bool, inInt64Range);
CborParser parser;
CborValue first;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
QVERIFY(cbor_value_is_integer(&first));
QVERIFY(cbor_value_is_integer(&w.first));
uint64_t raw;
cbor_value_get_raw_integer(&first, &raw);
cbor_value_get_raw_integer(&w.first, &raw);
QCOMPARE(quint64(raw), expectedRaw);
if (isNegative) {
QVERIFY(cbor_value_is_negative_integer(&first));
QVERIFY(!cbor_value_is_unsigned_integer(&first));
QVERIFY(cbor_value_is_negative_integer(&w.first));
QVERIFY(!cbor_value_is_unsigned_integer(&w.first));
} else {
QVERIFY(!cbor_value_is_negative_integer(&first));
QVERIFY(cbor_value_is_unsigned_integer(&first));
QVERIFY(!cbor_value_is_negative_integer(&w.first));
QVERIFY(cbor_value_is_unsigned_integer(&w.first));
}
int64_t value;
if (inInt64Range) {
cbor_value_get_int64(&first, &value);
cbor_value_get_int64(&w.first, &value);
QCOMPARE(qint64(value), expectedValue);
}
err = cbor_value_get_int64_checked(&first, &value);
err = cbor_value_get_int64_checked(&w.first, &value);
QCOMPARE(err, inInt64Range ? CborNoError : CborErrorDataTooLarge);
int ivalue;
bool inIntRange = inInt64Range && (expectedValue == int(expectedValue));
err = cbor_value_get_int_checked(&first, &ivalue);
err = cbor_value_get_int_checked(&w.first, &ivalue);
QCOMPARE(err, inIntRange ? CborNoError : CborErrorDataTooLarge);
}
static void addHalfFloat()
{
QTest::addColumn<QByteArray>("data");
QTest::addColumn<unsigned>("expectedRaw");
QTest::addColumn<double>("expectedValue");
QTest::newRow("+0") << raw("\x00\x00") << 0U << 0.0;
QTest::newRow("-0") << raw("\x80\x00") << 0x8000U << 0.0;
QTest::newRow("min.denorm") << raw("\x00\x01") << 1U << ldexp(1.0, -14) * ldexp(1.0, -10);
QTest::newRow("-min.denorm") << raw("\x80\x01") << 0x8001U << ldexp(-1.0, -14) * ldexp(1.0, -10);
QTest::newRow("max.denorm") << raw("\x03\xff") << 0x03ffU << ldexp(1.0, -14) * (1.0 - ldexp(1.0, -10));
QTest::newRow("-max.denorm") << raw("\x83\xff") << 0x83ffU << ldexp(-1.0, -14) * (1.0 - ldexp(1.0, -10));
QTest::newRow("min.norm") << raw("\x04\x00") << 0x0400U << ldexp(1.0, -14);
QTest::newRow("-min.norm") << raw("\x84\x00") << 0x8400U << ldexp(-1.0, -14);
QTest::newRow("1.0") << raw("\x3c\x00") << 0x3c00U << 1.0;
QTest::newRow("-1.0") << raw("\xbc\x00") << 0xbc00U << -1.0;
QTest::newRow("1.5") << raw("\x3e\x00") << 0x3e00U << 1.5;
QTest::newRow("-1.5") << raw("\xbe\x00") << 0xbe00U << -1.5;
QTest::newRow("max") << raw("\x7b\xff") << 0x7bffU << ldexp(1.0, 15) * (2.0 - ldexp(1.0, -10));
QTest::newRow("-max") << raw("\xfb\xff") << 0xfbffU << ldexp(-1.0, 15) * (2.0 - ldexp(1.0, -10));
QTest::newRow("inf") << raw("\x7c\x00") << 0x7c00U << double(INFINITY);
QTest::newRow("-inf") << raw("\xfc\x00") << 0xfc00U << double(-INFINITY);
QTest::newRow("nan") << raw("\x7c\x01") << 0x7c01U << double(NAN);
QTest::newRow("nan2") << raw("\xfc\x01") << 0xfc01U << double(NAN);
QTest::newRow("nan3") << raw("\x7e\x00") << 0x7e00U << double(NAN);
QTest::newRow("nan4") << raw("\xfe\x00") << 0xfe00U << double(NAN);
}
void tst_Parser::halfFloat_data()
{
addHalfFloat();
}
void tst_Parser::halfFloat()
{
QFETCH(QByteArray, data);
QFETCH(unsigned, expectedRaw);
QFETCH(double, expectedValue);
CborParser parser;
CborValue first;
data.prepend('\xf9');
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
QVERIFY(cbor_value_is_half_float(&first));
uint16_t raw;
cbor_value_get_half_float(&first, &raw);
QCOMPARE(raw, uint16_t(expectedRaw));
float value;
cbor_value_get_half_float_as_float(&first, &value);
const double epsilon = ldexp(1.0, -25);
if (qIsNaN(expectedValue)) {
QVERIFY(qIsNaN(value));
} else if (qIsInf(expectedValue)) {
QVERIFY(value == (float)expectedValue);
} else {
QVERIFY(qAbs(value - (float)expectedValue) < epsilon);
}
}
void tst_Parser::fixed_data()
{
addColumns();
@ -678,14 +857,13 @@ void tst_Parser::chunkedString_data()
static void chunkedStringTest(const QByteArray &data, const QString &concatenated,
QStringList &chunks, CborType ourType)
{
CborParser parser;
CborValue first;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
CborValue value;
QVERIFY(cbor_value_is_array(&first));
err = cbor_value_enter_container(&first, &value);
QVERIFY(cbor_value_is_array(&w.first));
err = cbor_value_enter_container(&w.first, &value);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
QVERIFY(cbor_value_is_byte_string(&value) || cbor_value_is_text_string(&value));
@ -748,9 +926,9 @@ static void chunkedStringTest(const QByteArray &data, const QString &concatenate
// confirm EOF
QVERIFY(cbor_value_at_end(&value));
err = cbor_value_leave_container(&first, &value);
err = cbor_value_leave_container(&w.first, &value);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd());
QCOMPARE((void*)cbor_value_get_next_byte(&w.first), (void*)w.end());
}
void tst_Parser::chunkedString()
@ -840,18 +1018,17 @@ void tst_Parser::stringLength()
QFETCH(QByteArray, data);
QFETCH(int, expected);
CborParser parser;
CborValue value;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
size_t result;
err = cbor_value_calculate_string_length(&value, &result);
err = cbor_value_calculate_string_length(&w.first, &result);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
QCOMPARE(result, size_t(expected));
if (cbor_value_is_length_known(&value)) {
QCOMPARE(cbor_value_get_string_length(&value, &result), CborNoError);
if (cbor_value_is_length_known(&w.first)) {
QCOMPARE(cbor_value_get_string_length(&w.first, &result), CborNoError);
QCOMPARE(result, size_t(expected));
}
@ -935,25 +1112,24 @@ void compareOneString(const QByteArray &data, const QString &string, bool expect
{
compareFailed = true;
CborParser parser;
CborValue value;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
bool result;
QByteArray bastring = string.toUtf8();
err = cbor_value_text_string_equals(&value, bastring.constData(), &result);
err = cbor_value_text_string_equals(&w.first, bastring.constData(), &result);
QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
QCOMPARE(result, expected);
if (expected) {
size_t len;
cbor_value_skip_tag(&value);
if (cbor_value_is_length_known(&value)) {
QCOMPARE(cbor_value_get_string_length(&value, &len), CborNoError);
cbor_value_skip_tag(&w.first);
if (cbor_value_is_length_known(&w.first)) {
QCOMPARE(cbor_value_get_string_length(&w.first, &len), CborNoError);
QCOMPARE(int(len), bastring.size());
}
QCOMPARE(cbor_value_calculate_string_length(&value, &len), CborNoError);
QCOMPARE(cbor_value_calculate_string_length(&w.first, &len), CborNoError);
QCOMPARE(int(len), bastring.size());
}
@ -1042,13 +1218,12 @@ void tst_Parser::mapFind()
QFETCH(QByteArray, data);
QFETCH(bool, expected);
CborParser parser;
CborValue value;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
CborValue element;
err = cbor_value_map_find_value(&value, "needle", &element);
err = cbor_value_map_find_value(&w.first, "needle", &element);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
if (expected) {
@ -1119,13 +1294,12 @@ void tst_Parser::checkedIntegers()
QFETCH(QVariant, result);
int64_t expected = result.toLongLong();
CborParser parser;
CborValue value;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &value);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
int64_t v;
err = cbor_value_get_int64_checked(&value, &v);
err = cbor_value_get_int64_checked(&w.first, &v);
if (result.isNull()) {
QCOMPARE(err, CborErrorDataTooLarge);
} else {
@ -1133,7 +1307,7 @@ void tst_Parser::checkedIntegers()
}
int v2;
err = cbor_value_get_int_checked(&value, &v2);
err = cbor_value_get_int_checked(&w.first, &v2);
if (result.isNull() || expected < std::numeric_limits<int>::min() || expected > std::numeric_limits<int>::max()) {
QCOMPARE(err, CborErrorDataTooLarge);
} else {
@ -1154,14 +1328,13 @@ void tst_Parser::validation()
QFETCH(CborError, expectedError);
QString decoded;
CborParser parser;
CborValue first;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), flags, &parser, &first);
ParserWrapper w;
CborError err = w.init(data, uint32_t(flags));
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
CborError err2 = cbor_value_validate_basic(&first);
CborError err3 = cbor_value_validate(&first, CborValidateBasic);
err = parseOne(&first, &decoded);
CborError err2 = cbor_value_validate_basic(&w.first);
CborError err3 = cbor_value_validate(&w.first, CborValidateBasic);
err = parseOne(&w.first, &decoded);
QCOMPARE(err, expectedError);
if (!QByteArray(QTest::currentDataTag()).contains("utf8")) {
QCOMPARE(err2, expectedError);
@ -1352,24 +1525,36 @@ void tst_Parser::strictValidation_data()
QTest::newRow("overlong-_stringx2-0*8") << raw("\x7f\x60\x7b\0\0\0\0\0\0\0\0\xff") << int(CborValidateShortestNumbers) << CborErrorOverlongEncoding;
// strict mode
QTest::newRow("invalid-utf8-1char") << raw("\x61\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-2chars-1") << raw("\x62\xc2\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-2chars-2") << raw("\x62\xc3\xdf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-2chars-3") << raw("\x62\xc7\xf0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-3chars-1") << raw("\x63\xe0\xa0\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-3chars-2") << raw("\x63\xe0\xc0\xa0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-4chars-1") << raw("\x64\xf0\x90\x80\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-4chars-2") << raw("\x64\xf0\x90\xc0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-4chars-3") << raw("\x64\xf0\xc0\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
// UTF-8 sequences with invalid continuation bytes
QTest::newRow("invalid-utf8-bad-continuation-1char") << raw("\x61\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-bad-continuation-2chars-1") << raw("\x62\xc2\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-bad-continuation-2chars-2") << raw("\x62\xc3\xdf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-bad-continuation-2chars-3") << raw("\x62\xc7\xf0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-bad-continuation-3chars-1") << raw("\x63\xe0\xa0\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-bad-continuation-3chars-2") << raw("\x63\xe0\xc0\xa0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-bad-continuation-4chars-1") << raw("\x64\xf0\x90\x80\xc0") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-bad-continuation-4chars-2") << raw("\x64\xf0\x90\xc0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-bad-continuation-4chars-3") << raw("\x64\xf0\xc0\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
// Too short UTF-8 sequences (in an array so there's a byte after that would make it valid UTF-8 if it were part of the string)
QTest::newRow("invalid-utf8-too-short-2chars") << raw("\x82\x61\xc2\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-too-short-3chars-1") << raw("\x82\x61\xe0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-too-short-3chars-2") << raw("\x82\x62\xe0\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-too-short-4chars-1") << raw("\x82\x61\xf0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-too-short-4chars-2") << raw("\x82\x62\xf0\x90\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-too-short-4chars-3") << raw("\x82\x63\xf0\x90\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
// UTF-16 surrogages encoded in UTF-8
QTest::newRow("invalid-utf8-hi-surrogate") << raw("\x63\xed\xa0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-lo-surrogate") << raw("\x63\xed\xb0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-surrogate-pair") << raw("\x66\xed\xa0\x80\xed\xb0\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
// Non-Unicode UTF-8 sequences
QTest::newRow("invalid-utf8-non-unicode-1") << raw("\x64\xf4\x90\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-non-unicode-2") << raw("\x65\xf8\x88\x80\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-non-unicode-3") << raw("\x66\xfc\x84\x80\x80\x80\x80") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-non-unicode-4") << raw("\x66\xfd\xbf\xbf\xbf\xbf\xbf") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
// invalid bytes in UTF-8
QTest::newRow("invalid-utf8-fe") << raw("\x61\xfe") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-ff") << raw("\x61\xff") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
// Overlong sequences
QTest::newRow("invalid-utf8-overlong-1-2") << raw("\x62\xc1\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-overlong-1-3") << raw("\x63\xe0\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
QTest::newRow("invalid-utf8-overlong-1-4") << raw("\x64\xf0\x80\x81\x81") << int(CborValidateStrictMode) << CborErrorInvalidUtf8TextString;
@ -1525,12 +1710,11 @@ void tst_Parser::strictValidation()
QFETCH(CborError, expectedError);
QString decoded;
CborParser parser;
CborValue first;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
err = cbor_value_validate(&first, flags);
err = cbor_value_validate(&w.first, flags);
QCOMPARE(err, expectedError);
}
@ -1549,12 +1733,11 @@ void tst_Parser::incompleteData()
QFETCH(QString, expected);
for (int len = 0; len < data.length() - 1; ++len) {
CborParser parser;
CborValue first;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), len, 0, &parser, &first);
ParserWrapper w;
CborError err = w.init(data.constData(), len);
if (!err) {
QString decoded;
err = parseOne(&first, &decoded);
err = parseOne(&w.first, &decoded);
}
if (err != CborErrorUnexpectedEOF)
qDebug() << "Length is" << len;
@ -1583,14 +1766,13 @@ void tst_Parser::endPointer()
QFETCH(int, offset);
QString decoded;
CborParser parser;
CborValue first;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
err = parseOne(&first, &decoded);
err = parseOne(&w.first, &decoded);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
QCOMPARE(int(cbor_value_get_next_byte(&first) - reinterpret_cast<const quint8 *>(data.constBegin())), offset);
QCOMPARE(int(cbor_value_get_next_byte(&w.first) - w.begin()), offset);
}
void tst_Parser::recursionLimit_data()
@ -1638,24 +1820,23 @@ void tst_Parser::recursionLimit()
{
QFETCH(QByteArray, data);
CborParser parser;
CborValue first;
CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
ParserWrapper w;
CborError err = w.init(data);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
// check that it is valid:
CborValue it = first;
CborValue it = w.first;
{
QString dummy;
err = parseOne(&it, &dummy);
QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\"");
}
it = first;
it = w.first;
err = cbor_value_advance(&it);
QCOMPARE(err, CborErrorNestingTooDeep);
it = first;
it = w.first;
if (cbor_value_is_map(&it)) {
CborValue dummy;
err = cbor_value_map_find_value(&it, "foo", &dummy);

View File

@ -77,15 +77,6 @@ static inline qint64 ticksToNanoseconds(qint64 ticks)
return ticks * 1000000;
}
static inline qint64 nanosecondsToTicks(qint64 nsec)
{
if (counterFrequency > 0) {
// QueryPerformanceCounter uses an arbitrary frequency
return double(nsec) * counterFrequency / 1000000000.;
}
// GetTickCount(64) uses milliseconds
return nsec / 1000000;
}
static quint64 getTickCount()
{

View File

@ -235,6 +235,12 @@ QObject *QMetaObject::newInstance(QGenericArgument val0,
QGenericArgument val8,
QGenericArgument val9) const
{
if (!inherits(&QObject::staticMetaObject))
{
qWarning("QMetaObject::newInstance: type %s does not inherit QObject", className());
return nullptr;
}
QByteArray constructorName = className();
{
int idx = constructorName.lastIndexOf(':');

View File

@ -817,7 +817,7 @@ bool QTranslatorPrivate::do_load(const uchar *data, qsizetype len, const QString
data += MagicLength;
QStringList dependencies;
while (data < end - 4) {
while (data < end - 5) {
quint8 tag = read8(data++);
quint32 blockLen = read32(data);
data += 4;

View File

@ -101,6 +101,16 @@ static CborError _cbor_value_dup_string(const CborValue *, void **, size_t *, Cb
Q_UNREACHABLE();
return CborErrorInternalError;
}
static CborError cbor_value_get_half_float_as_float(const CborValue *, float *)
{
Q_UNREACHABLE();
return CborErrorInternalError;
}
static CborError cbor_encode_float_as_half_float(CborEncoder *, float)
{
Q_UNREACHABLE();
return CborErrorInternalError;
}
QT_WARNING_POP
Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);

View File

@ -260,21 +260,22 @@ namespace
QByteArray replaceParameters(const QByteArray &original, const QShaderNode &node, const QShaderFormat &format)
{
auto result = original;
QByteArray result = original;
for (const auto &parameterName : node.parameterNames()) {
const auto placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8());
const auto parameter = node.parameter(parameterName);
const QStringList parameterNames = node.parameterNames();
for (const QString &parameterName : parameterNames) {
const QByteArray placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8());
const QVariant parameter = node.parameter(parameterName);
if (parameter.userType() == qMetaTypeId<QShaderLanguage::StorageQualifier>()) {
const auto qualifier = parameter.value<QShaderLanguage::StorageQualifier>();
const auto value = toGlsl(qualifier, format);
const QShaderLanguage::StorageQualifier qualifier = parameter.value<QShaderLanguage::StorageQualifier>();
const QByteArray value = toGlsl(qualifier, format);
result.replace(placeholder, value);
} else if (parameter.userType() == qMetaTypeId<QShaderLanguage::VariableType>()) {
const auto type = parameter.value<QShaderLanguage::VariableType>();
const auto value = toGlsl(type);
const QShaderLanguage::VariableType type = parameter.value<QShaderLanguage::VariableType>();
const QByteArray value = toGlsl(type);
result.replace(placeholder, value);
} else {
const auto value = parameter.toString().toUtf8();
const QByteArray value = parameter.toString().toUtf8();
result.replace(placeholder, value);
}
}
@ -288,20 +289,20 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
auto code = QByteArrayList();
if (format.isValid()) {
const auto isGLES = format.api() == QShaderFormat::OpenGLES;
const auto major = format.version().majorVersion();
const auto minor = format.version().minorVersion();
const bool isGLES = format.api() == QShaderFormat::OpenGLES;
const int major = format.version().majorVersion();
const int minor = format.version().minorVersion();
const auto version = major == 2 && isGLES ? 100
: major == 3 && isGLES ? 300
: major == 2 ? 100 + 10 * (minor + 1)
: major == 3 && minor <= 2 ? 100 + 10 * (minor + 3)
: major * 100 + minor * 10;
const int version = major == 2 && isGLES ? 100
: major == 3 && isGLES ? 300
: major == 2 ? 100 + 10 * (minor + 1)
: major == 3 && minor <= 2 ? 100 + 10 * (minor + 3)
: major * 100 + minor * 10;
const auto profile = isGLES && version > 100 ? QByteArrayLiteral(" es")
: version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core")
: version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility")
: QByteArray();
const QByteArray profile = isGLES && version > 100 ? QByteArrayLiteral(" es")
: version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core")
: version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility")
: QByteArray();
code << (QByteArrayLiteral("#version ") + QByteArray::number(version) + profile);
code << QByteArray();
@ -313,9 +314,11 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
};
for (const auto &node : graph.nodes()) {
const QVector<QShaderNode> nodes = graph.nodes();
for (const QShaderNode &node : nodes) {
if (intersectsEnabledLayers(node.layers())) {
for (const auto &snippet : node.rule(format).headerSnippets) {
const QByteArrayList headerSnippets = node.rule(format).headerSnippets;
for (const QByteArray &snippet : headerSnippets) {
code << replaceParameters(snippet, node, format);
}
}
@ -325,17 +328,18 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
code << QByteArrayLiteral("void main()");
code << QByteArrayLiteral("{");
for (const auto &statement : graph.createStatements(enabledLayers)) {
const auto node = statement.node;
auto line = node.rule(format).substitution;
for (const auto &port : node.ports()) {
const auto portName = port.name;
const auto portDirection = port.direction;
const auto isInput = port.direction == QShaderNodePort::Input;
for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) {
const QShaderNode node = statement.node;
QByteArray line = node.rule(format).substitution;
const QVector<QShaderNodePort> ports = node.ports();
for (const QShaderNodePort &port : ports) {
const QString portName = port.name;
const QShaderNodePort::Direction portDirection = port.direction;
const bool isInput = port.direction == QShaderNodePort::Input;
const auto portIndex = statement.portIndex(portDirection, portName);
const auto variableIndex = isInput ? statement.inputs.at(portIndex)
: statement.outputs.at(portIndex);
const int portIndex = statement.portIndex(portDirection, portName);
const int variableIndex = isInput ? statement.inputs.at(portIndex)
: statement.outputs.at(portIndex);
if (variableIndex < 0)
continue;

View File

@ -82,8 +82,8 @@ namespace
auto statement = QShaderGraph::Statement();
statement.node = node;
const auto ports = node.ports();
for (const auto &port : ports) {
const QVector<QShaderNodePort> ports = node.ports();
for (const QShaderNodePort &port : ports) {
if (port.direction == QShaderNodePort::Input) {
statement.inputs.append(-1);
} else {
@ -99,19 +99,19 @@ namespace
const QUuid &uuid)
{
auto targetStatement = idHash.value(uuid);
for (const auto &edge : edges) {
for (const QShaderGraph::Edge &edge : edges) {
if (edge.targetNodeUuid != uuid)
continue;
const auto sourceStatement = idHash.value(edge.sourceNodeUuid);
const auto sourcePortIndex = sourceStatement.portIndex(QShaderNodePort::Output, edge.sourcePortName);
const auto targetPortIndex = targetStatement.portIndex(QShaderNodePort::Input, edge.targetPortName);
const QShaderGraph::Statement sourceStatement = idHash.value(edge.sourceNodeUuid);
const int sourcePortIndex = sourceStatement.portIndex(QShaderNodePort::Output, edge.sourcePortName);
const int targetPortIndex = targetStatement.portIndex(QShaderNodePort::Input, edge.targetPortName);
if (sourcePortIndex < 0 || targetPortIndex < 0)
continue;
const auto &sourceOutputs = sourceStatement.outputs;
auto &targetInputs = targetStatement.inputs;
const QVector<int> sourceOutputs = sourceStatement.outputs;
QVector<int> &targetInputs = targetStatement.inputs;
targetInputs[targetPortIndex] = sourceOutputs[sourcePortIndex];
}
return targetStatement;
@ -125,9 +125,9 @@ QUuid QShaderGraph::Statement::uuid() const noexcept
int QShaderGraph::Statement::portIndex(QShaderNodePort::Direction direction, const QString &portName) const noexcept
{
const auto ports = node.ports();
const QVector<QShaderNodePort> ports = node.ports();
int index = 0;
for (const auto &port : ports) {
for (const QShaderNodePort &port : ports) {
if (port.name == portName && port.direction == direction)
return index;
else if (port.direction == direction)
@ -180,7 +180,7 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
};
const auto enabledNodes = [this, intersectsEnabledLayers] {
const QVector<QShaderNode> enabledNodes = [this, intersectsEnabledLayers] {
auto res = QVector<QShaderNode>();
std::copy_if(m_nodes.cbegin(), m_nodes.cend(),
std::back_inserter(res),
@ -190,7 +190,7 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
return res;
}();
const auto enabledEdges = [this, intersectsEnabledLayers] {
const QVector<Edge> enabledEdges = [this, intersectsEnabledLayers] {
auto res = QVector<Edge>();
std::copy_if(m_edges.cbegin(), m_edges.cend(),
std::back_inserter(res),
@ -200,18 +200,18 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
return res;
}();
const auto idHash = [enabledNodes] {
const QHash<QUuid, Statement> idHash = [enabledNodes] {
auto nextVarId = 0;
auto res = QHash<QUuid, Statement>();
for (const auto &node : enabledNodes)
for (const QShaderNode &node : enabledNodes)
res.insert(node.uuid(), nodeToStatement(node, nextVarId));
return res;
}();
auto result = QVector<Statement>();
auto currentEdges = enabledEdges;
auto currentUuids = [enabledNodes] {
const auto inputs = copyOutputNodes(enabledNodes);
QVector<Edge> currentEdges = enabledEdges;
QVector<QUuid> currentUuids = [enabledNodes] {
const QVector<QShaderNode> inputs = copyOutputNodes(enabledNodes);
auto res = QVector<QUuid>();
std::transform(inputs.cbegin(), inputs.cend(),
std::back_inserter(res),
@ -226,14 +226,14 @@ QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringLis
// because we want to track the dependencies from the output nodes and not the
// input nodes
while (!currentUuids.isEmpty()) {
const auto uuid = currentUuids.takeFirst();
const QUuid uuid = currentUuids.takeFirst();
result.append(completeStatement(idHash, enabledEdges, uuid));
const auto outgoing = outgoingEdges(currentEdges, uuid);
for (const auto &outgoingEdge : outgoing) {
const QVector<QShaderGraph::Edge> outgoing = outgoingEdges(currentEdges, uuid);
for (const QShaderGraph::Edge &outgoingEdge : outgoing) {
currentEdges.removeAll(outgoingEdge);
const QUuid nextUuid = outgoingEdge.sourceNodeUuid;
const auto incoming = incomingEdges(currentEdges, nextUuid);
const QVector<QShaderGraph::Edge> incoming = incomingEdges(currentEdges, nextUuid);
if (incoming.isEmpty()) {
currentUuids.append(nextUuid);
}

View File

@ -99,7 +99,7 @@ void QShaderGraphLoader::load()
return;
auto error = QJsonParseError();
const auto document = QJsonDocument::fromJson(m_device->readAll(), &error);
const QJsonDocument document = QJsonDocument::fromJson(m_device->readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "Invalid JSON document:" << error.errorString();
@ -113,16 +113,16 @@ void QShaderGraphLoader::load()
return;
}
const auto root = document.object();
const QJsonObject root = document.object();
const auto nodesValue = root.value(QStringLiteral("nodes"));
const QJsonValue nodesValue = root.value(QStringLiteral("nodes"));
if (!nodesValue.isArray()) {
qWarning() << "Invalid nodes property, should be an array";
m_status = Error;
return;
}
const auto edgesValue = root.value(QStringLiteral("edges"));
const QJsonValue edgesValue = root.value(QStringLiteral("edges"));
if (!edgesValue.isArray()) {
qWarning() << "Invalid edges property, should be an array";
m_status = Error;
@ -131,7 +131,7 @@ void QShaderGraphLoader::load()
bool hasError = false;
const auto prototypesValue = root.value(QStringLiteral("prototypes"));
const QJsonValue prototypesValue = root.value(QStringLiteral("prototypes"));
if (!prototypesValue.isUndefined()) {
if (prototypesValue.isObject()) {
QShaderNodesLoader loader;
@ -144,60 +144,60 @@ void QShaderGraphLoader::load()
}
}
const auto nodes = nodesValue.toArray();
for (const auto &nodeValue : nodes) {
const QJsonArray nodes = nodesValue.toArray();
for (const QJsonValue &nodeValue : nodes) {
if (!nodeValue.isObject()) {
qWarning() << "Invalid node found";
hasError = true;
continue;
}
const auto nodeObject = nodeValue.toObject();
const QJsonObject nodeObject = nodeValue.toObject();
const auto uuidString = nodeObject.value(QStringLiteral("uuid")).toString();
const auto uuid = QUuid(uuidString);
const QString uuidString = nodeObject.value(QStringLiteral("uuid")).toString();
const QUuid uuid = QUuid(uuidString);
if (uuid.isNull()) {
qWarning() << "Invalid UUID found in node:" << uuidString;
hasError = true;
continue;
}
const auto type = nodeObject.value(QStringLiteral("type")).toString();
const QString type = nodeObject.value(QStringLiteral("type")).toString();
if (!m_prototypes.contains(type)) {
qWarning() << "Unsupported node type found:" << type;
hasError = true;
continue;
}
const auto layersArray = nodeObject.value(QStringLiteral("layers")).toArray();
const QJsonArray layersArray = nodeObject.value(QStringLiteral("layers")).toArray();
auto layers = QStringList();
for (const auto &layerValue : layersArray) {
for (const QJsonValue &layerValue : layersArray) {
layers.append(layerValue.toString());
}
auto node = m_prototypes.value(type);
QShaderNode node = m_prototypes.value(type);
node.setUuid(uuid);
node.setLayers(layers);
const auto parametersValue = nodeObject.value(QStringLiteral("parameters"));
const QJsonValue parametersValue = nodeObject.value(QStringLiteral("parameters"));
if (parametersValue.isObject()) {
const auto parametersObject = parametersValue.toObject();
for (const auto &parameterName : parametersObject.keys()) {
const auto parameterValue = parametersObject.value(parameterName);
const QJsonObject parametersObject = parametersValue.toObject();
for (const QString &parameterName : parametersObject.keys()) {
const QJsonValue parameterValue = parametersObject.value(parameterName);
if (parameterValue.isObject()) {
const auto parameterObject = parameterValue.toObject();
const auto type = parameterObject.value(QStringLiteral("type")).toString();
const auto typeId = QMetaType::type(type.toUtf8());
const QJsonObject parameterObject = parameterValue.toObject();
const QString type = parameterObject.value(QStringLiteral("type")).toString();
const int typeId = QMetaType::type(type.toUtf8());
const auto value = parameterObject.value(QStringLiteral("value")).toString();
const QString value = parameterObject.value(QStringLiteral("value")).toString();
auto variant = QVariant(value);
if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) {
const auto metaObject = QMetaType::metaObjectForType(typeId);
const auto className = metaObject->className();
const auto enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
const auto metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
const auto enumValue = metaEnum.keyToValue(value.toUtf8());
const QMetaObject *metaObject = QMetaType::metaObjectForType(typeId);
const char *className = metaObject->className();
const QByteArray enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
const QMetaEnum metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
const int enumValue = metaEnum.keyToValue(value.toUtf8());
variant = QVariant(enumValue);
variant.convert(typeId);
} else {
@ -213,39 +213,39 @@ void QShaderGraphLoader::load()
m_graph.addNode(node);
}
const auto edges = edgesValue.toArray();
for (const auto &edgeValue : edges) {
const QJsonArray edges = edgesValue.toArray();
for (const QJsonValue &edgeValue : edges) {
if (!edgeValue.isObject()) {
qWarning() << "Invalid edge found";
hasError = true;
continue;
}
const auto edgeObject = edgeValue.toObject();
const QJsonObject edgeObject = edgeValue.toObject();
const auto sourceUuidString = edgeObject.value(QStringLiteral("sourceUuid")).toString();
const auto sourceUuid = QUuid(sourceUuidString);
const QString sourceUuidString = edgeObject.value(QStringLiteral("sourceUuid")).toString();
const QUuid sourceUuid = QUuid(sourceUuidString);
if (sourceUuid.isNull()) {
qWarning() << "Invalid source UUID found in edge:" << sourceUuidString;
hasError = true;
continue;
}
const auto sourcePort = edgeObject.value(QStringLiteral("sourcePort")).toString();
const QString sourcePort = edgeObject.value(QStringLiteral("sourcePort")).toString();
const auto targetUuidString = edgeObject.value(QStringLiteral("targetUuid")).toString();
const auto targetUuid = QUuid(targetUuidString);
const QString targetUuidString = edgeObject.value(QStringLiteral("targetUuid")).toString();
const QUuid targetUuid = QUuid(targetUuidString);
if (targetUuid.isNull()) {
qWarning() << "Invalid target UUID found in edge:" << targetUuidString;
hasError = true;
continue;
}
const auto targetPort = edgeObject.value(QStringLiteral("targetPort")).toString();
const QString targetPort = edgeObject.value(QStringLiteral("targetPort")).toString();
const auto layersArray = edgeObject.value(QStringLiteral("layers")).toArray();
const QJsonArray layersArray = edgeObject.value(QStringLiteral("layers")).toArray();
auto layers = QStringList();
for (const auto &layerValue : layersArray) {
for (const QJsonValue &layerValue : layersArray) {
layers.append(layerValue.toString());
}

View File

@ -84,7 +84,7 @@ void QShaderNodesLoader::load()
return;
auto error = QJsonParseError();
const auto document = QJsonDocument::fromJson(m_device->readAll(), &error);
const QJsonDocument document = QJsonDocument::fromJson(m_device->readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "Invalid JSON document:" << error.errorString();
@ -98,7 +98,7 @@ void QShaderNodesLoader::load()
return;
}
const auto root = document.object();
const QJsonObject root = document.object();
load(root);
}
@ -106,22 +106,22 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
{
bool hasError = false;
for (const auto &property : prototypesObject.keys()) {
const auto nodeValue = prototypesObject.value(property);
for (const QString &property : prototypesObject.keys()) {
const QJsonValue nodeValue = prototypesObject.value(property);
if (!nodeValue.isObject()) {
qWarning() << "Invalid node found";
hasError = true;
break;
}
const auto nodeObject = nodeValue.toObject();
const QJsonObject nodeObject = nodeValue.toObject();
auto node = QShaderNode();
const auto inputsValue = nodeObject.value(QStringLiteral("inputs"));
const QJsonValue inputsValue = nodeObject.value(QStringLiteral("inputs"));
if (inputsValue.isArray()) {
const auto inputsArray = inputsValue.toArray();
for (const auto &inputValue : inputsArray) {
const QJsonArray inputsArray = inputsValue.toArray();
for (const QJsonValue &inputValue : inputsArray) {
if (!inputValue.isString()) {
qWarning() << "Non-string value in inputs";
hasError = true;
@ -135,10 +135,10 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
}
}
const auto outputsValue = nodeObject.value(QStringLiteral("outputs"));
const QJsonValue outputsValue = nodeObject.value(QStringLiteral("outputs"));
if (outputsValue.isArray()) {
const auto outputsArray = outputsValue.toArray();
for (const auto &outputValue : outputsArray) {
const QJsonArray outputsArray = outputsValue.toArray();
for (const QJsonValue &outputValue : outputsArray) {
if (!outputValue.isString()) {
qWarning() << "Non-string value in outputs";
hasError = true;
@ -152,25 +152,25 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
}
}
const auto parametersValue = nodeObject.value(QStringLiteral("parameters"));
const QJsonValue parametersValue = nodeObject.value(QStringLiteral("parameters"));
if (parametersValue.isObject()) {
const auto parametersObject = parametersValue.toObject();
for (const auto &parameterName : parametersObject.keys()) {
const auto parameterValue = parametersObject.value(parameterName);
const QJsonObject parametersObject = parametersValue.toObject();
for (const QString &parameterName : parametersObject.keys()) {
const QJsonValue parameterValue = parametersObject.value(parameterName);
if (parameterValue.isObject()) {
const auto parameterObject = parameterValue.toObject();
const auto type = parameterObject.value(QStringLiteral("type")).toString();
const auto typeId = QMetaType::type(type.toUtf8());
const QJsonObject parameterObject = parameterValue.toObject();
const QString type = parameterObject.value(QStringLiteral("type")).toString();
const int typeId = QMetaType::type(type.toUtf8());
const auto value = parameterObject.value(QStringLiteral("value")).toString();
const QString value = parameterObject.value(QStringLiteral("value")).toString();
auto variant = QVariant(value);
if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) {
const auto metaObject = QMetaType::metaObjectForType(typeId);
const auto className = metaObject->className();
const auto enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
const auto metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
const auto enumValue = metaEnum.keyToValue(value.toUtf8());
const QMetaObject *metaObject = QMetaType::metaObjectForType(typeId);
const char *className = metaObject->className();
const QByteArray enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
const QMetaEnum metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
const int enumValue = metaEnum.keyToValue(value.toUtf8());
variant = QVariant(enumValue);
variant.convert(typeId);
} else {
@ -183,36 +183,36 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
}
}
const auto rulesValue = nodeObject.value(QStringLiteral("rules"));
const QJsonValue rulesValue = nodeObject.value(QStringLiteral("rules"));
if (rulesValue.isArray()) {
const auto rulesArray = rulesValue.toArray();
for (const auto &ruleValue : rulesArray) {
const QJsonArray rulesArray = rulesValue.toArray();
for (const QJsonValue &ruleValue : rulesArray) {
if (!ruleValue.isObject()) {
qWarning() << "Rules should be objects";
hasError = true;
break;
}
const auto ruleObject = ruleValue.toObject();
const QJsonObject ruleObject = ruleValue.toObject();
const auto formatValue = ruleObject.value(QStringLiteral("format"));
const QJsonValue formatValue = ruleObject.value(QStringLiteral("format"));
if (!formatValue.isObject()) {
qWarning() << "Format is mandatory in rules and should be an object";
hasError = true;
break;
}
const auto formatObject = formatValue.toObject();
const QJsonObject formatObject = formatValue.toObject();
auto format = QShaderFormat();
const auto apiValue = formatObject.value(QStringLiteral("api"));
const QJsonValue apiValue = formatObject.value(QStringLiteral("api"));
if (!apiValue.isString()) {
qWarning() << "Format API must be a string";
hasError = true;
break;
}
const auto api = apiValue.toString();
const QString api = apiValue.toString();
format.setApi(api == QStringLiteral("OpenGLES") ? QShaderFormat::OpenGLES
: api == QStringLiteral("OpenGLNoProfile") ? QShaderFormat::OpenGLNoProfile
: api == QStringLiteral("OpenGLCoreProfile") ? QShaderFormat::OpenGLCoreProfile
@ -224,8 +224,8 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
break;
}
const auto majorValue = formatObject.value(QStringLiteral("major"));
const auto minorValue = formatObject.value(QStringLiteral("minor"));
const QJsonValue majorValue = formatObject.value(QStringLiteral("major"));
const QJsonValue minorValue = formatObject.value(QStringLiteral("minor"));
if (!majorValue.isDouble() || !minorValue.isDouble()) {
qWarning() << "Format major and minor version must be values";
hasError = true;
@ -233,28 +233,28 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
}
format.setVersion(QVersionNumber(majorValue.toInt(), minorValue.toInt()));
const auto extensionsValue = formatObject.value(QStringLiteral("extensions"));
const auto extensionsArray = extensionsValue.toArray();
const QJsonValue extensionsValue = formatObject.value(QStringLiteral("extensions"));
const QJsonArray extensionsArray = extensionsValue.toArray();
auto extensions = QStringList();
std::transform(extensionsArray.constBegin(), extensionsArray.constEnd(),
std::back_inserter(extensions),
[] (const QJsonValue &extensionValue) { return extensionValue.toString(); });
format.setExtensions(extensions);
const auto vendor = formatObject.value(QStringLiteral("vendor")).toString();
const QString vendor = formatObject.value(QStringLiteral("vendor")).toString();
format.setVendor(vendor);
const auto substitutionValue = ruleObject.value(QStringLiteral("substitution"));
const QJsonValue substitutionValue = ruleObject.value(QStringLiteral("substitution"));
if (!substitutionValue.isString()) {
qWarning() << "Substitution needs to be a string";
hasError = true;
break;
}
const auto substitution = substitutionValue.toString().toUtf8();
const QByteArray substitution = substitutionValue.toString().toUtf8();
const auto snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));
const auto snippetsArray = snippetsValue.toArray();
const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));
const QJsonArray snippetsArray = snippetsValue.toArray();
auto snippets = QByteArrayList();
std::transform(snippetsArray.constBegin(), snippetsArray.constEnd(),
std::back_inserter(snippets),

View File

@ -66,6 +66,11 @@ void QEglFSVivWaylandIntegration::platformInit()
mScreenSize.setWidth(width);
}
void QEglFSVivWaylandIntegration::platformDestroy()
{
wl_display_destroy(mWaylandDisplay);
}
QSize QEglFSVivWaylandIntegration::screenSize() const
{
return mScreenSize;

View File

@ -49,6 +49,7 @@ class QEglFSVivWaylandIntegration : public QEglFSDeviceIntegration
{
public:
void platformInit() override;
void platformDestroy() override;
QSize screenSize() const override;
EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override;
void destroyNativeWindow(EGLNativeWindowType window) override;

View File

@ -1453,26 +1453,41 @@ static QString createTemporaryItemCopy(QWindowsShellItem &qItem, QString *errorM
return result;
}
static QUrl itemToDialogUrl(QWindowsShellItem &qItem, QString *errorMessage)
{
QUrl url = qItem.url();
if (url.isLocalFile() || url.scheme().startsWith(QLatin1String("http")))
return url;
const QString path = qItem.path();
if (path.isEmpty() && !qItem.isDir() && qItem.canStream()) {
const QString temporaryCopy = createTemporaryItemCopy(qItem, errorMessage);
if (temporaryCopy.isEmpty()) {
QDebug(errorMessage).noquote() << "Unable to create a local copy of"
<< qItem << ": " << errorMessage;
return QUrl();
}
return QUrl::fromLocalFile(temporaryCopy);
}
if (!url.isValid())
QDebug(errorMessage).noquote() << "Invalid URL obtained from" << qItem;
return url;
}
QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const
{
QList<QUrl> result;
IShellItemArray *items = nullptr;
if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) {
QString errorMessage;
for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) {
QWindowsShellItem qItem(item);
const QString path = qItem.path();
if (path.isEmpty() && !qItem.isDir()) {
QString errorMessage;
const QString temporaryCopy = createTemporaryItemCopy(qItem, &errorMessage);
if (temporaryCopy.isEmpty()) {
qWarning().noquote() << "Unable to create a local copy of" << qItem
<< ": " << errorMessage;
} else {
result.append(QUrl::fromLocalFile(temporaryCopy));
}
} else {
result.append(qItem.url());
const QUrl url = itemToDialogUrl(qItem, &errorMessage);
if (!url.isValid()) {
qWarning("%s", qPrintable(errorMessage));
result.clear();
break;
}
result.append(url);
}
}
return result;

View File

@ -1105,16 +1105,16 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
if (mode == property(PPK_Duplex).toInt() || !d->m_printDevice.supportedDuplexModes().contains(mode))
break;
switch (mode) {
case QPrinter::DuplexNone:
case QPrint::DuplexNone:
d->devMode->dmDuplex = DMDUP_SIMPLEX;
break;
case QPrinter::DuplexAuto:
case QPrint::DuplexAuto:
d->devMode->dmDuplex = d->m_pageLayout.orientation() == QPageLayout::Landscape ? DMDUP_HORIZONTAL : DMDUP_VERTICAL;
break;
case QPrinter::DuplexLongSide:
case QPrint::DuplexLongSide:
d->devMode->dmDuplex = DMDUP_VERTICAL;
break;
case QPrinter::DuplexShortSide:
case QPrint::DuplexShortSide:
d->devMode->dmDuplex = DMDUP_HORIZONTAL;
break;
default:

View File

@ -1581,29 +1581,6 @@ void QTableView::paintEvent(QPaintEvent *event)
colp += columnWidth(col) - gridSize;
painter.drawLine(colp, dirtyArea.top(), colp, dirtyArea.bottom());
}
//draw the top & left grid lines if the headers are not visible.
//We do update this line when subsequent scroll happen (see scrollContentsBy)
if (horizontalHeader->isHidden() && top == 0) {
const int row = verticalHeader->logicalIndex(top);
if (!verticalHeader->isSectionHidden(row)) {
const int rowY = rowViewportPosition(row) + offset.y();
if (rowY == dirtyArea.top())
painter.drawLine(dirtyArea.left(), rowY, dirtyArea.right(), rowY);
}
}
if (verticalHeader->isHidden() && left == 0) {
const int col = horizontalHeader->logicalIndex(left);
if (!horizontalHeader->isSectionHidden(col)) {
int colX = columnViewportPosition(col) + offset.x();
if (!isLeftToRight())
colX += columnWidth(left) - 1;
if (isLeftToRight() && colX == dirtyArea.left())
painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom());
if (!isLeftToRight() && colX == dirtyArea.right())
painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom());
}
}
painter.setPen(old);
}
}
@ -1878,7 +1855,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi
visualColumn = d->nextActiveVisualColumn(visualRow, right, -1,
QTableViewPrivate::SearchDirection::Decreasing);
if (modifiers & Qt::ControlModifier)
visualRow = d->nextActiveVisualRow(bottom, current.column(), -1,
visualRow = d->nextActiveVisualRow(bottom, visualColumn, -1,
QTableViewPrivate::SearchDirection::Decreasing);
break;
case MovePageUp: {

View File

@ -46,6 +46,7 @@
#include "qstyleoption.h"
#include "private/qstyle_p.h"
#include "private/qguiapplication_p.h"
#include <qpa/qplatformtheme.h>
#ifndef QT_NO_DEBUG
#include "qdebug.h"
#endif
@ -2447,6 +2448,13 @@ void QStyle::setProxy(QStyle *style)
d->proxyStyle = style;
}
//Windows and KDE allow menus to cover the taskbar, while GNOME and macOS don't
bool QStylePrivate::useFullScreenForPopup()
{
auto theme = QGuiApplicationPrivate::platformTheme();
return theme && theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool();
}
QT_END_NAMESPACE
#include "moc_qstyle.cpp"

View File

@ -67,6 +67,9 @@ class QStylePrivate: public QObjectPrivate
public:
inline QStylePrivate()
: layoutSpacingIndex(-1), proxyStyle(nullptr) {}
static bool useFullScreenForPopup();
mutable int layoutSpacingIndex;
QStyle *proxyStyle;
};

View File

@ -80,6 +80,7 @@
#if QT_CONFIG(effects)
# include <private/qeffects_p.h>
#endif
#include <private/qstyle_p.h>
#ifndef QT_NO_ACCESSIBILITY
#include "qaccessible.h"
#endif
@ -261,16 +262,11 @@ void QComboBoxPrivate::_q_modelDestroyed()
model = QAbstractItemModelPrivate::staticEmptyModel();
}
//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
QRect QComboBoxPrivate::popupGeometry(int screen) const
{
bool useFullScreenForPopupMenu = false;
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
useFullScreenForPopupMenu = theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool();
return useFullScreenForPopupMenu ?
QDesktopWidgetPrivate::screenGeometry(screen) :
QDesktopWidgetPrivate::availableGeometry(screen);
return QStylePrivate::useFullScreenForPopup()
? QDesktopWidgetPrivate::screenGeometry(screen)
: QDesktopWidgetPrivate::availableGeometry(screen);
}
bool QComboBoxPrivate::updateHoverControl(const QPoint &pos)

View File

@ -78,6 +78,7 @@
#include <private/qguiapplication_p.h>
#include <qpa/qplatformtheme.h>
#include <private/qdesktopwidget_p.h>
#include <private/qstyle_p.h>
QT_BEGIN_NAMESPACE
@ -307,29 +308,26 @@ int QMenuPrivate::scrollerHeight() const
return qMax(QApplication::globalStrut().height(), q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q));
}
//Windows and KDE allow menus to cover the taskbar, while GNOME and Mac don't
// Windows and KDE allow menus to cover the taskbar, while GNOME and macOS
// don't. Torn-off menus are again different
inline bool QMenuPrivate::useFullScreenForPopup() const
{
return !tornoff && QStylePrivate::useFullScreenForPopup();
}
QRect QMenuPrivate::popupGeometry() const
{
Q_Q(const QMenu);
if (!tornoff && // Torn-off menus are different
QGuiApplicationPrivate::platformTheme() &&
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool()) {
return QDesktopWidgetPrivate::screenGeometry(q);
} else {
return QDesktopWidgetPrivate::availableGeometry(q);
}
return useFullScreenForPopup()
? QDesktopWidgetPrivate::screenGeometry(q)
: QDesktopWidgetPrivate::availableGeometry(q);
}
//Windows and KDE allow menus to cover the taskbar, while GNOME and Mac don't
QRect QMenuPrivate::popupGeometry(int screen) const
{
if (!tornoff && // Torn-off menus are different
QGuiApplicationPrivate::platformTheme() &&
QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool()) {
return QDesktopWidgetPrivate::screenGeometry(screen);
} else {
return QDesktopWidgetPrivate::availableGeometry(screen);
}
return useFullScreenForPopup()
? QDesktopWidgetPrivate::screenGeometry(screen)
: QDesktopWidgetPrivate::availableGeometry(screen);
}
QVector<QPointer<QWidget> > QMenuPrivate::calcCausedStack() const

View File

@ -349,6 +349,7 @@ public:
void updateActionRects(const QRect &screen) const;
QRect popupGeometry() const;
QRect popupGeometry(int screen) const;
bool useFullScreenForPopup() const;
int getLastVisibleAction() const;
//selection

View File

@ -47,6 +47,7 @@ class tst_QUrl : public QObject
private slots:
void initTestCase();
void cleanupTestCase();
void effectiveTLDs_data();
void effectiveTLDs();
void getSetCheck();
@ -188,6 +189,7 @@ private slots:
private:
void testThreadingHelper();
const QString m_currentPath = QDir::currentPath();
QTemporaryDir m_tempDir;
};
@ -196,6 +198,12 @@ void tst_QUrl::initTestCase()
QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString()));
}
void tst_QUrl::cleanupTestCase()
{
// Restore working directory changed in fromUserInputWithCwd()
QDir::setCurrent(m_currentPath);
}
// Testing get/set functions
void tst_QUrl::getSetCheck()
{

View File

@ -40,6 +40,13 @@ struct MyStruct
int i;
};
class MyGadget
{
Q_GADGET
public:
Q_INVOKABLE MyGadget() {}
};
namespace MyNamespace {
// Used in tst_QMetaObject::checkScope
class MyClass : public QObject
@ -1208,6 +1215,12 @@ void tst_QMetaObject::invokeMetaConstructor()
QCOMPARE(obj2->parent(), (QObject*)&obj);
QVERIFY(qobject_cast<NamespaceWithConstructibleClass::ConstructibleClass*>(obj2) != 0);
}
// gadget shouldn't return a valid pointer
{
QCOMPARE(MyGadget::staticMetaObject.constructorCount(), 1);
QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject");
QVERIFY(!MyGadget::staticMetaObject.newInstance());
}
}
void tst_QMetaObject::invokeTypedefTypes()

View File

@ -76,11 +76,15 @@ void fill_push_header(const HttpHeader &originalRequest, HttpHeader &promisedReq
}
Http2Server::Http2Server(bool h2c, const Http2::RawSettings &ss, const Http2::RawSettings &cs)
: serverSettings(ss),
expectedClientSettings(cs),
clearTextHTTP2(h2c)
Http2Server::Http2Server(H2Type type, const Http2::RawSettings &ss, const Http2::RawSettings &cs)
: connectionType(type),
serverSettings(ss),
expectedClientSettings(cs)
{
#if !QT_CONFIG(ssl)
Q_ASSERT(type != H2Type::h2Alpn && type != H2Type::h2Direct);
#endif
responseBody = "<html>\n"
"<head>\n"
"<title>Sample \"Hello, World\" Application</title>\n"
@ -129,15 +133,15 @@ void Http2Server::redirectOpenStream(quint16 port)
targetPort = port;
}
bool Http2Server::isClearText() const
{
return connectionType == H2Type::h2c || connectionType == H2Type::h2cDirect;
}
void Http2Server::startServer()
{
#ifdef QT_NO_SSL
// Let the test fail with timeout.
if (!clearTextHTTP2)
return;
#endif
if (listen()) {
if (clearTextHTTP2)
if (isClearText())
authority = QStringLiteral("127.0.0.1:%1").arg(serverPort()).toLatin1();
emit serverStarted(serverPort());
}
@ -146,7 +150,7 @@ void Http2Server::startServer()
bool Http2Server::sendProtocolSwitchReply()
{
Q_ASSERT(socket);
Q_ASSERT(clearTextHTTP2 && upgradeProtocol);
Q_ASSERT(connectionType == H2Type::h2c);
// The first and the last HTTP/1.1 response we send:
const char response[] = "HTTP/1.1 101 Switching Protocols\r\n"
"Connection: Upgrade\r\n"
@ -262,25 +266,28 @@ void Http2Server::sendWINDOW_UPDATE(quint32 streamID, quint32 delta)
void Http2Server::incomingConnection(qintptr socketDescriptor)
{
if (clearTextHTTP2) {
if (isClearText()) {
socket.reset(new QTcpSocket);
const bool set = socket->setSocketDescriptor(socketDescriptor);
Q_ASSERT(set);
// Stop listening:
close();
upgradeProtocol = true;
upgradeProtocol = connectionType == H2Type::h2c;
QMetaObject::invokeMethod(this, "connectionEstablished",
Qt::QueuedConnection);
} else {
#ifndef QT_NO_SSL
#if QT_CONFIG(ssl)
socket.reset(new QSslSocket);
QSslSocket *sslSocket = static_cast<QSslSocket *>(socket.data());
// Add HTTP2 as supported protocol:
auto conf = QSslConfiguration::defaultConfiguration();
auto protos = conf.allowedNextProtocols();
protos.prepend(QSslConfiguration::ALPNProtocolHTTP2);
conf.setAllowedNextProtocols(protos);
sslSocket->setSslConfiguration(conf);
if (connectionType == H2Type::h2Alpn) {
// Add HTTP2 as supported protocol:
auto conf = QSslConfiguration::defaultConfiguration();
auto protos = conf.allowedNextProtocols();
protos.prepend(QSslConfiguration::ALPNProtocolHTTP2);
conf.setAllowedNextProtocols(protos);
sslSocket->setSslConfiguration(conf);
}
// SSL-related setup ...
sslSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
sslSocket->setProtocol(QSsl::TlsV1_2OrLater);
@ -299,7 +306,7 @@ void Http2Server::incomingConnection(qintptr socketDescriptor)
connect(sslSocket, SIGNAL(encrypted()), this, SLOT(connectionEstablished()));
sslSocket->startServerEncryption();
#else
Q_UNREACHABLE();
Q_ASSERT(0);
#endif
}
}
@ -377,7 +384,7 @@ void Http2Server::connectionEstablished()
{
using namespace Http2;
if (testingGOAWAY && !clearTextHTTP2)
if (testingGOAWAY && !isClearText())
return triggerGOAWAYEmulation();
// For clearTextHTTP2 we first have to respond with 'protocol switch'
@ -392,7 +399,7 @@ void Http2Server::connectionEstablished()
waitingClientSettings = false;
settingsSent = false;
if (clearTextHTTP2) {
if (connectionType == H2Type::h2c) {
requestLine.clear();
// Now we have to handle HTTP/1.1 request. We use Get/Post in our test,
// so set requestType to something unsupported:
@ -818,7 +825,7 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody)
Q_ASSERT(targetPort);
header.push_back({":status", "308"});
const QString url("%1://localhost:%2/");
header.push_back({"location", url.arg(clearTextHTTP2 ? QStringLiteral("http") : QStringLiteral("https"),
header.push_back({"location", url.arg(isClearText() ? QStringLiteral("http") : QStringLiteral("https"),
QString::number(targetPort)).toLatin1()});
} else {

View File

@ -62,21 +62,32 @@ public:
Q_DECLARE_PRIVATE(Http11Reply)
};
enum class H2Type {
h2Alpn, // Secure connection, ALPN to negotiate h2.
h2c, // Clear text with protocol upgrade.
h2Direct, // Secure connection, ALPN not supported.
h2cDirect, // Clear text direct
};
class Http2Server : public QTcpServer
{
Q_OBJECT
public:
Http2Server(bool clearText, const Http2::RawSettings &serverSettings,
Http2Server(H2Type type, const Http2::RawSettings &serverSettings,
const Http2::RawSettings &clientSettings);
~Http2Server();
// To be called before server started:
void enablePushPromise(bool enabled, const QByteArray &path = QByteArray());
void setResponseBody(const QByteArray &body);
void emulateGOAWAY(int timeout);
void redirectOpenStream(quint16 targetPort);
bool isClearText() const;
// Invokables, since we can call them from the main thread,
// but server (can) work on its own thread.
Q_INVOKABLE void startServer();
@ -129,6 +140,7 @@ private:
QScopedPointer<QAbstractSocket> socket;
H2Type connectionType = H2Type::h2Alpn;
// Connection preface:
bool waitingClientPreface = false;
bool waitingClientSettings = false;
@ -170,7 +182,6 @@ private:
quint32 streamRecvWindowSize = Http2::defaultSessionWindowSize;
QByteArray responseBody;
bool clearTextHTTP2 = false;
bool pushPromiseEnabled = false;
quint32 lastPromisedStream = 0;
QByteArray pushPath;

View File

@ -60,6 +60,9 @@ const bool clearTextHTTP2 = false;
const bool clearTextHTTP2 = true;
#endif
Q_DECLARE_METATYPE(H2Type)
Q_DECLARE_METATYPE(QNetworkRequest::Attribute)
QT_BEGIN_NAMESPACE
class tst_Http2 : public QObject
@ -70,6 +73,7 @@ public:
~tst_Http2();
private slots:
// Tests:
void singleRequest_data();
void singleRequest();
void multipleRequests();
void flowControlClientSide();
@ -101,13 +105,13 @@ private:
// small payload.
void runEventLoop(int ms = 5000);
void stopEventLoop();
Http2Server *newServer(const Http2::RawSettings &serverSettings,
Http2Server *newServer(const Http2::RawSettings &serverSettings, H2Type connectionType,
const Http2::ProtocolParameters &clientSettings = {});
// Send a get or post request, depending on a payload (empty or not).
void sendRequest(int streamNumber,
QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority,
const QByteArray &payload = QByteArray());
QUrl requestUrl() const;
QUrl requestUrl(H2Type connnectionType) const;
quint16 serverPort = 0;
QThread *workerThread = nullptr;
@ -144,6 +148,11 @@ struct ServerDeleter
using ServerPtr = QScopedPointer<Http2Server, ServerDeleter>;
H2Type defaultConnectionType()
{
return clearTextHTTP2 ? H2Type::h2c : H2Type::h2Alpn;
}
} // unnamed namespace
tst_Http2::tst_Http2()
@ -165,25 +174,59 @@ tst_Http2::~tst_Http2()
}
}
void tst_Http2::singleRequest_data()
{
QTest::addColumn<QNetworkRequest::Attribute>("h2Attribute");
QTest::addColumn<H2Type>("connectionType");
// 'Clear text' that should always work, either via the protocol upgrade
// or as direct.
QTest::addRow("h2c-upgrade") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2c;
QTest::addRow("h2c-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2cDirect;
if (!clearTextHTTP2) {
// Qt with TLS where TLS-backend supports ALPN.
QTest::addRow("h2-ALPN") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2Alpn;
}
#if QT_CONFIG(ssl)
QTest::addRow("h2-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2Direct;
#endif
}
void tst_Http2::singleRequest()
{
clearHTTP2State();
#if QT_CONFIG(securetransport)
// Normally on macOS we use plain text only for SecureTransport
// does not support ALPN on the server side. With 'direct encrytped'
// we have to use TLS sockets (== private key) and thus suppress a
// keychain UI asking for permission to use a private key.
// Our CI has this, but somebody testing locally - will have a problem.
qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1"));
auto envRollback = qScopeGuard([](){
qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN");
});
#endif
serverPort = 0;
nRequests = 1;
ServerPtr srv(newServer(defaultServerSettings));
QFETCH(const H2Type, connectionType);
ServerPtr srv(newServer(defaultServerSettings, connectionType));
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
runEventLoop();
QVERIFY(serverPort != 0);
auto url = requestUrl();
auto url = requestUrl(connectionType);
url.setPath("/index.html");
QNetworkRequest request(url);
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
QFETCH(const QNetworkRequest::Attribute, h2Attribute);
request.setAttribute(h2Attribute, QVariant(true));
auto reply = manager.get(request);
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
@ -208,7 +251,7 @@ void tst_Http2::multipleRequests()
serverPort = 0;
nRequests = 10;
ServerPtr srv(newServer(defaultServerSettings));
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType()));
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
@ -259,7 +302,7 @@ void tst_Http2::flowControlClientSide()
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}};
ServerPtr srv(newServer(serverSettings, params));
ServerPtr srv(newServer(serverSettings, defaultConnectionType(), params));
const QByteArray respond(int(Http2::defaultSessionWindowSize * 10), 'x');
@ -301,7 +344,7 @@ void tst_Http2::flowControlServerSide()
const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 7}};
ServerPtr srv(newServer(serverSettings));
ServerPtr srv(newServer(serverSettings, defaultConnectionType()));
const QByteArray payload(int(Http2::defaultSessionWindowSize * 500), 'x');
@ -336,7 +379,7 @@ void tst_Http2::pushPromise()
params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1;
manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params));
ServerPtr srv(newServer(defaultServerSettings, params));
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), params));
srv->enablePushPromise(true, QByteArray("/script.js"));
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
@ -344,7 +387,7 @@ void tst_Http2::pushPromise()
QVERIFY(serverPort != 0);
auto url = requestUrl();
auto url = requestUrl(defaultConnectionType());
url.setPath("/index.html");
QNetworkRequest request(url);
@ -410,14 +453,14 @@ void tst_Http2::goaway()
serverPort = 0;
nRequests = 3;
ServerPtr srv(newServer(defaultServerSettings));
ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType()));
srv->emulateGOAWAY(responseTimeoutMS);
QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
runEventLoop();
QVERIFY(serverPort != 0);
auto url = requestUrl();
auto url = requestUrl(defaultConnectionType());
// We have to store these replies, so that we can check errors later.
std::vector<QNetworkReply *> replies(nRequests);
for (int i = 0; i < nRequests; ++i) {
@ -457,7 +500,7 @@ void tst_Http2::earlyResponse()
serverPort = 0;
nRequests = 1;
ServerPtr targetServer(newServer(defaultServerSettings));
ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType()));
QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection);
runEventLoop();
@ -467,7 +510,7 @@ void tst_Http2::earlyResponse()
const quint16 targetPort = serverPort;
serverPort = 0;
ServerPtr redirector(newServer(defaultServerSettings));
ServerPtr redirector(newServer(defaultServerSettings, defaultConnectionType()));
redirector->redirectOpenStream(targetPort);
QMetaObject::invokeMethod(redirector.data(), "startServer", Qt::QueuedConnection);
@ -507,11 +550,11 @@ void tst_Http2::stopEventLoop()
eventLoop.exitLoop();
}
Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings,
Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, H2Type connectionType,
const Http2::ProtocolParameters &clientSettings)
{
using namespace Http2;
auto srv = new Http2Server(clearTextHTTP2, serverSettings,
auto srv = new Http2Server(connectionType, serverSettings,
clientSettings.settingsFrameData);
using Srv = Http2Server;
@ -536,7 +579,7 @@ void tst_Http2::sendRequest(int streamNumber,
QNetworkRequest::Priority priority,
const QByteArray &payload)
{
auto url = requestUrl();
auto url = requestUrl(defaultConnectionType());
url.setPath(QString("/stream%1.html").arg(streamNumber));
QNetworkRequest request(url);
@ -555,10 +598,24 @@ void tst_Http2::sendRequest(int streamNumber,
connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
}
QUrl tst_Http2::requestUrl() const
QUrl tst_Http2::requestUrl(H2Type connectionType) const
{
#if !QT_CONFIG(ssl)
Q_ASSERT(connectionType != H2Type::h2Alpn && connectionType != H2Type::h2Direct);
#endif
static auto url = QUrl(QLatin1String(clearTextHTTP2 ? "http://127.0.0.1" : "https://127.0.0.1"));
url.setPort(serverPort);
// Clear text may mean no-TLS-at-all or crappy-TLS-without-ALPN.
switch (connectionType) {
case H2Type::h2Alpn:
case H2Type::h2Direct:
url.setScheme(QStringLiteral("https"));
break;
case H2Type::h2c:
case H2Type::h2cDirect:
url.setScheme(QStringLiteral("http"));
break;
}
return url;
}