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(); m_vectors.clear();
QMatrix m; QMatrix m;
qreal rot = 360 / count; qreal rot = 360.0 / count;
QPointF center(width() / 2, height() / 2); QPointF center(width() / 2, height() / 2);
QMatrix vm; QMatrix vm;
vm.shear(2, -1); vm.shear(2, -1);

View File

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

View File

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

View File

@ -156,7 +156,7 @@ for(ever) {
!isEmpty(var_sfx): break() !isEmpty(var_sfx): break()
var_sfx = _PRIVATE 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("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("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!") 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): \ for(inst, DOC_TARGETS): \
prepareRecursiveTarget($$inst) prepareRecursiveTarget($$inst)
} else { } else {
debug_and_release:!build_pass { !isEmpty(BUILDS):!build_pass {
sub = $$first(BUILDS) sub = $$first(BUILDS)
for(inst, DOC_TARGETS) { for(inst, DOC_TARGETS) {
$${inst}.CONFIG = recursive $${inst}.CONFIG = recursive

View File

@ -259,7 +259,10 @@ defineReplace(pkgConfigExecutable) {
} }
defineTest(packagesExist) { 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 # 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 # 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 resource_file = $$RCC_DIR/qmake_$${resource}.qrc
!debug_and_release|build_pass { isEmpty(BUILDS)|build_pass {
# Collection of files, generate qrc file # Collection of files, generate qrc file
prefix = $$eval($${resource}.prefix) prefix = $$eval($${resource}.prefix)
isEmpty(prefix): \ isEmpty(prefix): \

View File

@ -17,9 +17,26 @@ QMAKE_LIBDIR_X11 = /usr/X11R6/lib
QMAKE_INCDIR_OPENGL = /usr/X11R6/include QMAKE_INCDIR_OPENGL = /usr/X11R6/include
QMAKE_LIBDIR_OPENGL = /usr/X11R6/lib QMAKE_LIBDIR_OPENGL = /usr/X11R6/lib
QMAKE_RPATHDIR += $$QMAKE_LIBDIR_X11
include(../common/gcc-base-unix.conf) include(../common/gcc-base-unix.conf)
include(../common/g++-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 # Reset g++-unix.conf's NOUNDEF flags as OpenBSD libc can't handle environ
QMAKE_LFLAGS_NOUNDEF = QMAKE_LFLAGS_NOUNDEF =

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -71,12 +71,12 @@
#elif defined(Q_OS_HAIKU) #elif defined(Q_OS_HAIKU)
# include <kernel/OS.h> # include <kernel/OS.h>
#elif defined(Q_OS_BSD4) && !defined(Q_OS_IOS) #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/cdefs.h>
# include <sys/param.h> # include <sys/param.h>
# include <sys/sysctl.h> # include <sys/sysctl.h>
# if !defined(Q_OS_NETBSD)
# include <sys/user.h>
# endif
#endif #endif
QT_BEGIN_NAMESPACE 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); 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 \internal
*/ */
void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar *after, int alen) 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 // Copy after if it lies inside our own d->data() area (which we could
// (which we could possibly invalidate via a realloc or corrupt via memcpy operations.) // possibly invalidate via a realloc or modify by replacement).
QChar *afterBuffer = const_cast<QChar *>(after); QChar *afterBuffer = 0;
if (after >= reinterpret_cast<QChar *>(d->data()) && after < reinterpret_cast<QChar *>(d->data()) + d->size) { if (pointsIntoRange(after, d->data(), d->size)) // Use copy in place of vulnerable original:
afterBuffer = static_cast<QChar *>(::malloc(alen*sizeof(QChar))); after = afterBuffer = textCopy(after, alen);
Q_CHECK_PTR(afterBuffer);
::memcpy(afterBuffer, after, alen*sizeof(QChar));
}
QT_TRY { QT_TRY {
if (blen == alen) { if (blen == alen) {
// replace in place // replace in place
detach(); detach();
for (int i = 0; i < nIndices; ++i) 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) { } else if (alen < blen) {
// replace from front // replace from front
detach(); detach();
@ -2446,7 +2460,7 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
to += msize; to += msize;
} }
if (alen) { if (alen) {
memcpy(d->data() + to, afterBuffer, alen*sizeof(QChar)); memcpy(d->data() + to, after, alen * sizeof(QChar));
to += alen; to += alen;
} }
movestart = indices[i] + blen; movestart = indices[i] + blen;
@ -2469,17 +2483,15 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
int moveto = insertstart + alen; int moveto = insertstart + alen;
memmove(d->data() + moveto, d->data() + movestart, memmove(d->data() + moveto, d->data() + movestart,
(moveend - movestart)*sizeof(QChar)); (moveend - movestart)*sizeof(QChar));
memcpy(d->data() + insertstart, afterBuffer, alen*sizeof(QChar)); memcpy(d->data() + insertstart, after, alen * sizeof(QChar));
moveend = movestart-blen; moveend = movestart-blen;
} }
} }
} QT_CATCH(const std::bad_alloc &) { } QT_CATCH(const std::bad_alloc &) {
if (afterBuffer != after) ::free(afterBuffer);
::free(afterBuffer);
QT_RETHROW; QT_RETHROW;
} }
if (afterBuffer != after) ::free(afterBuffer);
::free(afterBuffer);
} }
/*! /*!
@ -2508,31 +2520,48 @@ QString &QString::replace(const QChar *before, int blen,
return *this; return *this;
QStringMatcher matcher(before, blen, cs); QStringMatcher matcher(before, blen, cs);
QChar *beforeBuffer = 0, *afterBuffer = 0;
int index = 0; int index = 0;
while (1) { while (1) {
uint indices[1024]; uint indices[1024];
uint pos = 0; uint pos = 0;
while (pos < 1023) { while (pos < 1024) {
index = matcher.indexIn(*this, index); index = matcher.indexIn(*this, index);
if (index == -1) if (index == -1)
break; break;
indices[pos++] = index; indices[pos++] = index;
index += blen; if (blen) // Step over before:
// avoid infinite loop index += blen;
if (!blen) else // Only count one instance of empty between any two characters:
index++; index++;
} }
if (!pos) if (!pos) // Nothing to replace
break; 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); replace_helper(indices, pos, blen, after, alen);
if (index == -1) if (Q_LIKELY(index == -1)) // Nothing left to replace
break; 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); index += pos*(alen-blen);
} }
::free(afterBuffer);
::free(beforeBuffer);
return *this; return *this;
} }
@ -2563,26 +2592,26 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
uint indices[1024]; uint indices[1024];
uint pos = 0; uint pos = 0;
if (cs == Qt::CaseSensitive) { if (cs == Qt::CaseSensitive) {
while (pos < 1023 && index < d->size) { while (pos < 1024 && index < d->size) {
if (d->data()[index] == cc) if (d->data()[index] == cc)
indices[pos++] = index; indices[pos++] = index;
index++; index++;
} }
} else { } else {
while (pos < 1023 && index < d->size) { while (pos < 1024 && index < d->size) {
if (QChar::toCaseFolded(d->data()[index]) == cc) if (QChar::toCaseFolded(d->data()[index]) == cc)
indices[pos++] = index; indices[pos++] = index;
index++; index++;
} }
} }
if (!pos) if (!pos) // Nothing to replace
break; break;
replace_helper(indices, pos, 1, after.constData(), after.d->size); replace_helper(indices, pos, 1, after.constData(), after.d->size);
if (index == -1) if (Q_LIKELY(index == -1)) // Nothing left to replace
break; 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); index += pos*(after.d->size - 1);
} }
return *this; return *this;
@ -5008,7 +5037,7 @@ void QString::truncate(int pos)
Removes \a n characters from the end of the string. Removes \a n characters from the end of the string.
If \a n is greater than or equal to size(), the result is an 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: Example:
\snippet qstring/main.cpp 15 \snippet qstring/main.cpp 15

View File

@ -82,7 +82,7 @@ struct QStringBuilderCommon
T toLower() const { return resolved().toLower(); } T toLower() const { return resolved().toLower(); }
protected: 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> template<typename Builder, typename T>

View File

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

View File

@ -758,7 +758,7 @@ void QAccessible::deleteAccessibleInterface(Id id)
*/ */
QAccessible::Id QAccessible::uniqueId(QAccessibleInterface *iface) QAccessible::Id QAccessible::uniqueId(QAccessibleInterface *iface)
{ {
Id id = QAccessibleCache::instance()->idToInterface.key(iface); Id id = QAccessibleCache::instance()->idForInterface(iface);
if (!id) if (!id)
id = registerAccessibleInterface(iface); id = registerAccessibleInterface(iface);
return id; return id;
@ -771,7 +771,7 @@ QAccessible::Id QAccessible::uniqueId(QAccessibleInterface *iface)
*/ */
QAccessibleInterface *QAccessible::accessibleInterface(Id id) 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); return idToInterface.value(id);
} }
QAccessible::Id QAccessibleCache::idForInterface(QAccessibleInterface *iface) const
{
return interfaceToId.value(iface);
}
QAccessible::Id QAccessibleCache::insert(QObject *object, QAccessibleInterface *iface) const QAccessible::Id QAccessibleCache::insert(QObject *object, QAccessibleInterface *iface) const
{ {
Q_ASSERT(iface); Q_ASSERT(iface);
@ -90,7 +95,7 @@ QAccessible::Id QAccessibleCache::insert(QObject *object, QAccessibleInterface *
// object might be 0 // object might be 0
Q_ASSERT(!objectToId.contains(object)); 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(); QAccessible::Id id = acquireId();
QObject *obj = iface->object(); QObject *obj = iface->object();
@ -100,6 +105,7 @@ QAccessible::Id QAccessibleCache::insert(QObject *object, QAccessibleInterface *
connect(obj, &QObject::destroyed, this, &QAccessibleCache::objectDestroyed); connect(obj, &QObject::destroyed, this, &QAccessibleCache::objectDestroyed);
} }
idToInterface.insert(id, iface); idToInterface.insert(id, iface);
interfaceToId.insert(iface, id);
return id; return id;
} }
@ -115,6 +121,7 @@ void QAccessibleCache::objectDestroyed(QObject* obj)
void QAccessibleCache::deleteInterface(QAccessible::Id id, QObject *obj) void QAccessibleCache::deleteInterface(QAccessible::Id id, QObject *obj)
{ {
QAccessibleInterface *iface = idToInterface.take(id); QAccessibleInterface *iface = idToInterface.take(id);
interfaceToId.take(iface);
if (!obj) if (!obj)
obj = iface->object(); obj = iface->object();
if (obj) if (obj)

View File

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

View File

@ -3331,28 +3331,6 @@ bool QGuiApplication::isSavingSession() const
return d->is_saving_session; 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() void QGuiApplicationPrivate::commitData()
{ {
Q_Q(QGuiApplication); Q_Q(QGuiApplication);
@ -3377,6 +3355,28 @@ void QGuiApplicationPrivate::saveState()
} }
#endif //QT_NO_SESSIONMANAGER #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 \property QGuiApplication::layoutDirection
\brief the default layout direction for this application \brief the default layout direction for this application
@ -3623,7 +3623,8 @@ QPixmap QGuiApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
void QGuiApplicationPrivate::notifyThemeChanged() void QGuiApplicationPrivate::notifyThemeChanged()
{ {
if (!(applicationResourceFlags & ApplicationPaletteExplicitlySet)) { if (!(applicationResourceFlags & ApplicationPaletteExplicitlySet) &&
!QCoreApplication::testAttribute(Qt::AA_SetPalette)) {
clearPalette(); clearPalette();
initPalette(); 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)); const char *ver = reinterpret_cast<const char *>(funcs->glGetString(GL_VERSION));
// Blacklist GPU chipsets that have problems with their BGRA support. // Blacklist GPU chipsets that have problems with their BGRA support.
#ifndef Q_OS_IOS
const bool blackListed = (qstrcmp(renderer, "PowerVR Rogue G6200") == 0 const bool blackListed = (qstrcmp(renderer, "PowerVR Rogue G6200") == 0
&& ::strstr(ver, "1.3") != 0) || && ::strstr(ver, "1.3") != 0) ||
(qstrcmp(renderer, "Mali-T760") == 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 (qstrcmp(renderer, "Mali-T720") == 0
&& ::strstr(ver, "3.1") != 0) || && ::strstr(ver, "3.1") != 0) ||
qstrcmp(renderer, "PowerVR SGX 554") == 0; qstrcmp(renderer, "PowerVR SGX 554") == 0;
#else
const bool blackListed = true;
#endif
const bool supports_bgra = has_bgra_ext && !blackListed; const bool supports_bgra = has_bgra_ext && !blackListed;
if (supports_bgra) { if (supports_bgra) {

View File

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

View File

@ -583,7 +583,7 @@ void QSslSocketBackendPrivate::startClientEncryption()
// Error description/code were set, 'error' emitted // Error description/code were set, 'error' emitted
// by initSslContext, but OpenSSL socket also sets error // by initSslContext, but OpenSSL socket also sets error
// emits a signal twice, so ... // emits a signal twice, so ...
setErrorAndEmit(QAbstractSocket::SslInternalError, "Unable to init SSL Context"); setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
return; return;
} }
@ -596,7 +596,7 @@ void QSslSocketBackendPrivate::startServerEncryption()
// Error description/code were set, 'error' emitted // Error description/code were set, 'error' emitted
// by initSslContext, but OpenSSL socket also sets error // by initSslContext, but OpenSSL socket also sets error
// emits a signal twice, so ... // emits a signal twice, so ...
setErrorAndEmit(QAbstractSocket::SslInternalError, "Unable to init SSL Context"); setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Unable to init SSL Context"));
return; return;
} }
@ -927,7 +927,7 @@ bool QSslSocketBackendPrivate::initSslContext()
context.reset(qt_createSecureTransportContext(mode)); context.reset(qt_createSecureTransportContext(mode));
if (!context) { if (!context) {
setErrorAndEmit(QAbstractSocket::SslInternalError, "SSLCreateContext failed"); setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("SSLCreateContext failed"));
return false; return false;
} }
@ -955,7 +955,7 @@ bool QSslSocketBackendPrivate::initSslContext()
if (!setSessionProtocol()) { if (!setSessionProtocol()) {
destroySslContext(); destroySslContext();
setErrorAndEmit(QAbstractSocket::SslInternalError, "Failed to set protocol version"); setErrorAndEmit(QAbstractSocket::SslInternalError, QStringLiteral("Failed to set protocol version"));
return false; return false;
} }
@ -1397,8 +1397,7 @@ bool QSslSocketBackendPrivate::startHandshake()
// check protocol version ourselves, as Secure Transport does not enforce // check protocol version ourselves, as Secure Transport does not enforce
// the requested min / max versions. // the requested min / max versions.
if (!verifySessionProtocol()) { if (!verifySessionProtocol()) {
setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, setErrorAndEmit(QAbstractSocket::SslHandshakeFailedError, QStringLiteral("Protocol version mismatch"));
"Protocol version mismatch");
plainSocket->disconnectFromHost(); plainSocket->disconnectFromHost();
return false; 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 // I can only handle two types (system and unicode) so deal with them that way
QVariant ret; QVariant ret;
if (flavor == QLatin1String("public.utf8-plain-text")) { if (flavor == QLatin1String("public.utf8-plain-text")) {
ret = QString(QCFString(CFStringCreateWithBytes(kCFAllocatorDefault, ret = QString::fromUtf8(firstData);
reinterpret_cast<const UInt8 *>(firstData.constData()),
firstData.size(), CFStringGetSystemEncoding(), false)));
} else if (flavor == QLatin1String("public.utf16-plain-text")) { } else if (flavor == QLatin1String("public.utf16-plain-text")) {
ret = QString(reinterpret_cast<const QChar *>(firstData.constData()), ret = QString(reinterpret_cast<const QChar *>(firstData.constData()),
firstData.size() / sizeof(QChar)); firstData.size() / sizeof(QChar));

View File

@ -594,8 +594,7 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
fallbackList.append(familyNameFromPostScriptName(item)); 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 // 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 // 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; synthesisFlags = 0;
CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont); CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
#if defined(Q_OS_IOS) || MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 if (traits & kCTFontColorGlyphsTrait)
if (supportsColorGlyphs() && (traits & kCTFontColorGlyphsTrait))
glyphFormat = QFontEngine::Format_ARGB; glyphFormat = QFontEngine::Format_ARGB;
else else
#endif
glyphFormat = defaultGlyphFormat; glyphFormat = defaultGlyphFormat;
if (traits & kCTFontItalicTrait) 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); CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &CGSizeZero, 1); CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &CGSizeZero, 1);
} }
} } else {
#if defined(Q_OS_IOS) || MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
else if (supportsColorGlyphs()) {
// CGContextSetTextMatrix does not work with color glyphs, so we use // CGContextSetTextMatrix does not work with color glyphs, so we use
// the CTM instead. This means we must translate the CTM as well, to // the CTM instead. This means we must translate the CTM as well, to
// set the glyph position, instead of using CGContextSetTextPosition. // 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. // glyphs in the Apple Color Emoji font, so we use CTFontDrawGlyphs instead.
CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx); CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx);
} }
#endif
CGContextRelease(ctx); CGContextRelease(ctx);
CGColorSpaceRelease(colorspace); CGColorSpaceRelease(colorspace);

