Merge "Merge remote-tracking branch 'origin/5.6' into 5.7" into refs/staging/5.7

This commit is contained in:
Edward Welbourne 2016-07-19 10:46:15 +00:00 committed by The Qt Project
commit b3f260236a
63 changed files with 721 additions and 268 deletions

View File

@ -494,7 +494,7 @@ void PathStrokeRenderer::initializePoints()
m_vectors.clear();
QMatrix m;
qreal rot = 360 / count;
qreal rot = 360.0 / count;
QPointF center(width() / 2, height() / 2);
QMatrix vm;
vm.shear(2, -1);

View File

@ -31,6 +31,7 @@ QMAKE_LIBS_THREAD =
QMAKE_DSYMUTIL = dsymutil
QMAKE_STRIP = strip
QMAKE_STRIPFLAGS_LIB += -S -x
QMAKE_AR = ar cq
QMAKE_RANLIB = ranlib -s

View File

@ -1,8 +1,7 @@
isEmpty(COPIES): return()
contains(TEMPLATE, .*subdirs): error("COPIES does not work with TEMPLATE=subdirs")
build_pass:build_all: \
debug_and_release:debug {
build_pass:build_all:!isEqual(BUILD_PASS, $$first(BUILDS)) {
# Avoid that multiple build passes race with each other.
# This will fail to copy anything if the user explicitly invokes
# only the non-primary build. This is unfixable, as at qmake time

View File

@ -156,7 +156,7 @@ for(ever) {
!isEmpty(var_sfx): break()
var_sfx = _PRIVATE
}
!isEmpty(using_privates):!no_private_qt_headers_warning:if(!debug_and_release|!build_pass) {
!isEmpty(using_privates):!no_private_qt_headers_warning:!build_pass {
message("This project is using private headers and will therefore be tied to this specific Qt module build version.")
message("Running this project against other versions of the Qt modules may crash at any arbitrary point.")
message("This is not a bug, but a result of using Qt internals. You have been warned!")

View File

@ -30,7 +30,7 @@ contains(TEMPLATE, subdirs) {
for(inst, DOC_TARGETS): \
prepareRecursiveTarget($$inst)
} else {
debug_and_release:!build_pass {
!isEmpty(BUILDS):!build_pass {
sub = $$first(BUILDS)
for(inst, DOC_TARGETS) {
$${inst}.CONFIG = recursive

View File

@ -259,7 +259,10 @@ defineReplace(pkgConfigExecutable) {
}
defineTest(packagesExist) {
contains(QT_CONFIG, no-pkg-config):return(false)
contains(QT_CONFIG, no-pkg-config) {
warning("pkg-config disabled, can't check package existence")
return(false)
}
# this can't be done in global scope here because qt_functions is loaded
# before the .pro is parsed, so if the .pro set PKG_CONFIG, we wouldn't know it

View File

@ -35,7 +35,7 @@ for(resource, RESOURCES) {
resource_file = $$RCC_DIR/qmake_$${resource}.qrc
!debug_and_release|build_pass {
isEmpty(BUILDS)|build_pass {
# Collection of files, generate qrc file
prefix = $$eval($${resource}.prefix)
isEmpty(prefix): \

View File

@ -17,9 +17,26 @@ QMAKE_LIBDIR_X11 = /usr/X11R6/lib
QMAKE_INCDIR_OPENGL = /usr/X11R6/include
QMAKE_LIBDIR_OPENGL = /usr/X11R6/lib
QMAKE_RPATHDIR += $$QMAKE_LIBDIR_X11
include(../common/gcc-base-unix.conf)
include(../common/g++-unix.conf)
# System compiler is gcc 4.2.1 up to OpenBSD 6.0.
# For proper C++11 support, we need to use a newer gcc from ports/packages,
# where compiler commands are renamed to egcc/eg++. Therefore, redefine
# mkspecs/common/g++-base.conf compiler commands
QMAKE_CC = egcc
QMAKE_LINK_C = $$QMAKE_CC
QMAKE_LINK_C_SHLIB = $$QMAKE_CC
QMAKE_CXX = eg++
QMAKE_LINK = $$QMAKE_CXX
QMAKE_LINK_SHLIB = $$QMAKE_CXX
# Reset g++-unix.conf's NOUNDEF flags as OpenBSD libc can't handle environ
QMAKE_LFLAGS_NOUNDEF =

View File

@ -1037,7 +1037,11 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand(
QString rstr = QDir::cleanPath(
QDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory())
.absoluteFilePath(args.at(0).toQString(m_tmp1)));
ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0)));
ret << (rstr.isSharedWith(m_tmp1)
? args.at(0)
: args.count() > 1 && rstr.isSharedWith(m_tmp2)
? args.at(1)
: ProString(rstr).setSource(args.at(0)));
}
break;
case E_RELATIVE_PATH:
@ -1211,7 +1215,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
return ReturnFalse;
case T_REQUIRES:
#ifdef PROEVALUATOR_FULL
checkRequirements(args);
if (checkRequirements(args) == ReturnError)
return ReturnError;
#endif
return ReturnFalse; // Another qmake breakage
case T_EVAL: {
@ -1232,8 +1237,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional(
evalError(fL1S("if(condition) requires one argument."));
return ReturnFalse;
}
return returnBool(evaluateConditional(args.at(0).toQString(),
m_current.pro->fileName(), m_current.line));
return evaluateConditional(args.at(0).toQString(),
m_current.pro->fileName(), m_current.line);
}
case T_CONFIG: {
if (args.count() < 1 || args.count() > 2) {

View File

@ -405,7 +405,7 @@ static ALWAYS_INLINE void addStrList(
}
}
void QMakeEvaluator::evaluateExpression(
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpression(
const ushort *&tokPtr, ProStringList *ret, bool joined)
{
debugMsg(2, joined ? "evaluating joined expression" : "evaluating expression");
@ -455,12 +455,15 @@ void QMakeEvaluator::evaluateExpression(
case TokFuncName: {
const ProKey &func = pro->getHashStr(tokPtr);
debugMsg(2, "function %s", dbgKey(func));
addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined);
ProStringList val;
if (evaluateExpandFunction(func, tokPtr, &val) == ReturnError)
return ReturnError;
addStrList(val, tok, ret, pending, joined);
break; }
default:
debugMsg(2, "evaluated expression => %s", dbgStrList(*ret));
tokPtr--;
return;
return ReturnTrue;
}
}
}
@ -532,7 +535,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
case TokAppendUnique:
case TokRemove:
case TokReplace:
visitProVariable(tok, curr, tokPtr);
ret = visitProVariable(tok, curr, tokPtr);
if (ret == ReturnError)
break;
curr.clear();
continue;
case TokBranch:
@ -692,9 +697,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock(
continue;
default: {
const ushort *oTokPtr = --tokPtr;
evaluateExpression(tokPtr, &curr, false);
if (tokPtr != oTokPtr)
continue;
ret = evaluateExpression(tokPtr, &curr, false);
if (ret == ReturnError || tokPtr != oTokPtr)
break;
}
Q_ASSERT_X(false, "visitProBlock", "unexpected item type");
continue;
@ -727,7 +732,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
int index = 0;
ProKey variable;
ProStringList oldVarVal;
ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0);
ProStringList it_list_out;
if (expandVariableReferences(exprPtr, 0, &it_list_out, true) == ReturnError)
return ReturnError;
ProString it_list = it_list_out.at(0);
if (_variable.isEmpty()) {
if (it_list != statics.strever) {
evalError(fL1S("Invalid loop expression."));
@ -826,7 +834,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop(
return ret;
}
void QMakeEvaluator::visitProVariable(
QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable(
ushort tok, const ProStringList &curr, const ushort *&tokPtr)
{
int sizeHint = *tokPtr++;
@ -835,24 +843,26 @@ void QMakeEvaluator::visitProVariable(
skipExpression(tokPtr);
if (!m_cumulative || !curr.isEmpty())
evalError(fL1S("Left hand side of assignment must expand to exactly one word."));
return;
return ReturnTrue;
}
const ProKey &varName = map(curr.first());
if (tok == TokReplace) { // ~=
// DEFINES ~= s/a/b/?[gqi]
const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true);
ProStringList varVal;
if (expandVariableReferences(tokPtr, sizeHint, &varVal, true) == ReturnError)
return ReturnError;
const QString &val = varVal.at(0).toQString(m_tmp1);
if (val.length() < 4 || val.at(0) != QLatin1Char('s')) {
evalError(fL1S("The ~= operator can handle only the s/// function."));
return;
return ReturnTrue;
}
QChar sep = val.at(1);
QStringList func = val.split(sep);
if (func.count() < 3 || func.count() > 4) {
evalError(fL1S("The s/// function expects 3 or 4 arguments."));
return;
return ReturnTrue;
}
bool global = false, quote = false, case_sense = false;
@ -873,7 +883,9 @@ void QMakeEvaluator::visitProVariable(
replaceInList(&valuesRef(varName), regexp, replace, global, m_tmp2);
debugMsg(2, "replaced %s with %s", dbgQStr(pattern), dbgQStr(replace));
} else {
ProStringList varVal = expandVariableReferences(tokPtr, sizeHint);
ProStringList varVal;
if (expandVariableReferences(tokPtr, sizeHint, &varVal, false) == ReturnError)
return ReturnError;
switch (tok) {
default: // whatever - cannot happen
case TokAssign: // =
@ -919,8 +931,10 @@ void QMakeEvaluator::visitProVariable(
}
#ifdef PROEVALUATOR_FULL
else if (varName == statics.strREQUIRES)
checkRequirements(values(varName));
return checkRequirements(values(varName));
#endif
return ReturnTrue;
}
void QMakeEvaluator::setTemplate()
@ -1612,18 +1626,18 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex)
return false;
}
ProStringList QMakeEvaluator::expandVariableReferences(
const ushort *&tokPtr, int sizeHint, bool joined)
QMakeEvaluator::VisitReturn QMakeEvaluator::expandVariableReferences(
const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined)
{
ProStringList ret;
ret.reserve(sizeHint);
ret->reserve(sizeHint);
forever {
evaluateExpression(tokPtr, &ret, joined);
if (evaluateExpression(tokPtr, ret, joined) == ReturnError)
return ReturnError;
switch (*tokPtr) {
case TokValueTerminator:
case TokFuncTerminator:
tokPtr++;
return ret;
return ReturnTrue;
case TokArgSeparator:
if (joined) {
tokPtr++;
@ -1637,28 +1651,28 @@ ProStringList QMakeEvaluator::expandVariableReferences(
}
}
QList<ProStringList> QMakeEvaluator::prepareFunctionArgs(const ushort *&tokPtr)
QMakeEvaluator::VisitReturn QMakeEvaluator::prepareFunctionArgs(
const ushort *&tokPtr, QList<ProStringList> *ret)
{
QList<ProStringList> args_list;
if (*tokPtr != TokFuncTerminator) {
for (;; tokPtr++) {
ProStringList arg;
evaluateExpression(tokPtr, &arg, false);
args_list << arg;
if (evaluateExpression(tokPtr, &arg, false) == ReturnError)
return ReturnError;
*ret << arg;
if (*tokPtr == TokFuncTerminator)
break;
Q_ASSERT(*tokPtr == TokArgSeparator);
}
}
tokPtr++;
return args_list;
return ReturnTrue;
}
ProStringList QMakeEvaluator::evaluateFunction(
const ProFunctionDef &func, const QList<ProStringList> &argumentsList, VisitReturn *ok)
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFunction(
const ProFunctionDef &func, const QList<ProStringList> &argumentsList, ProStringList *ret)
{
VisitReturn vr;
ProStringList ret;
if (m_valuemapStack.count() >= 100) {
evalError(fL1S("Ran into infinite recursion (depth > 100)."));
@ -1677,25 +1691,22 @@ ProStringList QMakeEvaluator::evaluateFunction(
vr = visitProBlock(func.pro(), func.tokPtr());
if (vr == ReturnReturn)
vr = ReturnTrue;
ret = m_returnValue;
if (vr == ReturnTrue)
*ret = m_returnValue;
m_returnValue.clear();
m_current = m_locationStack.pop();
m_valuemapStack.pop();
}
if (ok)
*ok = vr;
if (vr == ReturnTrue)
return ret;
return ProStringList();
return vr;
}
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction(
const ProFunctionDef &func, const QList<ProStringList> &argumentsList,
const ProString &function)
{
VisitReturn vr;
ProStringList ret = evaluateFunction(func, argumentsList, &vr);
ProStringList ret;
VisitReturn vr = evaluateFunction(func, argumentsList, &ret);
if (vr == ReturnTrue) {
if (ret.isEmpty())
return ReturnTrue;
@ -1723,13 +1734,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
{
if (int func_t = statics.functions.value(func)) {
//why don't the builtin functions just use args_list? --Sam
return evaluateBuiltinConditional(func_t, func, expandVariableReferences(tokPtr, 5, true));
ProStringList args;
if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError)
return ReturnError;
return evaluateBuiltinConditional(func_t, func, args);
}
QHash<ProKey, ProFunctionDef>::ConstIterator it =
m_functionDefs.testFunctions.constFind(func);
if (it != m_functionDefs.testFunctions.constEnd()) {
const QList<ProStringList> args = prepareFunctionArgs(tokPtr);
QList<ProStringList> args;
if (prepareFunctionArgs(tokPtr, &args) == ReturnError)
return ReturnError;
traceMsg("calling %s(%s)", dbgKey(func), dbgStrListList(args));
return evaluateBoolFunction(*it, args, func);
}
@ -1739,34 +1755,41 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction(
return ReturnFalse;
}
ProStringList QMakeEvaluator::evaluateExpandFunction(
const ProKey &func, const ushort *&tokPtr)
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpandFunction(
const ProKey &func, const ushort *&tokPtr, ProStringList *ret)
{
if (int func_t = statics.expands.value(func)) {
//why don't the builtin functions just use args_list? --Sam
return evaluateBuiltinExpand(func_t, func, expandVariableReferences(tokPtr, 5, true));
ProStringList args;
if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError)
return ReturnError;
*ret = evaluateBuiltinExpand(func_t, func, args);
return ReturnTrue;
}
QHash<ProKey, ProFunctionDef>::ConstIterator it =
m_functionDefs.replaceFunctions.constFind(func);
if (it != m_functionDefs.replaceFunctions.constEnd()) {
const QList<ProStringList> args = prepareFunctionArgs(tokPtr);
QList<ProStringList> args;
if (prepareFunctionArgs(tokPtr, &args) == ReturnError)
return ReturnError;
traceMsg("calling $$%s(%s)", dbgKey(func), dbgStrListList(args));
return evaluateFunction(*it, args, 0);
return evaluateFunction(*it, args, ret);
}
skipExpression(tokPtr);
evalError(fL1S("'%1' is not a recognized replace function.").arg(func.toQString(m_tmp1)));
return ProStringList();
return ReturnFalse;
}
bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &where, int line)
QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional(
const QString &cond, const QString &where, int line)
{
bool ret = false;
VisitReturn ret = ReturnFalse;
ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar);
if (pro->isOk()) {
m_locationStack.push(m_current);
ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue;
ret = visitProBlock(pro, pro->tokPtr());
m_current = m_locationStack.pop();
}
pro->deref();
@ -1774,28 +1797,49 @@ bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &whe
}
#ifdef PROEVALUATOR_FULL
void QMakeEvaluator::checkRequirements(const ProStringList &deps)
QMakeEvaluator::VisitReturn QMakeEvaluator::checkRequirements(const ProStringList &deps)
{
ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS"));
for (const ProString &dep : deps)
if (!evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line))
for (const ProString &dep : deps) {
VisitReturn vr = evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line);
if (vr == ReturnError)
return ReturnError;
if (vr != ReturnTrue)
failed << dep;
}
return ReturnTrue;
}
#endif
static bool isFunctParam(const ProKey &variableName)
{
const int len = variableName.size();
const QChar *data = variableName.constData();
for (int i = 0; i < len; i++) {
ushort c = data[i].unicode();
if (c < '0' || c > '9')
return false;
}
return true;
}
ProValueMap *QMakeEvaluator::findValues(const ProKey &variableName, ProValueMap::Iterator *rit)
{
ProValueMapStack::Iterator vmi = m_valuemapStack.end();
do {
for (bool first = true; ; first = false) {
--vmi;
ProValueMap::Iterator it = (*vmi).find(variableName);
if (it != (*vmi).end()) {
if (it->constBegin() == statics.fakeValue.constBegin())
return 0;
break;
*rit = it;
return &(*vmi);
}
} while (vmi != m_valuemapStack.begin());
if (vmi == m_valuemapStack.begin())
break;
if (first && isFunctParam(variableName))
break;
}
return 0;
}
@ -1807,18 +1851,20 @@ ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName)
it->clear();
return *it;
}
ProValueMapStack::Iterator vmi = m_valuemapStack.end();
if (--vmi != m_valuemapStack.begin()) {
do {
--vmi;
ProValueMap::ConstIterator it = (*vmi).constFind(variableName);
if (it != (*vmi).constEnd()) {
ProStringList &ret = m_valuemapStack.top()[variableName];
if (it->constBegin() != statics.fakeValue.constBegin())
ret = *it;
return ret;
}
} while (vmi != m_valuemapStack.begin());
if (!isFunctParam(variableName)) {
ProValueMapStack::Iterator vmi = m_valuemapStack.end();
if (--vmi != m_valuemapStack.begin()) {
do {
--vmi;
ProValueMap::ConstIterator it = (*vmi).constFind(variableName);
if (it != (*vmi).constEnd()) {
ProStringList &ret = m_valuemapStack.top()[variableName];
if (it->constBegin() != statics.fakeValue.constBegin())
ret = *it;
return ret;
}
} while (vmi != m_valuemapStack.begin());
}
}
return m_valuemapStack.top()[variableName];
}
@ -1826,7 +1872,7 @@ ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName)
ProStringList QMakeEvaluator::values(const ProKey &variableName) const
{
ProValueMapStack::ConstIterator vmi = m_valuemapStack.constEnd();
do {
for (bool first = true; ; first = false) {
--vmi;
ProValueMap::ConstIterator it = (*vmi).constFind(variableName);
if (it != (*vmi).constEnd()) {
@ -1834,7 +1880,11 @@ ProStringList QMakeEvaluator::values(const ProKey &variableName) const
break;
return *it;
}
} while (vmi != m_valuemapStack.constBegin());
if (vmi == m_valuemapStack.constBegin())
break;
if (first && isFunctParam(variableName))
break;
}
return ProStringList();
}

View File

@ -148,7 +148,7 @@ public:
{ return b ? ReturnTrue : ReturnFalse; }
static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr);
void evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
VisitReturn evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
static ALWAYS_INLINE void skipStr(const ushort *&tokPtr);
static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr);
void skipExpression(const ushort *&tokPtr);
@ -168,7 +168,7 @@ public:
VisitReturn visitProLoop(const ProKey &variable, const ushort *exprPtr,
const ushort *tokPtr);
void visitProFunctionDef(ushort tok, const ProKey &name, const ushort *tokPtr);
void visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
VisitReturn visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
ALWAYS_INLINE const ProKey &map(const ProString &var) { return map(var.toKey()); }
const ProKey &map(const ProKey &var);
@ -177,7 +177,7 @@ public:
void setTemplate();
ProStringList split_value_list(const QString &vals, const ProFile *source = 0);
ProStringList expandVariableReferences(const ushort *&tokPtr, int sizeHint = 0, bool joined = false);
VisitReturn expandVariableReferences(const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined);
QString currentFileName() const;
QString currentDirectory() const;
@ -202,22 +202,22 @@ public:
void deprecationWarning(const QString &msg) const
{ message(QMakeHandler::EvalWarnDeprecated, msg); }
QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr);
ProStringList evaluateFunction(const ProFunctionDef &func,
const QList<ProStringList> &argumentsList, VisitReturn *ok);
VisitReturn prepareFunctionArgs(const ushort *&tokPtr, QList<ProStringList> *ret);
VisitReturn evaluateFunction(const ProFunctionDef &func,
const QList<ProStringList> &argumentsList, ProStringList *ret);
VisitReturn evaluateBoolFunction(const ProFunctionDef &func,
const QList<ProStringList> &argumentsList,
const ProString &function);
ProStringList evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr);
VisitReturn evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr, ProStringList *ret);
VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr);
ProStringList evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args);
VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args);
bool evaluateConditional(const QString &cond, const QString &where, int line = -1);
VisitReturn evaluateConditional(const QString &cond, const QString &where, int line = -1);
#ifdef PROEVALUATOR_FULL
void checkRequirements(const ProStringList &deps);
VisitReturn checkRequirements(const ProStringList &deps);
#endif
void updateMkspecPaths();

View File

@ -299,27 +299,30 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra
// Worst-case size calculations:
// - line marker adds 1 (2-nl) to 1st token of each line
// - empty assignment "A=":2 =>
// TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + 0(1) +
// TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + size_hint(1) +
// TokValueTerminator(1) == 8 (9)
// - non-empty assignment "A=B C":5 =>
// TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + 2(1) +
// TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + size_hint(1) +
// TokLiteral(1) + len(1) + "B"(1) +
// TokLiteral(1) + len(1) + "C"(1) + TokValueTerminator(1) == 14 (15)
// - variable expansion: "$$f":3 =>
// TokVariable(1) + hash(2) + len(1) + "f"(1) = 5
// - function expansion: "$$f()":5 =>
// TokFuncName(1) + hash(2) + len(1) + "f"(1) + TokFuncTerminator(1) = 6
// - test literal: "X":1 =>
// TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokCondition(1) = 6 (7)
// - scope: "X:":2 =>
// TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokCondition(1) +
// TokBranch(1) + len(2) + ... + len(2) + ... == 10
// - test: "X():":4 =>
// TokBranch(1) + len(2) + ... + len(2) + ... == 11 (12)
// - test call: "X():":4 =>
// TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokTestCall(1) + TokFuncTerminator(1) +
// TokBranch(1) + len(2) + ... + len(2) + ... == 11
// TokBranch(1) + len(2) + ... + len(2) + ... == 12 (13)
// - "for(A,B):":9 =>
// TokForLoop(1) + hash(2) + len(1) + "A"(1) +
// len(2) + TokLiteral(1) + len(1) + "B"(1) + TokValueTerminator(1) +
// len(2) + ... + TokTerminator(1) == 14 (15)
tokBuff.reserve((in.size() + 1) * 5);
// One extra for possibly missing trailing newline.
tokBuff.reserve((in.size() + 1) * 7);
ushort *tokPtr = (ushort *)tokBuff.constData(); // Current writing position
// Expression precompiler buffer.

View File

@ -105,9 +105,8 @@ QStringList QMakeProject::expand(const ProKey &func, const QList<ProStringList>
QHash<ProKey, ProFunctionDef>::ConstIterator it =
m_functionDefs.replaceFunctions.constFind(func);
if (it != m_functionDefs.replaceFunctions.constEnd()) {
QMakeProject::VisitReturn vr;
ProStringList ret = evaluateFunction(*it, args, &vr);
if (vr == QMakeProject::ReturnError)
ProStringList ret;
if (evaluateFunction(*it, args, &ret) == QMakeProject::ReturnError)
exit(3);
return ret.toQStringList();
}
@ -125,7 +124,9 @@ ProString QMakeProject::expand(const QString &expr, const QString &where, int li
m_current.pro = pro;
m_current.line = 0;
const ushort *tokPtr = pro->tokPtr();
ProStringList result = expandVariableReferences(tokPtr, 1, true);
ProStringList result;
if (expandVariableReferences(tokPtr, 1, &result, true) == ReturnError)
exit(3);
if (!result.isEmpty())
ret = result.at(0);
}

View File

@ -55,7 +55,7 @@ public:
ProString expand(const QString &v, const QString &file, int line);
QStringList expand(const ProKey &func, const QList<ProStringList> &args);
bool test(const QString &v, const QString &file, int line)
{ m_current.clear(); return evaluateConditional(v, file, line); }
{ m_current.clear(); return evaluateConditional(v, file, line) == ReturnTrue; }
bool test(const ProKey &func, const QList<ProStringList> &args);
bool isSet(const ProKey &v) const { return m_valuemapStack.first().contains(v); }

View File

@ -71,12 +71,12 @@
#elif defined(Q_OS_HAIKU)
# include <kernel/OS.h>
#elif defined(Q_OS_BSD4) && !defined(Q_OS_IOS)
# if !defined(Q_OS_NETBSD)
# include <sys/user.h>
# endif
# include <sys/cdefs.h>
# include <sys/param.h>
# include <sys/sysctl.h>
# if !defined(Q_OS_NETBSD)
# include <sys/user.h>
# endif
#endif
QT_BEGIN_NAMESPACE

View File

@ -2411,26 +2411,40 @@ QString &QString::replace(const QString &before, const QString &after, Qt::CaseS
return replace(before.constData(), before.size(), after.constData(), after.size(), cs);
}
namespace { // helpers for replace and its helper:
QChar *textCopy(const QChar *start, int len)
{
const size_t size = len * sizeof(QChar);
QChar *const copy = static_cast<QChar *>(::malloc(size));
Q_CHECK_PTR(copy);
::memcpy(copy, start, size);
return copy;
}
bool pointsIntoRange(const QChar *ptr, const ushort *base, int len)
{
const QChar *const start = reinterpret_cast<const QChar *>(base);
return start <= ptr && ptr < start + len;
}
} // end namespace
/*!
\internal
*/
void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar *after, int alen)
{
// copy *after in case it lies inside our own d->data() area
// (which we could possibly invalidate via a realloc or corrupt via memcpy operations.)
QChar *afterBuffer = const_cast<QChar *>(after);
if (after >= reinterpret_cast<QChar *>(d->data()) && after < reinterpret_cast<QChar *>(d->data()) + d->size) {
afterBuffer = static_cast<QChar *>(::malloc(alen*sizeof(QChar)));
Q_CHECK_PTR(afterBuffer);
::memcpy(afterBuffer, after, alen*sizeof(QChar));
}
// Copy after if it lies inside our own d->data() area (which we could
// possibly invalidate via a realloc or modify by replacement).
QChar *afterBuffer = 0;
if (pointsIntoRange(after, d->data(), d->size)) // Use copy in place of vulnerable original:
after = afterBuffer = textCopy(after, alen);
QT_TRY {
if (blen == alen) {
// replace in place
detach();
for (int i = 0; i < nIndices; ++i)
memcpy(d->data() + indices[i], afterBuffer, alen * sizeof(QChar));
memcpy(d->data() + indices[i], after, alen * sizeof(QChar));
} else if (alen < blen) {
// replace from front
detach();
@ -2446,7 +2460,7 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
to += msize;
}
if (alen) {
memcpy(d->data() + to, afterBuffer, alen*sizeof(QChar));
memcpy(d->data() + to, after, alen * sizeof(QChar));
to += alen;
}
movestart = indices[i] + blen;
@ -2469,17 +2483,15 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
int moveto = insertstart + alen;
memmove(d->data() + moveto, d->data() + movestart,
(moveend - movestart)*sizeof(QChar));
memcpy(d->data() + insertstart, afterBuffer, alen*sizeof(QChar));
memcpy(d->data() + insertstart, after, alen * sizeof(QChar));
moveend = movestart-blen;
}
}
} QT_CATCH(const std::bad_alloc &) {
if (afterBuffer != after)
::free(afterBuffer);
::free(afterBuffer);
QT_RETHROW;
}
if (afterBuffer != after)
::free(afterBuffer);
::free(afterBuffer);
}
/*!
@ -2508,31 +2520,48 @@ QString &QString::replace(const QChar *before, int blen,
return *this;
QStringMatcher matcher(before, blen, cs);
QChar *beforeBuffer = 0, *afterBuffer = 0;
int index = 0;
while (1) {
uint indices[1024];
uint pos = 0;
while (pos < 1023) {
while (pos < 1024) {
index = matcher.indexIn(*this, index);
if (index == -1)
break;
indices[pos++] = index;
index += blen;
// avoid infinite loop
if (!blen)
if (blen) // Step over before:
index += blen;
else // Only count one instance of empty between any two characters:
index++;
}
if (!pos)
if (!pos) // Nothing to replace
break;
if (Q_UNLIKELY(index != -1)) {
/*
We're about to change data, that before and after might point
into, and we'll need that data for our next batch of indices.
*/
if (!afterBuffer && pointsIntoRange(after, d->data(), d->size))
after = afterBuffer = textCopy(after, alen);
if (!beforeBuffer && pointsIntoRange(before, d->data(), d->size)) {
beforeBuffer = textCopy(before, blen);
matcher = QStringMatcher(beforeBuffer, blen, cs);
}
}
replace_helper(indices, pos, blen, after, alen);
if (index == -1)
if (Q_LIKELY(index == -1)) // Nothing left to replace
break;
// index has to be adjusted in case we get back into the loop above.
// The call to replace_helper just moved what index points at:
index += pos*(alen-blen);
}
::free(afterBuffer);
::free(beforeBuffer);
return *this;
}
@ -2563,26 +2592,26 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
uint indices[1024];
uint pos = 0;
if (cs == Qt::CaseSensitive) {
while (pos < 1023 && index < d->size) {
while (pos < 1024 && index < d->size) {
if (d->data()[index] == cc)
indices[pos++] = index;
index++;
}
} else {
while (pos < 1023 && index < d->size) {
while (pos < 1024 && index < d->size) {
if (QChar::toCaseFolded(d->data()[index]) == cc)
indices[pos++] = index;
index++;
}
}
if (!pos)
if (!pos) // Nothing to replace
break;
replace_helper(indices, pos, 1, after.constData(), after.d->size);
if (index == -1)
if (Q_LIKELY(index == -1)) // Nothing left to replace
break;
// index has to be adjusted in case we get back into the loop above.
// The call to replace_helper just moved what index points at:
index += pos*(after.d->size - 1);
}
return *this;
@ -5008,7 +5037,7 @@ void QString::truncate(int pos)
Removes \a n characters from the end of the string.
If \a n is greater than or equal to size(), the result is an
empty string.
empty string; if \a n is negative, it is equivalent to passing zero.
Example:
\snippet qstring/main.cpp 15

View File

@ -82,7 +82,7 @@ struct QStringBuilderCommon
T toLower() const { return resolved().toLower(); }
protected:
const T resolved() const { return *static_cast<const Builder*>(this); }
T resolved() const { return *static_cast<const Builder*>(this); }
};
template<typename Builder, typename T>

