aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-08-17 10:57:38 +0200
committerLiang Qi <liang.qi@qt.io>2016-08-17 10:57:38 +0200
commit7e609f6d109f8bebb7e2fe4bd8867c5a4f8ece3d (patch)
treeecbd4f56e83a84233d42928e5554709ca8832ce1 /src
parent78f5b9e7f7295b9ba11da6908713fb938a1e0b90 (diff)
parentc0f3c8ae5cee3ecda1ac8829336aa95cbe4d330e (diff)
Merge remote-tracking branch 'origin/5.7' into dev
Conflicts: src/qml/compiler/qqmltypecompiler.cpp src/qml/compiler/qv4isel_moth.cpp src/qml/compiler/qv4ssa_p.h src/qml/qml/qqmlobjectcreator.cpp Change-Id: I8bb7fe773d657f908f20ee5e72c2b9bd643f6260
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/yarr/YarrJIT.cpp22
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp2
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp163
-rw-r--r--src/qml/compiler/qv4ssa_p.h163
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc5
-rw-r--r--src/qml/jsruntime/qv4engine.cpp13
-rw-r--r--src/qml/memory/qv4mm.cpp13
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp10
-rw-r--r--src/qml/qml/qqmlproperty.cpp25
-rw-r--r--src/quick/items/qquickclipnode.cpp2
-rw-r--r--src/quick/items/qquickflickable.cpp10
-rw-r--r--src/quick/items/qquickpathview.cpp60
-rw-r--r--src/quick/items/qquicktext.cpp1
-rw-r--r--src/quick/items/qquicktextinput.cpp2
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp3
15 files changed, 268 insertions, 226 deletions
diff --git a/src/3rdparty/masm/yarr/YarrJIT.cpp b/src/3rdparty/masm/yarr/YarrJIT.cpp
index 5664c585b9..d8211ec4b2 100644
--- a/src/3rdparty/masm/yarr/YarrJIT.cpp
+++ b/src/3rdparty/masm/yarr/YarrJIT.cpp
@@ -338,17 +338,31 @@ class YarrGenerator : private MacroAssembler {
jump(Address(stackPointerRegister, frameLocation * sizeof(void*)));
}
+ unsigned alignCallFrameSizeInBytes(unsigned callFrameSize)
+ {
+ callFrameSize *= sizeof(void*);
+ if (callFrameSize / sizeof(void*) != m_pattern.m_body->m_callFrameSize)
+ CRASH();
+ // Originally, the code was:
+// callFrameSize = (callFrameSize + 0x3f) & ~0x3f;
+ // However, 64 bytes is a bit surprising. The biggest "alignment" requirement is on Aarch64, where:
+ // "SP mod 16 = 0. The stack must be quad-word aligned." (IHI0055B_aapcs64.pdf)
+ callFrameSize = (callFrameSize + 0xf) & ~0xf;
+ if (!callFrameSize)
+ CRASH();
+ return callFrameSize;
+ }
void initCallFrame()
{
unsigned callFrameSize = m_pattern.m_body->m_callFrameSize;
if (callFrameSize)
- subPtr(Imm32(callFrameSize * sizeof(void*)), stackPointerRegister);
+ subPtr(Imm32(alignCallFrameSizeInBytes(callFrameSize)), stackPointerRegister);
}
void removeCallFrame()
{
unsigned callFrameSize = m_pattern.m_body->m_callFrameSize;
if (callFrameSize)
- addPtr(Imm32(callFrameSize * sizeof(void*)), stackPointerRegister);
+ addPtr(Imm32(alignCallFrameSizeInBytes(callFrameSize)), stackPointerRegister);
}
// Used to record subpatters, should only be called if compileMode is IncludeSubpatterns.
@@ -2565,6 +2579,10 @@ class YarrGenerator : private MacroAssembler {
if (compileMode == IncludeSubpatterns)
loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output);
#endif
+#elif CPU(ARM64)
+ // The ABI doesn't guarantee the upper bits are zero on unsigned arguments, so clear them ourselves.
+ zeroExtend32ToPtr(index, index);
+ zeroExtend32ToPtr(length, length);
#elif CPU(ARM)
push(ARMRegisters::r4);
push(ARMRegisters::r5);
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 4b33363d09..2308e66609 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -816,7 +816,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
continue;
QQmlPropertyCache *pc = enginePrivate->rawPropertyCacheForType(pd->propType());
- const QMetaObject *mo = pc->firstCppMetaObject();
+ const QMetaObject *mo = pc ? pc->firstCppMetaObject() : 0;
while (mo) {
if (mo == &QQmlComponent::staticMetaObject)
break;
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index c9143b6857..fda5b4cdd0 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -150,167 +150,6 @@ inline bool isBoolType(IR::Expr *e)
return (e->type == IR::BoolType);
}
-/*
- * stack slot allocation:
- *
- * foreach bb do
- * foreach stmt do
- * if the current statement is not a phi-node:
- * purge ranges that end before the current statement
- * check for life ranges to activate, and if they don't have a stackslot associated then allocate one
- * renumber temps to stack
- * for phi nodes: check if all temps (src+dst) are assigned stack slots and marked as allocated
- * if it's a jump:
- * foreach phi node in the successor:
- * allocate slots for each temp (both sources and targets) if they don't have one allocated already
- * insert moves before the jump
- */
-class AllocateStackSlots: protected ConvertTemps
-{
- IR::LifeTimeIntervals::Ptr _intervals;
- QVector<IR::LifeTimeInterval *> _unhandled;
- QVector<IR::LifeTimeInterval *> _live;
- QBitArray _slotIsInUse;
- IR::Function *_function;
-
- int defPosition(IR::Stmt *s) const
- {
- return usePosition(s) + 1;
- }
-
- int usePosition(IR::Stmt *s) const
- {
- return _intervals->positionForStatement(s);
- }
-
-public:
- AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals)
- : _intervals(intervals)
- , _slotIsInUse(intervals->size(), false)
- , _function(0)
- {
- _live.reserve(8);
- _unhandled = _intervals->intervals();
- }
-
- void forFunction(IR::Function *function)
- {
- IR::Optimizer::showMeTheCode(function, "Before stack slot allocation");
- _function = function;
- toStackSlots(function);
- }
-
-protected:
- virtual int allocateFreeSlot()
- {
- for (int i = 0, ei = _slotIsInUse.size(); i != ei; ++i) {
- if (!_slotIsInUse[i]) {
- if (_nextUnusedStackSlot <= i) {
- Q_ASSERT(_nextUnusedStackSlot == i);
- _nextUnusedStackSlot = i + 1;
- }
- _slotIsInUse[i] = true;
- return i;
- }
- }
-
- Q_UNREACHABLE();
- return -1;
- }
-
- virtual void process(IR::Stmt *s)
- {
-// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id);
-
- if (IR::Phi *phi = s->asPhi()) {
- visitPhi(phi);
- } else {
- // purge ranges no longer alive:
- for (int i = 0; i < _live.size(); ) {
- const IR::LifeTimeInterval *lti = _live.at(i);
- if (lti->end() < usePosition(s)) {
-// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index];
- _live.remove(i);
- Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]);
- _slotIsInUse[_stackSlotForTemp[lti->temp().index]] = false;
- continue;
- } else {
- ++i;
- }
- }
-
- // active new ranges:
- while (!_unhandled.isEmpty()) {
- IR::LifeTimeInterval *lti = _unhandled.last();
- if (lti->start() > defPosition(s))
- break; // we're done
- Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index));
- _stackSlotForTemp[lti->temp().index] = allocateFreeSlot();
-// qDebug() << "\t - activating temp" << lti->temp().index << "on slot" << _stackSlotForTemp[lti->temp().index];
- _live.append(lti);
- _unhandled.removeLast();
- }
-
- visit(s);
- }
-
- if (IR::Jump *jump = s->asJump()) {
- IR::MoveMapping moves;
- for (IR::Stmt *succStmt : jump->target->statements()) {
- if (IR::Phi *phi = succStmt->asPhi()) {
- forceActivation(*phi->targetTemp);
- for (int i = 0, ei = phi->incoming.size(); i != ei; ++i) {
- IR::Expr *e = phi->incoming[i];
- if (IR::Temp *t = e->asTemp()) {
- forceActivation(*t);
- }
- if (jump->target->in[i] == _currentBasicBlock)
- moves.add(phi->incoming[i], phi->targetTemp);
- }
- } else {
- break;
- }
- }
- moves.order();
- QList<IR::Move *> newMoves = moves.insertMoves(_currentBasicBlock, _function, true);
- foreach (IR::Move *move, newMoves)
- visit(move);
- }
- }
-
- void forceActivation(const IR::Temp &t)
- {
- if (_stackSlotForTemp.contains(t.index))
- return;
-
- int i = _unhandled.size() - 1;
- for (; i >= 0; --i) {
- IR::LifeTimeInterval *lti = _unhandled[i];
- if (lti->temp() == t) {
- _live.append(lti);
- _unhandled.remove(i);
- break;
- }
- }
- Q_ASSERT(i >= 0); // check that we always found the entry
-
- _stackSlotForTemp[t.index] = allocateFreeSlot();
-// qDebug() << "\t - force activating temp" << t.index << "on slot" << _stackSlotForTemp[t.index];
- }
-
- virtual void visitPhi(IR::Phi *phi)
- {
- Q_UNUSED(phi);
-#if !defined(QT_NO_DEBUG)
- Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index));
- Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]);
- foreach (IR::Expr *e, phi->incoming) {
- if (IR::Temp *t = e->asTemp())
- Q_ASSERT(_stackSlotForTemp.contains(t->index));
- }
-#endif // defined(QT_NO_DEBUG)
- }
-};
} // anonymous namespace
InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
@@ -360,7 +199,7 @@ void InstructionSelection::run(int functionIndex)
qEnvironmentVariableIsEmpty("QV4_NO_INTERPRETER_STACK_SLOT_ALLOCATION");
if (doStackSlotAllocation) {
- AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function);
+ IR::AllocateStackSlots(opt.lifeTimeIntervals()).forFunction(_function);
} else {
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index e608c08591..386990a9f5 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -52,6 +52,7 @@
//
#include "qv4jsir_p.h"
+#include "qv4isel_util_p.h"
#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
@@ -277,6 +278,168 @@ private:
QList<Move> &swaps) const;
};
+/*
+ * stack slot allocation:
+ *
+ * foreach bb do
+ * foreach stmt do
+ * if the current statement is not a phi-node:
+ * purge ranges that end before the current statement
+ * check for life ranges to activate, and if they don't have a stackslot associated then allocate one
+ * renumber temps to stack
+ * for phi nodes: check if all temps (src+dst) are assigned stack slots and marked as allocated
+ * if it's a jump:
+ * foreach phi node in the successor:
+ * allocate slots for each temp (both sources and targets) if they don't have one allocated already
+ * insert moves before the jump
+ */
+class AllocateStackSlots: protected ConvertTemps
+{
+ IR::LifeTimeIntervals::Ptr _intervals;
+ QVector<IR::LifeTimeInterval *> _unhandled;
+ QVector<IR::LifeTimeInterval *> _live;
+ QBitArray _slotIsInUse;
+ IR::Function *_function;
+
+ int defPosition(IR::Stmt *s) const
+ {
+ return usePosition(s) + 1;
+ }
+
+ int usePosition(IR::Stmt *s) const
+ {
+ return _intervals->positionForStatement(s);
+ }
+
+public:
+ AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals)
+ : _intervals(intervals)
+ , _slotIsInUse(intervals->size(), false)
+ , _function(0)
+ {
+ _live.reserve(8);
+ _unhandled = _intervals->intervals();
+ }
+
+ void forFunction(IR::Function *function)
+ {
+ IR::Optimizer::showMeTheCode(function, "Before stack slot allocation");
+ _function = function;
+ toStackSlots(function);
+ }
+
+protected:
+ virtual int allocateFreeSlot()
+ {
+ for (int i = 0, ei = _slotIsInUse.size(); i != ei; ++i) {
+ if (!_slotIsInUse[i]) {
+ if (_nextUnusedStackSlot <= i) {
+ Q_ASSERT(_nextUnusedStackSlot == i);
+ _nextUnusedStackSlot = i + 1;
+ }
+ _slotIsInUse[i] = true;
+ return i;
+ }
+ }
+
+ Q_UNREACHABLE();
+ return -1;
+ }
+
+ virtual void process(IR::Stmt *s)
+ {
+// qDebug("L%d statement %d:", _currentBasicBlock->index, s->id);
+
+ if (IR::Phi *phi = s->asPhi()) {
+ visitPhi(phi);
+ } else {
+ // purge ranges no longer alive:
+ for (int i = 0; i < _live.size(); ) {
+ const IR::LifeTimeInterval *lti = _live.at(i);
+ if (lti->end() < usePosition(s)) {
+// qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index];
+ _live.remove(i);
+ Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]);
+ _slotIsInUse[_stackSlotForTemp[lti->temp().index]] = false;
+ continue;
+ } else {
+ ++i;
+ }
+ }
+
+ // active new ranges:
+ while (!_unhandled.isEmpty()) {
+ IR::LifeTimeInterval *lti = _unhandled.last();
+ if (lti->start() > defPosition(s))
+ break; // we're done
+ Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index));
+ _stackSlotForTemp[lti->temp().index] = allocateFreeSlot();
+// qDebug() << "\t - activating temp" << lti->temp().index << "on slot" << _stackSlotForTemp[lti->temp().index];
+ _live.append(lti);
+ _unhandled.removeLast();
+ }
+
+ visit(s);
+ }
+
+ if (IR::Jump *jump = s->asJump()) {
+ IR::MoveMapping moves;
+ for (IR::Stmt *succStmt : jump->target->statements()) {
+ if (IR::Phi *phi = succStmt->asPhi()) {
+ forceActivation(*phi->targetTemp);
+ for (int i = 0, ei = phi->incoming.size(); i != ei; ++i) {
+ IR::Expr *e = phi->incoming[i];
+ if (IR::Temp *t = e->asTemp()) {
+ forceActivation(*t);
+ }
+ if (jump->target->in[i] == _currentBasicBlock)
+ moves.add(phi->incoming[i], phi->targetTemp);
+ }
+ } else {
+ break;
+ }
+ }
+ moves.order();
+ QList<IR::Move *> newMoves = moves.insertMoves(_currentBasicBlock, _function, true);
+ foreach (IR::Move *move, newMoves)
+ visit(move);
+ }
+ }
+
+ void forceActivation(const IR::Temp &t)
+ {
+ if (_stackSlotForTemp.contains(t.index))
+ return;
+
+ int i = _unhandled.size() - 1;
+ for (; i >= 0; --i) {
+ IR::LifeTimeInterval *lti = _unhandled[i];
+ if (lti->temp() == t) {
+ _live.append(lti);
+ _unhandled.remove(i);
+ break;
+ }
+ }
+ Q_ASSERT(i >= 0); // check that we always found the entry
+
+ _stackSlotForTemp[t.index] = allocateFreeSlot();
+// qDebug() << "\t - force activating temp" << t.index << "on slot" << _stackSlotForTemp[t.index];
+ }
+
+ virtual void visitPhi(IR::Phi *phi)
+ {
+ Q_UNUSED(phi);
+#if !defined(QT_NO_DEBUG)
+ Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index));
+ Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]);
+ foreach (IR::Expr *e, phi->incoming) {
+ if (IR::Temp *t = e->asTemp())
+ Q_ASSERT(_stackSlotForTemp.contains(t->index));
+ }
+#endif // defined(QT_NO_DEBUG)
+ }
+};
+
} // IR namespace
} // QV4 namespace
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index de8b967d72..1e33f2f641 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -80,7 +80,10 @@ Note that QML makes the following modifications to native objects:
QML implements the following restrictions for JavaScript code:
\list
-\li JavaScript code cannot modify the global object.
+\li JavaScript code written in a \c .qml file cannot modify the global object.
+ JavaScript code in a .js file can modify the global object,
+ and those modifications will be visible to the .qml file when
+ \l {Importing a JavaScript Resource from a QML Document}{imported}.
In QML, the global object is constant - existing properties cannot be modified
or deleted, and no new properties may be created.
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 27397fe3d8..f8110d29f6 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1144,8 +1144,13 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return value.integerValue();
if (value.isNumber())
return value.asDouble();
- if (value.isString())
- return value.stringValue()->toQString();
+ if (value.isString()) {
+ const QString &str = value.toQString();
+ // QChars are stored as a strings
+ if (typeHint == QVariant::Char && str.size() == 1)
+ return str.at(0);
+ return str;
+ }
if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
return ld->d()->locale;
if (const QV4::DateObject *d = value.as<DateObject>())
@@ -1288,9 +1293,9 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
case QMetaType::UShort:
return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(ptr));
case QMetaType::Char:
- return newString(QChar::fromLatin1(*reinterpret_cast<const char *>(ptr)))->asReturnedValue();
+ return QV4::Encode((int)*reinterpret_cast<const char*>(ptr));
case QMetaType::UChar:
- return newString(QChar::fromLatin1(*reinterpret_cast<const unsigned char *>(ptr)))->asReturnedValue();
+ return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(ptr));
case QMetaType::QChar:
return newString(*reinterpret_cast<const QChar *>(ptr))->asReturnedValue();
case QMetaType::QDateTime:
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 53b9ebfe2a..3d25bd1639 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -456,7 +456,7 @@ void MemoryManager::sweep(bool lastSweep)
Managed *m = (*it).managed();
if (m->markBit())
continue;
- // we need to call detroyObject on qobjectwrappers now, so that they can emit the destroyed
+ // we need to call destroyObject on qobjectwrappers now, so that they can emit the destroyed
// signal before we start sweeping the heap
if (QObjectWrapper *qobjectWrapper = (*it).as<QObjectWrapper>())
qobjectWrapper->destroyObject(lastSweep);
@@ -464,6 +464,17 @@ void MemoryManager::sweep(bool lastSweep)
(*it) = Primitive::undefinedValue();
}
+ // onDestruction handlers may have accessed other QObject wrappers and reset their value, so ensure
+ // that they are all set to undefined.
+ for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
+ if (!(*it).isManaged())
+ continue;
+ Managed *m = (*it).as<Managed>();
+ if (m->markBit())
+ continue;
+ (*it) = Primitive::undefinedValue();
+ }
+
// Now it is time to free QV4::QObjectWrapper Value, we must check the Value's tag to make sure its object has been destroyed
const int pendingCount = m_pendingFreedObjectWrapperValue.count();
if (pendingCount) {
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index f9794ec26a..e02d362815 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -75,12 +75,12 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::Compil
, compilationUnit(compilationUnit)
, resolvedTypes(compilationUnit->resolvedTypes)
, propertyCaches(&compilationUnit->propertyCaches)
+ , sharedState(new QQmlObjectCreatorSharedState)
+ , topLevelCreator(true)
, activeVMEDataForRootContext(activeVMEDataForRootContext)
{
init(parentContext);
- sharedState = new QQmlObjectCreatorSharedState;
- topLevelCreator = true;
sharedState->componentAttached = 0;
sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount);
sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount);
@@ -102,12 +102,11 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::Compil
, compilationUnit(compilationUnit)
, resolvedTypes(compilationUnit->resolvedTypes)
, propertyCaches(&compilationUnit->propertyCaches)
+ , sharedState(inheritedSharedState)
+ , topLevelCreator(false)
, activeVMEDataForRootContext(0)
{
init(parentContext);
-
- sharedState = inheritedSharedState;
- topLevelCreator = false;
}
void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
@@ -123,6 +122,7 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext)
context = 0;
_qobject = 0;
_scopeObject = 0;
+ _bindingTarget = 0;
_valueTypeProperty = 0;
_compiledObject = 0;
_compiledObjectIndex = -1;
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 7b1e2ec4f6..c62fef7c3d 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1321,29 +1321,8 @@ bool QQmlPropertyPrivate::write(QObject *object,
bool ok = false;
QVariant v;
- if (variantType == QVariant::String) {
- const QString &str = value.toString();
- const bool targetIsChar = (propertyType == qMetaTypeId<QChar>()
- || propertyType == qMetaTypeId<char>()
- || propertyType == qMetaTypeId<unsigned char>());
- // If the string contains only one character and the target is a char, try converting it.
- if (targetIsChar) {
- if (str.size() != 1)
- return false; // We can only convert if the string contains exactly one character.
-
- const QChar &qChar = str.at(0);
- if (propertyType == qMetaTypeId<QChar>()) {
- v = qChar;
- ok = true;
- } else if (propertyType == qMetaTypeId<char>() || propertyType == qMetaTypeId<unsigned char>()) {
- const char c = qChar.toLatin1();
- v = c;
- ok = (qChar == c);
- }
- } else {
- v = QQmlStringConverters::variantFromString(str, propertyType, &ok);
- }
- }
+ if (variantType == QVariant::String)
+ v = QQmlStringConverters::variantFromString(value.toString(), propertyType, &ok);
if (!ok) {
v = value;
diff --git a/src/quick/items/qquickclipnode.cpp b/src/quick/items/qquickclipnode.cpp
index 7c7fee4a42..747e844172 100644
--- a/src/quick/items/qquickclipnode.cpp
+++ b/src/quick/items/qquickclipnode.cpp
@@ -93,7 +93,7 @@ void QQuickDefaultClipNode::updateGeometry()
int segments = qMin(30, qCeil(radius)); // Number of segments per corner.
- g->allocate((segments + 1) * 2);
+ g->allocate((segments + 1) * 4);
QVector2D *vertices = (QVector2D *)g->vertexData();
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index dcba5c2d71..31581c0f07 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -886,7 +886,7 @@ QQuickFlickableVisibleArea *QQuickFlickable::visibleArea()
\li Flickable.AutoFlickIfNeeded - allows flicking vertically if the
\e contentHeight is greater than the \e height of the Flickable.
Allows flicking horizontally if the \e contentWidth is greater than
- to the \e width of the Flickable.
+ to the \e width of the Flickable. (since \c{QtQuick 2.7})
\li Flickable.HorizontalFlick - allows flicking horizontally.
\li Flickable.VerticalFlick - allows flicking vertically.
\li Flickable.HorizontalAndVerticalFlick - allows flicking in both directions.
@@ -1234,13 +1234,17 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
return;
qint64 currentTimestamp = computeCurrentTime(event);
- qreal elapsed = qreal(currentTimestamp - (lastPos.isNull() ? lastPressTime : lastPosTime)) / 1000.;
QVector2D deltas = QVector2D(event->localPos() - pressPos);
bool overThreshold = false;
QVector2D velocity = QGuiApplicationPrivate::mouseEventVelocity(event);
// TODO guarantee that events always have velocity so that it never needs to be computed here
- if (!(QGuiApplicationPrivate::mouseEventCaps(event) & QTouchDevice::Velocity))
+ if (!(QGuiApplicationPrivate::mouseEventCaps(event) & QTouchDevice::Velocity)) {
+ qint64 lastTimestamp = (lastPos.isNull() ? lastPressTime : lastPosTime);
+ if (currentTimestamp == lastTimestamp)
+ return; // events are too close together: velocity would be infinite
+ qreal elapsed = qreal(currentTimestamp - lastTimestamp) / 1000.;
velocity = QVector2D(event->localPos() - (lastPos.isNull() ? pressPos : lastPos)) / elapsed;
+ }
if (q->yflick())
overThreshold |= QQuickWindowPrivate::dragOverThreshold(deltas.y(), Qt::YAxis, event);
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 1de20ed5b9..0d047bc882 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -296,6 +296,8 @@ qreal QQuickPathViewPrivate::positionOfIndex(qreal index) const
// account the circular space.
bool QQuickPathViewPrivate::isInBound(qreal position, qreal lower, qreal upper) const
{
+ if (lower == upper)
+ return true;
if (lower > upper) {
if (position > upper && position > lower)
position -= mappedRange;
@@ -1903,6 +1905,14 @@ void QQuickPathView::updatePolish()
refill();
}
+static inline int currentIndexRemainder(int currentIndex, int modelCount) Q_DECL_NOTHROW
+{
+ if (currentIndex < 0)
+ return modelCount + currentIndex % modelCount;
+ else
+ return currentIndex % modelCount;
+}
+
void QQuickPathView::componentComplete()
{
Q_D(QQuickPathView);
@@ -1914,7 +1924,7 @@ void QQuickPathView::componentComplete()
if (d->model) {
d->modelCount = d->model->count();
if (d->modelCount && d->currentIndex != 0) // an initial value has been provided for currentIndex
- d->offset = qmlMod(d->modelCount - d->currentIndex, d->modelCount);
+ d->offset = qmlMod(d->modelCount - currentIndexRemainder(d->currentIndex, d->modelCount), d->modelCount);
}
d->createHighlight();
@@ -1988,7 +1998,8 @@ void QQuickPathView::refill()
qreal endPos;
int startIdx = 0;
qreal startPos = 0.0;
- if (d->items.count()) {
+ const bool wasEmpty = d->items.isEmpty();
+ if (!wasEmpty) {
//Find the beginning and end, items may not be in sorted order
endPos = -1.0;
startPos = 2.0;
@@ -2047,7 +2058,8 @@ void QQuickPathView::refill()
}
//Prepend
- idx = startIdx - 1;
+ idx = (wasEmpty ? d->calcCurrentIndex() : startIdx) - 1;
+
if (idx < 0)
idx = d->modelCount - 1;
nextPos = d->positionOfIndex(idx);
@@ -2086,27 +2098,33 @@ void QQuickPathView::refill()
idx = startIdx;
QQuickItem *lastItem = d->items.at(0);
while (idx != endIdx) {
- //This gets the reference from the delegate model, and will not re-create
- QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0);
- if (!item) {
- waiting = true;
- break;
- }
- if (!d->items.contains(item)) { //We found a hole
- nextPos = d->positionOfIndex(idx);
- qCDebug(lcItemViewDelegateLifecycle) << "middle insert" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count();
- if (d->currentIndex == idx) {
- currentVisible = true;
- d->currentItemOffset = nextPos;
+ nextPos = d->positionOfIndex(idx);
+ if (d->isInBound(nextPos, d->mappedRange - d->mappedCache, 1.0 + d->mappedCache)) {
+ //This gets the reference from the delegate model, and will not re-create
+ QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0);
+ if (!item) {
+ waiting = true;
+ break;
}
- int lastListIdx = d->items.indexOf(lastItem);
- d->items.insert(lastListIdx + 1, item);
- d->updateItem(item, nextPos);
- } else {
- d->releaseItem(item);
+
+ if (!d->items.contains(item)) { //We found a hole
+ qCDebug(lcItemViewDelegateLifecycle) << "middle insert" << idx << "@" << nextPos
+ << (d->currentIndex == idx ? "current" : "")
+ << "items count was" << d->items.count();
+ if (d->currentIndex == idx) {
+ currentVisible = true;
+ d->currentItemOffset = nextPos;
+ }
+ int lastListIdx = d->items.indexOf(lastItem);
+ d->items.insert(lastListIdx + 1, item);
+ d->updateItem(item, nextPos);
+ } else {
+ d->releaseItem(item);
+ }
+
+ lastItem = item;
}
- lastItem = item;
++idx;
if (idx >= d->modelCount)
idx = 0;
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 4dc59b100a..9494a55c2d 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -2062,6 +2062,7 @@ void QQuickText::setTextFormat(TextFormat format)
}
d->updateLayout();
setAcceptHoverEvents(d->richText || d->styledText);
+ setAcceptedMouseButtons(d->richText || d->styledText ? Qt::LeftButton : Qt::NoButton);
emit textFormatChanged(d->format);
}
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index 0078c4ac21..17f00ebef9 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -2992,7 +2992,7 @@ void QQuickTextInputPrivate::updateLayout()
if (inLayout) // probably the result of a binding loop, but by letting it
return; // get this far we'll get a warning to that effect.
}
- qreal lineWidth = q->widthValid() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX;
+ qreal lineWidth = q->widthValid() || !isImplicitResizeEnabled() ? q->width() - q->leftPadding() - q->rightPadding() : INT_MAX;
qreal height = 0;
qreal width = 0;
do {
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index afb9b673d9..f0a336e229 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -259,7 +259,8 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int
const GLenum format = GL_ALPHA;
#endif
- m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, 0);
+ QByteArray zeroBuf(width * height, 0);
+ m_funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, zeroBuf.constData());
texInfo->size = QSize(width, height);