View File

@ -113,21 +113,6 @@ public:
QFontEngine::Properties properties() const Q_DECL_OVERRIDE; 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 bool ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length);
static QFont::Weight qtWeightFromCFWeight(float value); static QFont::Weight qtWeightFromCFWeight(float value);

View File

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

View File

@ -457,6 +457,10 @@ QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
if (index >= mScreens.count()) if (index >= mScreens.count())
updateScreens(); 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); return mScreens.at(index);
} }

View File

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

View File

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

View File

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

View File

@ -260,34 +260,14 @@ QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
} }
if (iconType != 0) { if (iconType != 0) {
QPixmap pixmap; QPixmap pixmap;
IconRef icon; IconRef icon = Q_NULLPTR;
IconRef overlayIcon = 0; GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon);
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);
}
}
if (icon) { if (icon) {
pixmap = qt_mac_convert_iconref(icon, size.width(), size.height()); pixmap = qt_mac_convert_iconref(icon, size.width(), size.height());
ReleaseIconRef(icon); 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; return pixmap;
} }

View File

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

View File

@ -11,7 +11,7 @@ HEADERS = qminimalintegration.h \
OTHER_FILES += minimal.json OTHER_FILES += minimal.json
CONFIG += qpa/genericunixfontdatabase CONFIG += qpa/genericunixfontdatabase
darwin: DEFINES += QT_NO_FONTCONFIG win32|darwin: DEFINES += QT_NO_FONTCONFIG
PLUGIN_TYPE = platforms PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QMinimalIntegrationPlugin 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 // When having a raster window we don't need any buffers, since
// Qt will draw to the parent TLW backing store. // 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()) if (windowSize != bufferSize())
setBufferSize(windowSize); setBufferSize(windowSize);
} }
@ -194,6 +194,13 @@ void QQnxRasterWindow::resetBuffers()
m_currentBufferIndex = -1; m_currentBufferIndex = -1;
m_previousDirty = QRegion(); m_previousDirty = QRegion();
m_scrolled = 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) 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 // Set the transparency. According to QNX technical support, setting the window
// transparency property should always be done *after* creating the window // transparency property should always be done *after* creating the window
// buffers in order to guarantee the property is paid attention to. // 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 // To avoid overhead in the composition manager, disable blending
// when the underlying window buffer doesn't have an alpha channel. // when the underlying window buffer doesn't have an alpha channel.
val[0] = SCREEN_TRANSPARENCY_NONE; val[0] = SCREEN_TRANSPARENCY_NONE;