View File

@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE
// Create the system default time zone
QMacTimeZonePrivate::QMacTimeZonePrivate()
: m_nstz(0)
{
init(systemTimeZoneId());
}

View File

@ -758,7 +758,7 @@ void QAccessible::deleteAccessibleInterface(Id id)
*/
QAccessible::Id QAccessible::uniqueId(QAccessibleInterface *iface)
{
Id id = QAccessibleCache::instance()->idToInterface.key(iface);
Id id = QAccessibleCache::instance()->idForInterface(iface);
if (!id)
id = registerAccessibleInterface(iface);
return id;
@ -771,7 +771,7 @@ QAccessible::Id QAccessible::uniqueId(QAccessibleInterface *iface)
*/
QAccessibleInterface *QAccessible::accessibleInterface(Id id)
{
return QAccessibleCache::instance()->idToInterface.value(id);
return QAccessibleCache::instance()->interfaceForId(id);
}

View File

@ -83,6 +83,11 @@ QAccessibleInterface *QAccessibleCache::interfaceForId(QAccessible::Id id) const
return idToInterface.value(id);
}
QAccessible::Id QAccessibleCache::idForInterface(QAccessibleInterface *iface) const
{
return interfaceToId.value(iface);
}
QAccessible::Id QAccessibleCache::insert(QObject *object, QAccessibleInterface *iface) const
{
Q_ASSERT(iface);
@ -90,7 +95,7 @@ QAccessible::Id QAccessibleCache::insert(QObject *object, QAccessibleInterface *
// object might be 0
Q_ASSERT(!objectToId.contains(object));
Q_ASSERT_X(!idToInterface.values().contains(iface), "", "Accessible interface inserted into cache twice!");
Q_ASSERT_X(!interfaceToId.contains(iface), "", "Accessible interface inserted into cache twice!");
QAccessible::Id id = acquireId();
QObject *obj = iface->object();
@ -100,6 +105,7 @@ QAccessible::Id QAccessibleCache::insert(QObject *object, QAccessibleInterface *
connect(obj, &QObject::destroyed, this, &QAccessibleCache::objectDestroyed);
}
idToInterface.insert(id, iface);
interfaceToId.insert(iface, id);
return id;
}
@ -115,6 +121,7 @@ void QAccessibleCache::objectDestroyed(QObject* obj)
void QAccessibleCache::deleteInterface(QAccessible::Id id, QObject *obj)
{
QAccessibleInterface *iface = idToInterface.take(id);
interfaceToId.take(iface);
if (!obj)
obj = iface->object();
if (obj)

View File

@ -70,6 +70,7 @@ class Q_GUI_EXPORT QAccessibleCache :public QObject
public:
static QAccessibleCache *instance();
QAccessibleInterface *interfaceForId(QAccessible::Id id) const;
QAccessible::Id idForInterface(QAccessibleInterface *iface) const;
QAccessible::Id insert(QObject *object, QAccessibleInterface *iface) const;
void deleteInterface(QAccessible::Id id, QObject *obj = 0);
@ -85,6 +86,7 @@ private:
QAccessible::Id acquireId() const;
mutable QHash<QAccessible::Id, QAccessibleInterface *> idToInterface;
mutable QHash<QAccessibleInterface *, QAccessible::Id> interfaceToId;
mutable QHash<QObject *, QAccessible::Id> objectToId;
#ifdef Q_OS_MAC

View File

@ -3331,28 +3331,6 @@ bool QGuiApplication::isSavingSession() const
return d->is_saving_session;
}
/*!
\since 5.2
Function that can be used to sync Qt state with the Window Systems state.
This function will first empty Qts events by calling QCoreApplication::processEvents(),
then the platform plugin will sync up with the windowsystem, and finally Qts events
will be delived by another call to QCoreApplication::processEvents();
This function is timeconsuming and its use is discouraged.
*/
void QGuiApplication::sync()
{
QCoreApplication::processEvents();
if (QGuiApplicationPrivate::platform_integration
&& QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::SyncState)) {
QGuiApplicationPrivate::platform_integration->sync();
QCoreApplication::processEvents();
QWindowSystemInterface::flushWindowSystemEvents();
}
}
void QGuiApplicationPrivate::commitData()
{
Q_Q(QGuiApplication);
@ -3377,6 +3355,28 @@ void QGuiApplicationPrivate::saveState()
}
#endif //QT_NO_SESSIONMANAGER
/*!
\since 5.2
Function that can be used to sync Qt state with the Window Systems state.
This function will first empty Qts events by calling QCoreApplication::processEvents(),
then the platform plugin will sync up with the windowsystem, and finally Qts events
will be delived by another call to QCoreApplication::processEvents();
This function is timeconsuming and its use is discouraged.
*/
void QGuiApplication::sync()
{
QCoreApplication::processEvents();
if (QGuiApplicationPrivate::platform_integration
&& QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::SyncState)) {
QGuiApplicationPrivate::platform_integration->sync();
QCoreApplication::processEvents();
QWindowSystemInterface::flushWindowSystemEvents();
}
}
/*!
\property QGuiApplication::layoutDirection
\brief the default layout direction for this application
@ -3623,7 +3623,8 @@ QPixmap QGuiApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
void QGuiApplicationPrivate::notifyThemeChanged()
{
if (!(applicationResourceFlags & ApplicationPaletteExplicitlySet)) {
if (!(applicationResourceFlags & ApplicationPaletteExplicitlySet) &&
!QCoreApplication::testAttribute(Qt::AA_SetPalette)) {
clearPalette();
initPalette();
}

View File

@ -1289,6 +1289,7 @@ static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool includ
const char *ver = reinterpret_cast<const char *>(funcs->glGetString(GL_VERSION));
// Blacklist GPU chipsets that have problems with their BGRA support.
#ifndef Q_OS_IOS
const bool blackListed = (qstrcmp(renderer, "PowerVR Rogue G6200") == 0
&& ::strstr(ver, "1.3") != 0) ||
(qstrcmp(renderer, "Mali-T760") == 0
@ -1296,7 +1297,9 @@ static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool includ
(qstrcmp(renderer, "Mali-T720") == 0
&& ::strstr(ver, "3.1") != 0) ||
qstrcmp(renderer, "PowerVR SGX 554") == 0;
#else
const bool blackListed = true;
#endif
const bool supports_bgra = has_bgra_ext && !blackListed;
if (supports_bgra) {

View File

@ -1278,10 +1278,10 @@ static QByteArray qEncodeNtlmv2Response(const QAuthenticatorPrivate *ctx,
// 369 years, 89 leap years
// ((369 * 365) + 89) * 24 * 3600 = 11644473600
time = Q_UINT64_C(currentTime.toTime_t() + 11644473600);
time = currentTime.toTime_t() + Q_UINT64_C(11644473600);
// represented as 100 nano seconds
time = Q_UINT64_C(time * 10000000);
time = time * Q_UINT64_C(10000000);
ds << time;
}

View File

@ -583,7 +583,7 @@ void QSslSocketBackendPrivate::startClientEncryption()
// Error description/code were set, 'error' emitted
// by initSslContext, but OpenSSL socket also sets error
// emits a signal twice, so ...
setErrorAndEmit(QAbstractSocket::SslInternalError, "Unable to init SSL Context");
setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
return;
}
@ -596,7 +596,7 @@ void QSslSocketBackendPrivate::startServerEncryption()
// Error description/code were set, 'error' emitted
// by initSslContext, but OpenSSL socket also sets error
// emits a signal twice, so ...
setErrorAndEmit(QAbstractSocket::SslInternalError, "Unable to init SSL Context");
setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
return;
}
@ -927,7 +927,7 @@ bool QSslSocketBackendPrivate::initSslContext()
context.reset(qt_createSecureTransportContext(mode));
if (!context) {
setErrorAndEmit(QAbstractSocket::SslInternalError, "SSLCreateContext failed");
setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("SSLCreateContext failed"));
return false;
}
@ -955,7 +955,7 @@ bool QSslSocketBackendPrivate::initSslContext()
if (!setSessionProtocol()) {
destroySslContext();
setErrorAndEmit(QAbstractSocket::SslInternalError, "Failed to set protocol version");
setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Failed to set protocol version"));
return false;
}
@ -1397,8 +1397,7 @@ bool QSslSocketBackendPrivate::startHandshake()
// check protocol version ourselves, as Secure Transport does not enforce
// the requested min / max versions.
if (!verifySessionProtocol()) {
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError,
"Protocol version mismatch");
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, QStringLiteral("Protocol version mismatch"));
plainSocket->disconnectFromHost();
return false;
}

View File

@ -412,9 +412,7 @@ QVariant QMacPasteboardMimeUnicodeText::convertToMime(const QString &mimetype, Q
// I can only handle two types (system and unicode) so deal with them that way
QVariant ret;
if (flavor == QLatin1String("public.utf8-plain-text")) {
ret = QString(QCFString(CFStringCreateWithBytes(kCFAllocatorDefault,
reinterpret_cast<const UInt8 *>(firstData.constData()),
firstData.size(), CFStringGetSystemEncoding(), false)));
ret = QString::fromUtf8(firstData);
} else if (flavor == QLatin1String("public.utf16-plain-text")) {
ret = QString(reinterpret_cast<const QChar *>(firstData.constData()),
firstData.size() / sizeof(QChar));

View File

@ -594,8 +594,7 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
fallbackList.append(familyNameFromPostScriptName(item));
}
if (QCoreTextFontEngine::supportsColorGlyphs())
fallbackList.append(QLatin1String("Apple Color Emoji"));
fallbackList.append(QLatin1String("Apple Color Emoji"));
// Since we are only returning a list of default fonts for the current language, we do not
// cover all unicode completely. This was especially an issue for some of the common script

View File

@ -224,11 +224,9 @@ void QCoreTextFontEngine::init()
synthesisFlags = 0;
CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
#if defined(Q_OS_IOS) || MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if (supportsColorGlyphs() && (traits & kCTFontColorGlyphsTrait))
if (traits & kCTFontColorGlyphsTrait)
glyphFormat = QFontEngine::Format_ARGB;
else
#endif
glyphFormat = defaultGlyphFormat;
if (traits & kCTFontItalicTrait)
@ -656,9 +654,7 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &CGSizeZero, 1);
}
}
#if defined(Q_OS_IOS) || MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
else if (supportsColorGlyphs()) {
} else {
// CGContextSetTextMatrix does not work with color glyphs, so we use
// the CTM instead. This means we must translate the CTM as well, to
// set the glyph position, instead of using CGContextSetTextPosition.
@ -669,7 +665,6 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
// glyphs in the Apple Color Emoji font, so we use CTFontDrawGlyphs instead.
CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx);
}
#endif
CGContextRelease(ctx);
CGColorSpaceRelease(colorspace);

View File

@ -113,21 +113,6 @@ public:
QFontEngine::Properties properties() const Q_DECL_OVERRIDE;
static bool supportsColorGlyphs()
{
#if defined(Q_OS_IOS)
return true;
#elif MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
return &CTFontDrawGlyphs;
#else
return true;
#endif
#else
return false;
#endif
}
static bool ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length);
static QFont::Weight qtWeightFromCFWeight(float value);

View File

@ -218,6 +218,7 @@ protected:
private:
QVariantMap properties();
QVariantMap propertiesMap;
private Q_SLOTS:
void scanReply(QDBusPendingCallWatcher *call);
};

View File

@ -457,6 +457,10 @@ QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
if (index >= mScreens.count())
updateScreens();
// It is possible that the screen got removed while updateScreens was called
// so we do a sanity check to be certain
if (index >= mScreens.count())
return 0;
return mScreens.at(index);
}

View File

@ -93,6 +93,9 @@ public:
void setAttachedItem(NSMenuItem *item);
NSMenuItem *attachedItem() const;
bool isOpen() const;
void setIsOpen(bool isOpen);
private:
QCocoaMenuItem *itemOrNull(int index) const;
void insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem);
@ -100,9 +103,10 @@ private:
QList<QCocoaMenuItem *> m_menuItems;
NSMenu *m_nativeMenu;
NSMenuItem *m_attachedItem;
quintptr m_tag;
bool m_enabled;
bool m_visible;
quintptr m_tag;
bool m_isOpen;
};
QT_END_NAMESPACE

View File

@ -137,12 +137,14 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate);
- (void) menuWillOpen:(NSMenu*)m
{
Q_UNUSED(m);
m_menu->setIsOpen(true);
emit m_menu->aboutToShow();
}
- (void) menuDidClose:(NSMenu*)m
{
Q_UNUSED(m);
m_menu->setIsOpen(false);
// wrong, but it's the best we can do
emit m_menu->aboutToHide();
}
@ -257,9 +259,10 @@ QT_BEGIN_NAMESPACE
QCocoaMenu::QCocoaMenu() :
m_attachedItem(0),
m_tag(0),
m_enabled(true),
m_visible(true),
m_tag(0)
m_isOpen(false)
{
QMacAutoReleasePool pool;
@ -330,6 +333,8 @@ void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem)
item->nsItem().target = m_nativeMenu.delegate;
if (!item->menu())
[item->nsItem() setAction:@selector(itemFired:)];
else if (isOpen() && item->nsItem()) // Someone's adding new items after aboutToShow() was emitted
item->menu()->setAttachedItem(item->nsItem());
if (item->isMerged())
return;
@ -353,6 +358,16 @@ void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem)
item->setMenuParent(this);
}
bool QCocoaMenu::isOpen() const
{
return m_isOpen;
}
void QCocoaMenu::setIsOpen(bool isOpen)
{
m_isOpen = isOpen;
}
void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem)
{
QMacAutoReleasePool pool;

View File

@ -179,9 +179,11 @@ void QCocoaMenuBar::syncMenu(QPlatformMenu *menu)
}
}
NSMenuItem *nativeMenuItem = nativeItemForMenu(cocoaMenu);
nativeMenuItem.title = cocoaMenu->nsMenu().title;
nativeMenuItem.hidden = shouldHide;
if (NSMenuItem *attachedItem = cocoaMenu->attachedItem()) {
// Non-nil attached item means the item's submenu is set
attachedItem.title = cocoaMenu->nsMenu().title;
attachedItem.hidden = shouldHide;
}
}
NSMenuItem *QCocoaMenuBar::nativeItemForMenu(QCocoaMenu *menu) const

View File

@ -260,34 +260,14 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
}
if (iconType != 0) {
QPixmap pixmap;
IconRef icon;
IconRef overlayIcon = 0;
if (iconType != kGenericApplicationIcon) {
GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon);
} else {
FSRef fsRef;
ProcessSerialNumber psn = { 0, kCurrentProcess };
GetProcessBundleLocation(&psn, &fsRef);
GetIconRefFromFileInfo(&fsRef, 0, 0, 0, 0, kIconServicesNormalUsageFlag, &icon, 0);
if (sp == MessageBoxCritical) {
overlayIcon = icon;
GetIconRef(kOnSystemDisk, kSystemIconsCreator, kAlertCautionIcon, &icon);
}
}
IconRef icon = Q_NULLPTR;
GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon);
if (icon) {
pixmap = qt_mac_convert_iconref(icon, size.width(), size.height());
ReleaseIconRef(icon);
}
if (overlayIcon) {
QSizeF littleSize = size / 2;
QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize.width(), littleSize.height());
QPainter painter(&pixmap);
painter.drawPixmap(littleSize.width(), littleSize.height(), overlayPix);
ReleaseIconRef(overlayIcon);
}
return pixmap;
}

View File

@ -474,7 +474,8 @@ QT_WARNING_POP
NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen];
if (screenIndex != NSNotFound) {
QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex);
QWindowSystemInterface::handleWindowScreenChanged(m_window, cocoaScreen->screen());
if (cocoaScreen)
QWindowSystemInterface::handleWindowScreenChanged(m_window, cocoaScreen->screen());
m_platformWindow->updateExposedGeometry();
}
}

View File

@ -11,7 +11,7 @@ HEADERS = qminimalintegration.h \
OTHER_FILES += minimal.json
CONFIG += qpa/genericunixfontdatabase
darwin: DEFINES += QT_NO_FONTCONFIG
win32|darwin: DEFINES += QT_NO_FONTCONFIG
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QMinimalIntegrationPlugin

View File

@ -178,7 +178,7 @@ void QQnxRasterWindow::adjustBufferSize()
{
// When having a raster window we don't need any buffers, since
// Qt will draw to the parent TLW backing store.
const QSize windowSize = window()->parent() ? QSize(1,1) : window()->size();
const QSize windowSize = window()->parent() ? QSize(0,0) : window()->size();
if (windowSize != bufferSize())
setBufferSize(windowSize);
}
@ -194,6 +194,13 @@ void QQnxRasterWindow::resetBuffers()
m_currentBufferIndex = -1;
m_previousDirty = QRegion();
m_scrolled = QRegion();
if (window()->parent() && bufferSize() == QSize(1,1)) {
// If we have a parent then we're not really rendering. But if we don't render we'll
// be invisible and any children won't show up. This should be harmless since we're
// rendering into a 1x1 window that has transparency set to discard.
renderBuffer();
post(QRegion(0,0,1,1));
}
}
void QQnxRasterWindow::blitPreviousToCurrent(const QRegion &region, int dx, int dy, bool flush)

View File

@ -386,7 +386,12 @@ void QQnxWindow::setBufferSize(const QSize &size)
// Set the transparency. According to QNX technical support, setting the window
// transparency property should always be done *after* creating the window
// buffers in order to guarantee the property is paid attention to.
if (window()->requestedFormat().alphaBufferSize() == 0) {
if (size.isEmpty()) {
// We can't create 0x0 buffers and instead make them 1x1. But to allow these windows to
// still be 'visible' (thus allowing their children to be visible), we need to allow
// them to be posted but still not show up.
val[0] = SCREEN_TRANSPARENCY_DISCARD;
} else if (window()->requestedFormat().alphaBufferSize() == 0) {
// To avoid overhead in the composition manager, disable blending
// when the underlying window buffer doesn't have an alpha channel.
val[0] = SCREEN_TRANSPARENCY_NONE;

View File

@ -47,6 +47,7 @@
#include "qwindowsmime.h"
#include "qwindowsinputcontext.h"
#include "qwindowstabletsupport.h"
#include "qwindowstheme.h"
#include <private/qguiapplication_p.h>
#ifndef QT_NO_ACCESSIBILITY
# include "accessible/qwindowsaccessibility.h"
@ -1014,6 +1015,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
#endif
case QtWindows::DisplayChangedEvent:
return d->m_screenManager.handleDisplayChange(wParam, lParam);
if (QWindowsTheme *t = QWindowsTheme::instance())
t->displayChanged();
case QtWindows::SettingChangedEvent:
return d->m_screenManager.handleScreenChanges();
default:

View File

@ -53,7 +53,7 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
#include <QtCore/QDebug>
#include <QtCore/QScopedArrayPointer>
#include <QtCore/QVarLengthArray>
#include <QtCore/QtMath>
#include <private/qguiapplication_p.h>
@ -233,7 +233,7 @@ QString QWindowsTabletSupport::description() const
const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0);
if (!size)
return QString();
QScopedPointer<TCHAR> winTabId(new TCHAR[size + 1]);
QVarLengthArray<TCHAR> winTabId(size + 1);
m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, winTabId.data());
WORD implementationVersion = 0;
m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_IMPLVERSION, &implementationVersion);

View File

@ -335,6 +335,7 @@ QWindowsTheme::QWindowsTheme()
std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0));
std::fill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0));
refresh();
refreshIconPixmapSizes();
}
QWindowsTheme::~QWindowsTheme()
@ -400,16 +401,8 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const
return QVariant(int(WindowsKeyboardScheme));
case UiEffects:
return QVariant(uiEffects());
case IconPixmapSizes: {
QList<int> sizes;
sizes << 16 << 32;
#ifdef USE_IIMAGELIST
sizes << 48; // sHIL_EXTRALARGE
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
sizes << 256; // SHIL_JUMBO
#endif // USE_IIMAGELIST
return QVariant::fromValue(sizes);
}
case IconPixmapSizes:
return m_fileIconSizes;
case DialogSnapToDefaultButton:
return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON, false));
case ContextMenuOnMouseRelease:
@ -479,6 +472,15 @@ void QWindowsTheme::refreshFonts()
#endif // !Q_OS_WINCE
}
enum FileIconSize {
// Standard icons obtainable via shGetFileInfo(), SHGFI_SMALLICON, SHGFI_LARGEICON
SmallFileIcon, LargeFileIcon,
// Larger icons obtainable via SHGetImageList()
ExtraLargeFileIcon,
JumboFileIcon, // Vista onwards
FileIconSizeCount
};
bool QWindowsTheme::usePlatformNativeDialog(DialogType type) const
{
return QWindowsDialogs::useHelper(type);
@ -495,6 +497,27 @@ void QWindowsTheme::windowsThemeChanged(QWindow * window)
QWindowSystemInterface::handleThemeChange(window);
}
static int fileIconSizes[FileIconSizeCount];
void QWindowsTheme::refreshIconPixmapSizes()
{
// Standard sizes: 16, 32, 48, 256
fileIconSizes[SmallFileIcon] = GetSystemMetrics(SM_CXSMICON); // corresponds to SHGFI_SMALLICON);
fileIconSizes[LargeFileIcon] = GetSystemMetrics(SM_CXICON); // corresponds to SHGFI_LARGEICON
fileIconSizes[ExtraLargeFileIcon] =
fileIconSizes[LargeFileIcon] + fileIconSizes[LargeFileIcon] / 2;
fileIconSizes[JumboFileIcon] = 8 * fileIconSizes[LargeFileIcon]; // empirical, has not been observed to work
QList<int> sizes;
sizes << fileIconSizes[SmallFileIcon] << fileIconSizes[LargeFileIcon];
#ifdef USE_IIMAGELIST
sizes << fileIconSizes[ExtraLargeFileIcon]; // sHIL_EXTRALARGE
if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA)
sizes << fileIconSizes[JumboFileIcon]; // SHIL_JUMBO
#endif // USE_IIMAGELIST
qCDebug(lcQpaWindows) << __FUNCTION__ << sizes;
m_fileIconSizes = QVariant::fromValue(sizes);
}
// Defined in qpixmap_win.cpp
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon);
@ -741,10 +764,12 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s
QPixmap pixmap;
const QString filePath = QDir::toNativeSeparators(fileInfo.filePath());
const int width = int(size.width());
const int iconSize = width > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON;
const int iconSize = width > fileIconSizes[SmallFileIcon] ? SHGFI_LARGEICON : SHGFI_SMALLICON;
const int requestedImageListSize =
#ifdef USE_IIMAGELIST
width > 48 ? sHIL_JUMBO : (width > 32 ? sHIL_EXTRALARGE : 0);
width > fileIconSizes[ExtraLargeFileIcon]
? sHIL_JUMBO
: (width > fileIconSizes[LargeFileIcon] ? sHIL_EXTRALARGE : 0);
#else
0;
#endif // !USE_IIMAGELIST

View File

@ -43,6 +43,8 @@
#include "qwindowsthreadpoolrunner.h"
#include <qpa/qplatformtheme.h>
#include <QtCore/QVariant>
QT_BEGIN_NAMESPACE
class QWindow;
@ -68,6 +70,7 @@ public:
QPlatformTheme::IconOptions iconOptions = 0) const Q_DECL_OVERRIDE;
void windowsThemeChanged(QWindow *window);
void displayChanged() { refreshIconPixmapSizes(); }
static const char *name;
@ -77,11 +80,13 @@ private:
void refreshPalettes();
void clearFonts();
void refreshFonts();
void refreshIconPixmapSizes();
static QWindowsTheme *m_instance;
QPalette *m_palettes[NPalettes];
QFont *m_fonts[NFonts];
mutable QWindowsThreadPoolRunner m_threadPoolRunner;
QVariant m_fileIconSizes;
};
QT_END_NAMESPACE

View File

@ -2522,9 +2522,10 @@ void QWindowsWindow::aboutToMakeCurrent()
void QWindowsWindow::setHasBorderInFullScreenStatic(QWindow *window, bool border)
{
if (!window->handle())
return;
static_cast<QWindowsWindow *>(window->handle())->setHasBorderInFullScreen(border);
if (QPlatformWindow *handle = window->handle())
static_cast<QWindowsWindow *>(handle)->setHasBorderInFullScreen(border);
else
qWarning("%s invoked without window handle; call has no effect.", Q_FUNC_INFO);
}
void QWindowsWindow::setHasBorderInFullScreen(bool border)

View File

@ -265,8 +265,8 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
} else {
screen = createScreen(virtualDesktop, output, outputInfo.data());
qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
QHighDpiScaling::updateHighDpiScaling();
}
QHighDpiScaling::updateHighDpiScaling();
}
} else if (screen) {
if (output.crtc == XCB_NONE && output.mode == XCB_NONE) {

View File

@ -108,37 +108,57 @@ template<> inline char *toString(const QDateTime &dateTime)
template<> inline char *toString(const QChar &c)
{
const ushort uc = c.unicode();
if (uc < 128) {
char msg[32] = {'\0'};
qsnprintf(msg, sizeof(msg), "QChar: '%c' (0x%x)", char(uc), unsigned(uc));
return qstrdup(msg);
}
return qstrdup(qPrintable(QString::fromLatin1("QChar: '%1' (0x%2)").arg(c).arg(QString::number(static_cast<int>(c.unicode()), 16))));
}
template<> inline char *toString(const QPoint &p)
{
return qstrdup(QString::fromLatin1("QPoint(%1,%2)").arg(p.x()).arg(p.y()).toLatin1().constData());
char msg[128] = {'\0'};
qsnprintf(msg, sizeof(msg), "QPoint(%d,%d)", p.x(), p.y());
return qstrdup(msg);
}
template<> inline char *toString(const QSize &s)
{
return qstrdup(QString::fromLatin1("QSize(%1x%2)").arg(s.width()).arg(s.height()).toLatin1().constData());
char msg[128] = {'\0'};
qsnprintf(msg, sizeof(msg), "QSize(%dx%d)", s.width(), s.height());
return qstrdup(msg);
}
template<> inline char *toString(const QRect &s)
{
return qstrdup(QString::fromLatin1("QRect(%1,%2 %5x%6) (bottomright %3,%4)").arg(s.left()).arg(s.top()).arg(s.right()).arg(s.bottom()).arg(s.width()).arg(s.height()).toLatin1().constData());
char msg[256] = {'\0'};
qsnprintf(msg, sizeof(msg), "QRect(%d,%d %dx%d) (bottomright %d,%d)",
s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
return qstrdup(msg);
}
template<> inline char *toString(const QPointF &p)
{
return qstrdup(QString::fromLatin1("QPointF(%1,%2)").arg(p.x()).arg(p.y()).toLatin1().constData());
char msg[64] = {'\0'};
qsnprintf(msg, sizeof(msg), "QPointF(%g,%g)", p.x(), p.y());
return qstrdup(msg);
}
template<> inline char *toString(const QSizeF &s)
{
return qstrdup(QString::fromLatin1("QSizeF(%1x%2)").arg(s.width()).arg(s.height()).toLatin1().constData());
char msg[64] = {'\0'};
qsnprintf(msg, sizeof(msg), "QSizeF(%gx%g)", s.width(), s.height());
return qstrdup(msg);
}
template<> inline char *toString(const QRectF &s)
{
return qstrdup(QString::fromLatin1("QRectF(%1,%2 %5x%6) (bottomright %3,%4)").arg(s.left()).arg(s.top()).arg(s.right()).arg(s.bottom()).arg(s.width()).arg(s.height()).toLatin1().constData());
char msg[256] = {'\0'};
qsnprintf(msg, sizeof(msg), "QRectF(%g,%g %gx%g) (bottomright %g,%g)",
s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
return qstrdup(msg);
}
template<> inline char *toString(const QUrl &uri)

View File

@ -188,7 +188,8 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
token = keywords[state].ident;
if (token == NOTOKEN) {
++data;
if (*data)
++data;
// an error really, but let's ignore this input
// to not confuse moc later. However in pre-processor
// only mode let's continue.
@ -362,7 +363,6 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
++data;
continue;
}
int nextindex = pp_keywords[state].next;
int next = 0;
if (*data == pp_keywords[state].defchar)
@ -381,7 +381,8 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
switch (token) {
case NOTOKEN:
++data;
if (*data)
++data;
break;
case PP_DEFINE:
mode = PrepareDefine;
@ -1255,7 +1256,6 @@ void Preprocessor::parseDefineArguments(Macro *m)
error("missing ')' in macro argument list");
break;
} else if (!is_identifier(l.constData(), l.length())) {
qDebug() << l;
error("Unexpected character in macro argument list.");
}
}

View File

@ -1024,9 +1024,11 @@ static QPlatformTextureList *widgetTexturesFor(QWidget *tlw, QWidget *widget)
// The Windows compositor handles fullscreen OpenGL window specially. Besides
// having trouble with popups, it also has issues with flip-flopping between
// OpenGL-based and normal flushing. Therefore, stick with GL for fullscreen
// windows. (QTBUG-53515)
// windows (QTBUG-53515). Similary, translucent windows should not switch to
// layered native windows (QTBUG-54734).
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE)
|| tlw->windowState().testFlag(Qt::WindowFullScreen)
|| tlw->testAttribute(Qt::WA_TranslucentBackground)
#endif
)
{

View File

@ -2935,7 +2935,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
QImage img;
QSize pixmapSize = opt->rect.size();
if (pixmapSize.isValid()) {
if (!pixmapSize.isEmpty()) {
QPixmap pix(pixmapSize);
pix.fill(QColor(fillR, fillG, fillB));
QPainter pix_paint(&pix);

View File

@ -733,7 +733,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
\value State_None Indicates that the widget does not have a state.
\value State_Active Indicates that the widget is active.
\value State_AutoRaise Used to indicate if auto-raise appearance should be usd on a tool button.
\value State_AutoRaise Used to indicate if auto-raise appearance should be used on a tool button.
\value State_Children Used to indicate if an item view branch has children.
\value State_DownArrow Used to indicate if a down arrow should be visible on the widget.
\value State_Editing Used to indicate if an editor is opened on the widget.

View File

@ -1044,6 +1044,10 @@ void QCompleter::setModel(QAbstractItemModel *model)
{
Q_D(QCompleter);
QAbstractItemModel *oldModel = d->proxy->sourceModel();
#ifndef QT_NO_FILESYSTEMMODEL
if (qobject_cast<const QFileSystemModel *>(oldModel))
setCompletionRole(Qt::EditRole); // QTBUG-54642, clear FileNameRole set by QFileSystemModel
#endif
d->proxy->setSourceModel(model);
if (d->popup)
setPopup(d->popup); // set the model and make new connections

View File

@ -757,8 +757,7 @@ bool QAbstractSpinBox::event(QEvent *event)
case QEvent::HoverEnter:
case QEvent::HoverLeave:
case QEvent::HoverMove:
if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
d->updateHoverControl(he->pos());
d->updateHoverControl(static_cast<const QHoverEvent *>(event)->pos());
break;
case QEvent::ShortcutOverride:
if (d->edit->event(event))

View File

@ -2108,9 +2108,9 @@ void QComboBoxPrivate::setCurrentIndex(const QModelIndex &mi)
if (lineEdit) {
const QString newText = itemText(normalized);
if (lineEdit->text() != newText) {
lineEdit->setText(newText);
lineEdit->setText(newText); // may cause lineEdit -> nullptr (QTBUG-54191)
#ifndef QT_NO_COMPLETER
if (lineEdit->completer())
if (lineEdit && lineEdit->completer())
lineEdit->completer()->setCompletionPrefix(newText);
#endif
}

View File

@ -40,6 +40,8 @@ class tst_QHashFunctions : public QObject
Q_OBJECT
private Q_SLOTS:
void qhash();
void qhash_of_empty_and_null_qstring();
void qhash_of_empty_and_null_qbytearray();
void fp_qhash_of_zero_is_zero();
void qthash_data();
void qthash();
@ -128,6 +130,20 @@ void tst_QHashFunctions::qhash()
}
}
void tst_QHashFunctions::qhash_of_empty_and_null_qstring()
{
QString null, empty("");
QCOMPARE(null, empty);
QCOMPARE(qHash(null), qHash(empty));
}
void tst_QHashFunctions::qhash_of_empty_and_null_qbytearray()
{
QByteArray null, empty("");
QCOMPARE(null, empty);
QCOMPARE(qHash(null), qHash(empty));
}
void tst_QHashFunctions::fp_qhash_of_zero_is_zero()
{
QCOMPARE(qHash(-0.0f), 0U);

View File

@ -35,6 +35,7 @@ class tst_QPair : public QObject
{
Q_OBJECT
private Q_SLOTS:
void pairOfReferences();
void testConstexpr();
void testConversions();
void taskQTBUG_48780_pairContainingCArray();
@ -91,6 +92,35 @@ Q_STATIC_ASSERT(!QTypeInfo<QPairPP>::isDummy );
Q_STATIC_ASSERT(!QTypeInfo<QPairPP>::isPointer);
void tst_QPair::pairOfReferences()
{
int i = 0;
QString s;
QPair<int&, QString&> p(i, s);
p.first = 1;
QCOMPARE(i, 1);
i = 2;
QCOMPARE(p.first, 2);
p.second = QLatin1String("Hello");
QCOMPARE(s, QLatin1String("Hello"));
s = QLatin1String("olleH");
QCOMPARE(p.second, QLatin1String("olleH"));
QPair<int&, QString&> q = p;
q.first = 3;
QCOMPARE(i, 3);
QCOMPARE(p.first, 3);
q.second = QLatin1String("World");
QCOMPARE(s, QLatin1String("World"));
QCOMPARE(p.second, QLatin1String("World"));
}
void tst_QPair::testConstexpr()
{
Q_CONSTEXPR QPair<int, double> pID = qMakePair(0, 0.0);

View File

@ -206,9 +206,9 @@ void tst_QRingBuffer::free()
ringBuffer.append(QByteArray("01234", 5));
ringBuffer.free(1);
QCOMPARE(ringBuffer.size(), Q_INT64_C(4095 + 2048 + 5));
QCOMPARE(ringBuffer.size(), Q_INT64_C(4095) + 2048 + 5);
ringBuffer.free(4096);
QCOMPARE(ringBuffer.size(), Q_INT64_C(2047 + 5));
QCOMPARE(ringBuffer.size(), Q_INT64_C(2047) + 5);
ringBuffer.free(48);
ringBuffer.free(2000);
QCOMPARE(ringBuffer.size(), Q_INT64_C(4));
@ -268,9 +268,9 @@ void tst_QRingBuffer::chop()
ringBuffer.reserve(4096);
ringBuffer.chop(1);
QCOMPARE(ringBuffer.size(), Q_INT64_C(5 + 2048 + 4095));
QCOMPARE(ringBuffer.size(), Q_INT64_C(5) + 2048 + 4095);
ringBuffer.chop(4096);
QCOMPARE(ringBuffer.size(), Q_INT64_C(5 + 2047));
QCOMPARE(ringBuffer.size(), Q_INT64_C(5) + 2047);
ringBuffer.chop(48);
ringBuffer.chop(2000);
QCOMPARE(ringBuffer.size(), Q_INT64_C(4));

View File

@ -356,7 +356,7 @@ private slots:
void replace_qchar_qstring();
void replace_uint_uint_data();
void replace_uint_uint();
void replace_uint_uint_extra();
void replace_extra();
void replace_string_data();
void replace_string();
void replace_regexp_data();
@ -479,6 +479,8 @@ private slots:
void sprintfS();
void fill();
void truncate();
void chop_data();
void chop();
void constructor();
void constructorQByteArray_data();
void constructorQByteArray();
@ -1219,6 +1221,31 @@ void tst_QString::truncate()
}
void tst_QString::chop_data()
{
QTest::addColumn<QString>("input");
QTest::addColumn<int>("count" );
QTest::addColumn<QString>("result");
const QString original("abcd");
QTest::newRow("data0") << original << 1 << QString("abc");
QTest::newRow("data1") << original << 0 << original;
QTest::newRow("data2") << original << -1 << original;
QTest::newRow("data3") << original << original.size() << QString();
QTest::newRow("data4") << original << 1000 << QString();
}
void tst_QString::chop()
{
QFETCH(QString, input);
QFETCH(int, count);
QFETCH(QString, result);
input.chop(count);
QCOMPARE(input, result);
}
void tst_QString::fill()
{
QString e;
@ -2784,7 +2811,7 @@ void tst_QString::replace_uint_uint()
}
}
void tst_QString::replace_uint_uint_extra()
void tst_QString::replace_extra()
{
/*
This test is designed to be extremely slow if QString::replace() doesn't optimize the case
@ -2821,6 +2848,44 @@ void tst_QString::replace_uint_uint_extra()
QString str5("abcdefghij");
str5.replace(8, 10, str5);
QCOMPARE(str5, QString("abcdefghabcdefghij"));
// Replacements using only part of the string modified:
QString str6("abcdefghij");
str6.replace(1, 8, str6.constData() + 3, 3);
QCOMPARE(str6, QString("adefj"));
QString str7("abcdefghibcdefghij");
str7.replace(str7.constData() + 1, 6, str7.constData() + 2, 3);
QCOMPARE(str7, QString("acdehicdehij"));
const int many = 1024;
/*
QS::replace(const QChar *, int, const QChar *, int, Qt::CaseSensitivity)
does its replacements in batches of many (please keep in sync with any
changes to batch size), which lead to misbehaviour if ether QChar * array
was part of the data being modified.
*/
QString str8("abcdefg"), ans8("acdeg");
{
// Make str8 and ans8 repeat themselves many + 1 times:
int i = many;
QString big(str8), small(ans8);
while (i && !(i & 1)) { // Exploit many being a power of 2:
big += big;
small += small;
i >>= 1;
}
while (i-- > 0) {
str8 += big;
ans8 += small;
}
}
str8.replace(str8.constData() + 1, 5, str8.constData() + 2, 3);
// Pre-test the bit where the diff happens, so it gets displayed:
QCOMPARE(str8.mid((many - 3) * 5), ans8.mid((many - 3) * 5));
// Also check the full values match, of course:
QCOMPARE(str8.size(), ans8.size());
QCOMPARE(str8, ans8);
}
void tst_QString::replace_string()