View File

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

View File

@ -53,7 +53,7 @@
#include <QtGui/QGuiApplication> #include <QtGui/QGuiApplication>
#include <QtGui/QWindow> #include <QtGui/QWindow>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QScopedArrayPointer> #include <QtCore/QVarLengthArray>
#include <QtCore/QtMath> #include <QtCore/QtMath>
#include <private/qguiapplication_p.h> #include <private/qguiapplication_p.h>
@ -233,7 +233,7 @@ QString QWindowsTabletSupport::description() const
const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0); const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0);
if (!size) if (!size)
return QString(); return QString();
QScopedPointer<TCHAR> winTabId(new TCHAR[size + 1]); QVarLengthArray<TCHAR> winTabId(size + 1);
m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, winTabId.data()); m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, winTabId.data());
WORD implementationVersion = 0; WORD implementationVersion = 0;
m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_IMPLVERSION, &implementationVersion); 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_fonts, m_fonts + NFonts, static_cast<QFont *>(0));
std::fill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0)); std::fill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0));
refresh(); refresh();
refreshIconPixmapSizes();
} }
QWindowsTheme::~QWindowsTheme() QWindowsTheme::~QWindowsTheme()
@ -400,16 +401,8 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const
return QVariant(int(WindowsKeyboardScheme)); return QVariant(int(WindowsKeyboardScheme));
case UiEffects: case UiEffects:
return QVariant(uiEffects()); return QVariant(uiEffects());
case IconPixmapSizes: { case IconPixmapSizes:
QList<int> sizes; return m_fileIconSizes;
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 DialogSnapToDefaultButton: case DialogSnapToDefaultButton:
return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON, false)); return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON, false));
case ContextMenuOnMouseRelease: case ContextMenuOnMouseRelease:
@ -479,6 +472,15 @@ void QWindowsTheme::refreshFonts()
#endif // !Q_OS_WINCE #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 bool QWindowsTheme::usePlatformNativeDialog(DialogType type) const
{ {
return QWindowsDialogs::useHelper(type); return QWindowsDialogs::useHelper(type);
@ -495,6 +497,27 @@ void QWindowsTheme::windowsThemeChanged(QWindow * window)
QWindowSystemInterface::handleThemeChange(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 // Defined in qpixmap_win.cpp
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon); Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon);
@ -741,10 +764,12 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s
QPixmap pixmap; QPixmap pixmap;
const QString filePath = QDir::toNativeSeparators(fileInfo.filePath()); const QString filePath = QDir::toNativeSeparators(fileInfo.filePath());
const int width = int(size.width()); 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 = const int requestedImageListSize =
#ifdef USE_IIMAGELIST #ifdef USE_IIMAGELIST
width > 48 ? sHIL_JUMBO : (width > 32 ? sHIL_EXTRALARGE : 0); width > fileIconSizes[ExtraLargeFileIcon]
? sHIL_JUMBO
: (width > fileIconSizes[LargeFileIcon] ? sHIL_EXTRALARGE : 0);
#else #else
0; 0;
#endif // !USE_IIMAGELIST #endif // !USE_IIMAGELIST

View File

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

View File

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

View File

@ -265,8 +265,8 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
} else { } else {
screen = createScreen(virtualDesktop, output, outputInfo.data()); screen = createScreen(virtualDesktop, output, outputInfo.data());
qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled"; qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled";
QHighDpiScaling::updateHighDpiScaling();
} }
QHighDpiScaling::updateHighDpiScaling();
} }
} else if (screen) { } else if (screen) {
if (output.crtc == XCB_NONE && output.mode == XCB_NONE) { 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) 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)))); 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) 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) 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) 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) 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) 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) 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) 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; token = keywords[state].ident;
if (token == NOTOKEN) { if (token == NOTOKEN) {
++data; if (*data)
++data;
// an error really, but let's ignore this input // an error really, but let's ignore this input
// to not confuse moc later. However in pre-processor // to not confuse moc later. However in pre-processor
// only mode let's continue. // only mode let's continue.
@ -362,7 +363,6 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
++data; ++data;
continue; continue;
} }
int nextindex = pp_keywords[state].next; int nextindex = pp_keywords[state].next;
int next = 0; int next = 0;
if (*data == pp_keywords[state].defchar) if (*data == pp_keywords[state].defchar)
@ -381,7 +381,8 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
switch (token) { switch (token) {
case NOTOKEN: case NOTOKEN:
++data; if (*data)
++data;
break; break;
case PP_DEFINE: case PP_DEFINE:
mode = PrepareDefine; mode = PrepareDefine;
@ -1255,7 +1256,6 @@ void Preprocessor::parseDefineArguments(Macro *m)
error("missing ')' in macro argument list"); error("missing ')' in macro argument list");
break; break;
} else if (!is_identifier(l.constData(), l.length())) { } else if (!is_identifier(l.constData(), l.length())) {
qDebug() << l;
error("Unexpected character in macro argument list."); 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 // The Windows compositor handles fullscreen OpenGL window specially. Besides
// having trouble with popups, it also has issues with flip-flopping between // having trouble with popups, it also has issues with flip-flopping between
// OpenGL-based and normal flushing. Therefore, stick with GL for fullscreen // 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) #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE)
|| tlw->windowState().testFlag(Qt::WindowFullScreen) || tlw->windowState().testFlag(Qt::WindowFullScreen)
|| tlw->testAttribute(Qt::WA_TranslucentBackground)
#endif #endif
) )
{ {

View File

@ -2935,7 +2935,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
QImage img; QImage img;
QSize pixmapSize = opt->rect.size(); QSize pixmapSize = opt->rect.size();
if (pixmapSize.isValid()) { if (!pixmapSize.isEmpty()) {
QPixmap pix(pixmapSize); QPixmap pix(pixmapSize);
pix.fill(QColor(fillR, fillG, fillB)); pix.fill(QColor(fillR, fillG, fillB));
QPainter pix_paint(&pix); 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_None Indicates that the widget does not have a state.
\value State_Active Indicates that the widget is active. \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_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_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. \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); Q_D(QCompleter);
QAbstractItemModel *oldModel = d->proxy->sourceModel(); 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); d->proxy->setSourceModel(model);
if (d->popup) if (d->popup)
setPopup(d->popup); // set the model and make new connections 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::HoverEnter:
case QEvent::HoverLeave: case QEvent::HoverLeave:
case QEvent::HoverMove: case QEvent::HoverMove:
if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event)) d->updateHoverControl(static_cast<const QHoverEvent *>(event)->pos());
d->updateHoverControl(he->pos());
break; break;
case QEvent::ShortcutOverride: case QEvent::ShortcutOverride:
if (d->edit->event(event)) if (d->edit->event(event))