View File

@ -104,6 +104,7 @@ if isWindows:
exit()
tests = sys.argv[1:]
os.environ['LC_ALL'] = 'C'
if len(tests) == 0:
tests = subdirs()
print("Generating " + str(len(tests)) + " test results for: " + qtver + " in: " + rootPath)

View File

@ -1931,6 +1931,13 @@ void tst_Moc::warnings_data()
<< 1
<< QString("IGNORE_ALL_STDOUT")
<< QString(":2: Error: Macro invoked with too few parameters for a use of '#'");
QTest::newRow("QTBUG-54609: crash on invalid input")
<< QByteArray::fromBase64("EAkJCQkJbGFzcyBjbGFzcyBiYWkcV2kgTUEKcGYjZGVmaW5lIE1BKFEs/4D/FoQ=")
<< QStringList()
<< 1
<< QString("IGNORE_ALL_STDOUT")
<< QString(":-1: Error: Unexpected character in macro argument list.");
}
void tst_Moc::warnings()
@ -1946,7 +1953,7 @@ void tst_Moc::warnings()
#ifdef Q_CC_MSVC
// for some reasons, moc compiled with MSVC uses a different output format
QRegExp lineNumberRe(":(\\d+):");
QRegExp lineNumberRe(":(-?\\d+):");
lineNumberRe.setMinimal(true);
expectedStdErr.replace(lineNumberRe, "(\\1):");
#endif