View File

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

View File

@ -40,6 +40,8 @@ class tst_QHashFunctions : public QObject
Q_OBJECT Q_OBJECT
private Q_SLOTS: private Q_SLOTS:
void qhash(); void qhash();
void qhash_of_empty_and_null_qstring();
void qhash_of_empty_and_null_qbytearray();
void fp_qhash_of_zero_is_zero(); void fp_qhash_of_zero_is_zero();
void qthash_data(); void qthash_data();
void qthash(); 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() void tst_QHashFunctions::fp_qhash_of_zero_is_zero()
{ {
QCOMPARE(qHash(-0.0f), 0U); QCOMPARE(qHash(-0.0f), 0U);

View File

@ -35,6 +35,7 @@ class tst_QPair : public QObject
{ {
Q_OBJECT Q_OBJECT
private Q_SLOTS: private Q_SLOTS:
void pairOfReferences();
void testConstexpr(); void testConstexpr();
void testConversions(); void testConversions();
void taskQTBUG_48780_pairContainingCArray(); void taskQTBUG_48780_pairContainingCArray();
@ -91,6 +92,35 @@ Q_STATIC_ASSERT(!QTypeInfo<QPairPP>::isDummy );
Q_STATIC_ASSERT(!QTypeInfo<QPairPP>::isPointer); 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() void tst_QPair::testConstexpr()
{ {
Q_CONSTEXPR QPair<int, double> pID = qMakePair(0, 0.0); 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.append(QByteArray("01234", 5));
ringBuffer.free(1); ringBuffer.free(1);
QCOMPARE(ringBuffer.size(), Q_INT64_C(4095 + 2048 + 5)); QCOMPARE(ringBuffer.size(), Q_INT64_C(4095) + 2048 + 5);
ringBuffer.free(4096); ringBuffer.free(4096);
QCOMPARE(ringBuffer.size(), Q_INT64_C(2047 + 5)); QCOMPARE(ringBuffer.size(), Q_INT64_C(2047) + 5);
ringBuffer.free(48); ringBuffer.free(48);
ringBuffer.free(2000); ringBuffer.free(2000);
QCOMPARE(ringBuffer.size(), Q_INT64_C(4)); QCOMPARE(ringBuffer.size(), Q_INT64_C(4));
@ -268,9 +268,9 @@ void tst_QRingBuffer::chop()
ringBuffer.reserve(4096); ringBuffer.reserve(4096);
ringBuffer.chop(1); ringBuffer.chop(1);
QCOMPARE(ringBuffer.size(), Q_INT64_C(5 + 2048 + 4095)); QCOMPARE(ringBuffer.size(), Q_INT64_C(5) + 2048 + 4095);
ringBuffer.chop(4096); ringBuffer.chop(4096);
QCOMPARE(ringBuffer.size(), Q_INT64_C(5 + 2047)); QCOMPARE(ringBuffer.size(), Q_INT64_C(5) + 2047);
ringBuffer.chop(48); ringBuffer.chop(48);
ringBuffer.chop(2000); ringBuffer.chop(2000);
QCOMPARE(ringBuffer.size(), Q_INT64_C(4)); QCOMPARE(ringBuffer.size(), Q_INT64_C(4));

View File

@ -356,7 +356,7 @@ private slots:
void replace_qchar_qstring(); void replace_qchar_qstring();
void replace_uint_uint_data(); void replace_uint_uint_data();
void replace_uint_uint(); void replace_uint_uint();
void replace_uint_uint_extra(); void replace_extra();
void replace_string_data(); void replace_string_data();
void replace_string(); void replace_string();
void replace_regexp_data(); void replace_regexp_data();
@ -479,6 +479,8 @@ private slots:
void sprintfS(); void sprintfS();
void fill(); void fill();
void truncate(); void truncate();
void chop_data();
void chop();
void constructor(); void constructor();
void constructorQByteArray_data(); void constructorQByteArray_data();
void constructorQByteArray(); 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() void tst_QString::fill()
{ {
QString e; 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 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"); QString str5("abcdefghij");
str5.replace(8, 10, str5); str5.replace(8, 10, str5);
QCOMPARE(str5, QString("abcdefghabcdefghij")); 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() void tst_QString::replace_string()

View File

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

View File

@ -1931,6 +1931,13 @@ void tst_Moc::warnings_data()
<< 1 << 1
<< QString("IGNORE_ALL_STDOUT") << QString("IGNORE_ALL_STDOUT")
<< QString(":2: Error: Macro invoked with too few parameters for a use of '#'"); << 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() void tst_Moc::warnings()
@ -1946,7 +1953,7 @@ void tst_Moc::warnings()
#ifdef Q_CC_MSVC #ifdef Q_CC_MSVC
// for some reasons, moc compiled with MSVC uses a different output format // for some reasons, moc compiled with MSVC uses a different output format
QRegExp lineNumberRe(":(\\d+):"); QRegExp lineNumberRe(":(-?\\d+):");
lineNumberRe.setMinimal(true); lineNumberRe.setMinimal(true);
expectedStdErr.replace(lineNumberRe, "(\\1):"); expectedStdErr.replace(lineNumberRe, "(\\1):");
#endif #endif

View File

@ -594,6 +594,23 @@ void tst_qmakelib::addControlStructs()
<< "" << ""
<< true; << 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") QTest::newRow("ARGC and ARGS")
<< "defineTest(func) {\n" << "defineTest(func) {\n"
"export(ARGC)\n" "export(ARGC)\n"
@ -636,6 +653,86 @@ void tst_qmakelib::addControlStructs()
<< "VAR = final" << "VAR = final"
<< "" << ""
<< true; << 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) void tst_qmakelib::addReplaceFunctions(const QString &qindir)
@ -2098,6 +2195,12 @@ void tst_qmakelib::addTestFunctions(const QString &qindir)
<< "Project ERROR: World, you FAIL!" << "Project ERROR: World, you FAIL!"
<< false; << 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()") QTest::newRow("system()")
<< "system('" << "system('"
#ifdef Q_OS_WIN #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 joined: word: this is a test:done\n"
"Project MESSAGE: assign split quoted: word this is a test done" "Project MESSAGE: assign split quoted: word this is a test done"
<< true; << 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) static QString formatValue(const ProStringList &vals)

View File

@ -1867,6 +1867,13 @@ void tst_qmakelib::addParseAbuse()
/* 24 */ /* else branch */ << I(0)) /* 24 */ /* else branch */ << I(0))
<< "in:1: OR operator without prior condition." << "in:1: OR operator without prior condition."
<< false; << 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() void tst_qmakelib::proParser_data()

View File

@ -286,8 +286,8 @@ retry:
// Testing get/set functions // Testing get/set functions
void tst_QCompleter::getSetCheck() void tst_QCompleter::getSetCheck()
{ {
QStandardItemModel model(3,3); QStandardItemModel standardItemModel(3,3);
QCompleter completer(&model); QCompleter completer(&standardItemModel);
// QString QCompleter::completionPrefix() // QString QCompleter::completionPrefix()
// void QCompleter::setCompletionPrefix(QString) // void QCompleter::setCompletionPrefix(QString)
@ -347,6 +347,21 @@ void tst_QCompleter::getSetCheck()
QCOMPARE(completer.wrapAround(), true); // default value QCOMPARE(completer.wrapAround(), true); // default value
completer.setWrapAround(false); completer.setWrapAround(false);
QCOMPARE(completer.wrapAround(), 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() void tst_QCompleter::csMatchingOnCsSortedModel_data()

View File

@ -156,6 +156,7 @@ private slots:
void itemData(); void itemData();
void task_QTBUG_31146_popupCompletion(); void task_QTBUG_31146_popupCompletion();
void task_QTBUG_41288_completerChangesCurrentIndex(); void task_QTBUG_41288_completerChangesCurrentIndex();
void task_QTBUG_54191_slotOnEditTextChangedSetsComboBoxToReadOnly();
void keyboardSelection(); void keyboardSelection();
void setCustomModelAndView(); void setCustomModelAndView();
void updateDelegateOnEditableChange(); 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() void tst_QComboBox::keyboardSelection()
{ {
QComboBox comboBox; QComboBox comboBox;