View File

@ -594,6 +594,23 @@ void tst_qmakelib::addControlStructs()
<< ""
<< true;
QTest::newRow("function arguments")
<< "defineTest(func) {\n"
"defined(1, var) {\nd1 = 1\nexport(d1)\n}\n"
"defined(3, var) {\nd3 = 1\nexport(d3)\n}\n"
"x1 = $$1\nexport(x1)\n"
"2 += foo\nx2 = $$2\nexport(x2)\n"
"x3 = $$3\nexport(x3)\n"
"4 += foo\nx4 = $$4\nexport(x4)\n"
"x5 = $$5\nexport(x5)\n"
"6 += foo\nx6 = $$6\nexport(x6)\n"
"}\n"
"1 = first\n2 = second\n3 = third\n4 = fourth\nfunc(one, two)"
<< "1 = first\n2 = second\n3 = third\n4 = fourth\n5 = UNDEF\n6 = UNDEF\n"
"d1 = 1\nd3 = UNDEF\nx1 = one\nx2 = two foo\nx3 =\nx4 = foo\nx5 =\nx6 = foo"
<< ""
<< true;
QTest::newRow("ARGC and ARGS")
<< "defineTest(func) {\n"
"export(ARGC)\n"
@ -636,6 +653,86 @@ void tst_qmakelib::addControlStructs()
<< "VAR = final"
<< ""
<< true;
QTest::newRow("error() from replace function (assignment)")
<< "defineReplace(func) {\nerror(error)\n}\n"
"VAR = $$func()\n"
"OKE = 1"
<< "VAR = UNDEF\nOKE = UNDEF"
<< "Project ERROR: error"
<< false;
QTest::newRow("error() from replace function (replacement)")
<< "defineReplace(func) {\nerror(error)\n}\n"
"VAR = $$func()\n"
"OKE = 1"
<< "VAR = UNDEF\nOKE = UNDEF"
<< "Project ERROR: error"
<< false;
QTest::newRow("error() from replace function (LHS)")
<< "defineReplace(func) {\nerror(error)\nreturn(VAR)\n}\n"
"$$func() = 1\n"
"OKE = 1"
<< "VAR = UNDEF\nOKE = UNDEF"
<< "Project ERROR: error"
<< false;
QTest::newRow("error() from replace function (loop variable)")
<< "defineReplace(func) {\nerror(error)\nreturn(BLAH)\n}\n"
"for($$func()) {\nVAR = $$BLAH\nbreak()\n}\n"
"OKE = 1"
<< "VAR = UNDEF\nOKE = UNDEF"
<< "Project ERROR: error"
<< false;
QTest::newRow("error() from replace function (built-in test arguments)")
<< "defineReplace(func) {\nerror(error)\n}\n"
"message($$func()): VAR = 1\n"
"OKE = 1"
<< "VAR = UNDEF\nOKE = UNDEF"
<< "Project ERROR: error"
<< false;
QTest::newRow("error() from replace function (built-in replace arguments)")
<< "defineReplace(func) {\nerror(error)\n}\n"
"VAR = $$upper($$func())\n"
"OKE = 1"
<< "VAR = UNDEF\nOKE = UNDEF"
<< "Project ERROR: error"
<< false;
QTest::newRow("error() from replace function (custom test arguments)")
<< "defineReplace(func) {\nerror(error)\n}\n"
"defineTest(custom) {\n}\n"
"custom($$func()): VAR = 1\n"
"OKE = 1"
<< "VAR = UNDEF\nOKE = UNDEF"
<< "Project ERROR: error"
<< false;
QTest::newRow("error() from replace function (custom replace arguments)")
<< "defineReplace(func) {\nerror(error)\nreturn(1)\n}\n"
"defineReplace(custom) {\nreturn($$1)\n}\n"
"VAR = $$custom($$func(1))\n"
"OKE = 1"
<< "VAR = UNDEF\nOKE = UNDEF"
<< "Project ERROR: error"
<< false;
QTest::newRow("REQUIRES = error()")
<< "REQUIRES = error(error)\n"
"OKE = 1"
<< "OKE = UNDEF"
<< "Project ERROR: error"
<< false;
QTest::newRow("requires(error())")
<< "requires(error(error))\n"
"OKE = 1"
<< "OKE = UNDEF"
<< "Project ERROR: error"
<< false;
}
void tst_qmakelib::addReplaceFunctions(const QString &qindir)
@ -2098,6 +2195,12 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
<< "Project ERROR: World, you FAIL!"
<< false;
QTest::newRow("if(error())")
<< "if(error(\\'World, you FAIL!\\')): OK = 1\nOKE = 1"
<< "OK = UNDEF\nOKE = UNDEF"
<< "Project ERROR: World, you FAIL!"
<< false;
QTest::newRow("system()")
<< "system('"
#ifdef Q_OS_WIN
@ -2374,6 +2477,14 @@ void tst_qmakelib::proEval_data()
"Project MESSAGE: assign split joined: word: this is a test:done\n"
"Project MESSAGE: assign split quoted: word this is a test done"
<< true;
// Raw data leak with empty file name. Verify with Valgrind or asan.
QTest::newRow("QTBUG-54550")
<< "FULL = /there/is\n"
"VAR = $$absolute_path(, $$FULL/nothing/here/really)"
<< "VAR = /there/is/nothing/here/really"
<< ""
<< true;
}
static QString formatValue(const ProStringList &vals)

View File

@ -1867,6 +1867,13 @@ void tst_qmakelib::addParseAbuse()
/* 24 */ /* else branch */ << I(0))
<< "in:1: OR operator without prior condition."
<< false;
// Token buffer overflow. Verify with Valgrind or asan.
QTest::newRow("QTCREATORBUG-16508")
<< "a{b{c{d{"
<< TS()
<< "in:2: Missing closing brace(s)."
<< false;
}
void tst_qmakelib::proParser_data()

View File

@ -286,8 +286,8 @@ retry:
// Testing get/set functions
void tst_QCompleter::getSetCheck()
{
QStandardItemModel model(3,3);
QCompleter completer(&model);
QStandardItemModel standardItemModel(3,3);
QCompleter completer(&standardItemModel);
// QString QCompleter::completionPrefix()
// void QCompleter::setCompletionPrefix(QString)
@ -347,6 +347,21 @@ void tst_QCompleter::getSetCheck()
QCOMPARE(completer.wrapAround(), true); // default value
completer.setWrapAround(false);
QCOMPARE(completer.wrapAround(), false);
#ifndef QT_NO_FILESYSTEMMODEL
// QTBUG-54642, changing from QFileSystemModel to another model should restore role.
completer.setCompletionRole(Qt::EditRole);
QCOMPARE(completer.completionRole(), static_cast<int>(Qt::EditRole)); // default value
QFileSystemModel fileSystemModel;
completer.setModel(&fileSystemModel);
QCOMPARE(completer.completionRole(), static_cast<int>(QFileSystemModel::FileNameRole));
completer.setModel(&standardItemModel);
QCOMPARE(completer.completionRole(), static_cast<int>(Qt::EditRole));
completer.setCompletionRole(Qt::ToolTipRole);
QStandardItemModel standardItemModel2(2, 2); // Do not clobber a custom role when changing models
completer.setModel(&standardItemModel2);
QCOMPARE(completer.completionRole(), static_cast<int>(Qt::ToolTipRole));
#endif // QT_NO_FILESYSTEMMODEL
}
void tst_QCompleter::csMatchingOnCsSortedModel_data()

View File

@ -156,6 +156,7 @@ private slots:
void itemData();
void task_QTBUG_31146_popupCompletion();
void task_QTBUG_41288_completerChangesCurrentIndex();
void task_QTBUG_54191_slotOnEditTextChangedSetsComboBoxToReadOnly();
void keyboardSelection();
void setCustomModelAndView();
void updateDelegateOnEditableChange();
@ -3121,6 +3122,30 @@ void tst_QComboBox::task_QTBUG_41288_completerChangesCurrentIndex()
}
}
namespace {
struct SetReadOnly {
QComboBox *cb;
explicit SetReadOnly(QComboBox *cb) : cb(cb) {}
void operator()() const
{ cb->setEditable(false); }
};
}
void tst_QComboBox::task_QTBUG_54191_slotOnEditTextChangedSetsComboBoxToReadOnly()
{
QComboBox cb;
cb.addItems(QStringList() << "one" << "two");
cb.setEditable(true);
cb.setCurrentIndex(0);
connect(&cb, &QComboBox::editTextChanged,
SetReadOnly(&cb));
cb.setCurrentIndex(1);
// the real test is that it didn't crash...
QCOMPARE(cb.currentIndex(), 1);
}
void tst_QComboBox::keyboardSelection()
{
QComboBox comboBox;