diff options
42 files changed, 681 insertions, 237 deletions
diff --git a/dist/changes-5.2.1 b/dist/changes-5.2.1 new file mode 100644 index 0000000000..c5371185f0 --- /dev/null +++ b/dist/changes-5.2.1 @@ -0,0 +1,38 @@ +Qt 5.2.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.2.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://qt-project.org/doc/qt-5.2 + +The Qt version 5.2 series is binary compatible with the 5.1.x series. +Applications compiled for 5.1 will continue to run with 5.2. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt-project.org/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Library * +**************************************************************************** + +QtQml +----- + + - [QTBUG-35979] Fixed JavaScript Array.pop() not updating the + internal array length correctly + +QtQuick +------- + + - [QTBUG-35128] Fixed TextInput to call fixup() on its validator when + being accepted or losing focus, and the validator reports that the input + is in "intermediate" state ie. the input should be fixed up. + - [QTBUG-34517] Fixed an issue that caused QQuickTextInput to not + accept delete/home/backspace/left/right keys when the key was used + in a shortcut. diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 6df94e713d..b8b16a4151 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -1966,12 +1966,21 @@ void InstructionSelection::visitRet(V4IR::Ret *s) Assembler::ScratchRegister); _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister); } else if (t->type == V4IR::UInt32Type) { - Address tmp = addressForArgument(0); - _as->storeUInt32((Assembler::RegisterID) t->index, Pointer(tmp)); - _as->load64(tmp, Assembler::ReturnValueRegister); + Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index; + Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0)); + _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister); + _as->moveDoubleTo64(Assembler::FPGpr0, Assembler::ReturnValueRegister); + _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister); + _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister); + Assembler::Jump done = _as->jump(); + intRange.link(_as); + _as->zeroExtend32ToPtr(srcReg, Assembler::ReturnValueRegister); + quint64 tag = QV4::Value::_Integer_Type; + _as->or64(Assembler::TrustedImm64(tag << 32), + Assembler::ReturnValueRegister); + done.link(_as); } else { - _as->zeroExtend32ToPtr((Assembler::RegisterID) t->index, - Assembler::ReturnValueRegister); + _as->zeroExtend32ToPtr((Assembler::RegisterID) t->index, Assembler::ReturnValueRegister); quint64 tag; switch (t->type) { case V4IR::SInt32Type: diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index f5d4e469e5..a146220015 100644 --- a/src/qml/compiler/qv4isel_masm_p.h +++ b/src/qml/compiler/qv4isel_masm_p.h @@ -1481,6 +1481,7 @@ protected: typedef Assembler::Address Address; typedef Assembler::Pointer Pointer; +#if !defined(ARGUMENTS_IN_REGISTERS) Address addressForArgument(int index) const { // StackFrameRegister points to its old value on the stack, and above @@ -1488,6 +1489,7 @@ protected: // values before reaching the first argument. return Address(Assembler::StackFrameRegister, (index + 2) * sizeof(void*)); } +#endif Pointer baseAddressForCallArguments() { diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index f95cd55b04..2f1f64e523 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -860,7 +860,6 @@ private: if (it->end() < successorStart) continue; - bool lifeTimeHole = false; bool isPhiTarget = false; Expr *moveFrom = 0; @@ -906,9 +905,7 @@ private: predIt->temp().type); } else { int spillSlot = _assignedSpillSlots.value(predIt->temp(), -1); - if (spillSlot == -1) - lifeTimeHole = true; - else + if (spillSlot != -1) moveFrom = createTemp(Temp::StackSlot, spillSlot, predIt->temp().type); } break; @@ -916,9 +913,11 @@ private: } } if (!moveFrom) { -#if defined(QT_NO_DEBUG) - Q_UNUSED(lifeTimeHole); -#else +#if !defined(QT_NO_DEBUG) + bool lifeTimeHole = false; + if (it->ranges().first().start <= successorStart && it->ranges().last().end >= successorStart) + lifeTimeHole = !it->covers(successorStart); + Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole); if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) { const int successorEnd = successor->statements.last()->id; @@ -960,9 +959,6 @@ private: moveTo = createTemp(Temp::StackSlot, spillSlot, it->temp().type); } else { moveTo = createTemp(Temp::PhysicalRegister, platformRegister(*it), it->temp().type); - const int spillSlot = _assignedSpillSlots.value(it->temp(), -1); - if (isPhiTarget && spillSlot != -1) - mapping.add(moveFrom, createTemp(Temp::StackSlot, spillSlot, it->temp().type)); } // add move to mapping diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h index 6d7c0dcb51..c3329dbb89 100644 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ b/src/qml/debugger/qqmlprofilerservice_p.h @@ -57,6 +57,7 @@ #include <private/qqmlboundsignal_p.h> // this contains QUnifiedTimer #include <private/qabstractanimation_p.h> +#include <private/qv4function_p.h> #include <QtCore/qelapsedtimer.h> #include <QtCore/qmetaobject.h> @@ -401,8 +402,20 @@ struct QQmlBindingProfiler { struct QQmlHandlingSignalProfiler { QQmlHandlingSignalProfiler(QQmlBoundSignalExpression *expression) { - Q_QML_PROFILE(startHandlingSignal(expression->sourceFile(), expression->lineNumber(), - expression->columnNumber())); + if (QQmlProfilerService::enabled) { + if (expression->sourceFile().isEmpty()) { + QV4::Function *function = expression->function(); + if (function) { + Q_QML_PROFILE(startHandlingSignal( + function->sourceFile(), function->compiledFunction->location.line, + function->compiledFunction->location.column)); + } + } else { + Q_QML_PROFILE(startHandlingSignal( + expression->sourceFile(), expression->lineNumber(), + expression->columnNumber())); + } + } } ~QQmlHandlingSignalProfiler() diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 19cd3b3f02..d3d3174193 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -238,7 +238,7 @@ Usage: \code // First, define the singleton type provider function (callback). - static QJSValue *example_qjsvalue_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine) + static QJSValue example_qjsvalue_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 0734e92b19..c8de31ef78 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -746,7 +746,7 @@ static bool js_equal(const QString &string, QV4::ValueRef value) if (value->isNumber()) return __qmljs_string_to_number(string) == value->asDouble(); if (value->isBoolean()) - return __qmljs_string_to_number(string) == value->booleanValue(); + return __qmljs_string_to_number(string) == double(value->booleanValue()); if (value->isObject()) { Scope scope(value->objectValue()->engine()); ScopedValue p(scope, __qmljs_to_primitive(value, PREFERREDTYPE_HINT)); diff --git a/src/qml/jsruntime/qv4alloca_p.h b/src/qml/jsruntime/qv4alloca_p.h index f507d174e1..e51c6dff00 100644 --- a/src/qml/jsruntime/qv4alloca_p.h +++ b/src/qml/jsruntime/qv4alloca_p.h @@ -50,7 +50,9 @@ # define alloca _alloca # endif #else +#if !defined(__FreeBSD__) && !defined(__DragonFly__) # include <alloca.h> #endif +#endif #endif diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 995c711a02..299d11a4a1 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -77,6 +77,9 @@ #if USE(PTHREADS) # include <pthread.h> # include <sys/resource.h> +#if HAVE(PTHREAD_NP_H) +# include <pthread_np.h> +#endif #endif QT_BEGIN_NAMESPACE @@ -109,7 +112,11 @@ quintptr getStackLimit() # else void* stackBottom = 0; pthread_attr_t attr; +#if HAVE(PTHREAD_NP_H) && OS(FREEBSD) + if (pthread_attr_get_np(pthread_self(), &attr) == 0) { +#else if (pthread_getattr_np(pthread_self(), &attr) == 0) { +#endif size_t stackSize = 0; pthread_attr_getstack(&attr, &stackBottom, &stackSize); pthread_attr_destroy(&attr); diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp index 0af0fea49a..0ba0b18cda 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/jsruntime/qv4mm.cpp @@ -67,6 +67,10 @@ #include <sys/storage.h> // __tls() #endif +#if USE(PTHREADS) && HAVE(PTHREAD_NP_H) +#include <pthread_np.h> +#endif + QT_BEGIN_NAMESPACE using namespace QV4; @@ -234,7 +238,11 @@ MemoryManager::MemoryManager() # else void* stackBottom = 0; pthread_attr_t attr; +#if HAVE(PTHREAD_NP_H) && OS(FREEBSD) + if (pthread_attr_get_np(pthread_self(), &attr) == 0) { +#else if (pthread_getattr_np(pthread_self(), &attr) == 0) { +#endif size_t stackSize = 0; pthread_attr_getstack(&attr, &stackBottom, &stackSize); pthread_attr_destroy(&attr); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index aafecb5ad8..95b6569196 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -237,6 +237,15 @@ RegExpCtor::RegExpCtor(ExecutionContext *scope) : FunctionObject(scope, QStringLiteral("RegExp")) { setVTable(staticVTable()); + clearLastMatch(); +} + +void RegExpCtor::clearLastMatch() +{ + lastMatch = Primitive::nullValue(); + lastInput = engine()->newIdentifier(QString()); + lastMatchStart = 0; + lastMatchEnd = 0; } ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) @@ -299,6 +308,14 @@ ReturnedValue RegExpCtor::call(Managed *that, CallData *callData) return construct(that, callData); } +void RegExpCtor::markObjects(Managed *that, ExecutionEngine *e) +{ + RegExpCtor *This = static_cast<RegExpCtor*>(that); + This->lastMatch.mark(e); + This->lastInput.mark(e); + FunctionObject::markObjects(that, e); +} + void RegExpPrototype::init(ExecutionEngine *engine, ObjectRef ctor) { Scope scope(engine); @@ -306,6 +323,28 @@ void RegExpPrototype::init(ExecutionEngine *engine, ObjectRef ctor) ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(2)); + + // Properties deprecated in the spec but required by "the web" :( + ctor->defineAccessorProperty(QStringLiteral("lastMatch"), method_get_lastMatch_n<0>, 0); + ctor->defineAccessorProperty(QStringLiteral("$&"), method_get_lastMatch_n<0>, 0); + ctor->defineAccessorProperty(QStringLiteral("$1"), method_get_lastMatch_n<1>, 0); + ctor->defineAccessorProperty(QStringLiteral("$2"), method_get_lastMatch_n<2>, 0); + ctor->defineAccessorProperty(QStringLiteral("$3"), method_get_lastMatch_n<3>, 0); + ctor->defineAccessorProperty(QStringLiteral("$4"), method_get_lastMatch_n<4>, 0); + ctor->defineAccessorProperty(QStringLiteral("$5"), method_get_lastMatch_n<5>, 0); + ctor->defineAccessorProperty(QStringLiteral("$6"), method_get_lastMatch_n<6>, 0); + ctor->defineAccessorProperty(QStringLiteral("$7"), method_get_lastMatch_n<7>, 0); + ctor->defineAccessorProperty(QStringLiteral("$8"), method_get_lastMatch_n<8>, 0); + ctor->defineAccessorProperty(QStringLiteral("$9"), method_get_lastMatch_n<9>, 0); + ctor->defineAccessorProperty(QStringLiteral("lastParen"), method_get_lastParen, 0); + ctor->defineAccessorProperty(QStringLiteral("$+"), method_get_lastParen, 0); + ctor->defineAccessorProperty(QStringLiteral("input"), method_get_input, 0); + ctor->defineAccessorProperty(QStringLiteral("$_"), method_get_input, 0); + ctor->defineAccessorProperty(QStringLiteral("leftContext"), method_get_leftContext, 0); + ctor->defineAccessorProperty(QStringLiteral("$`"), method_get_leftContext, 0); + ctor->defineAccessorProperty(QStringLiteral("rightContext"), method_get_rightContext, 0); + ctor->defineAccessorProperty(QStringLiteral("$'"), method_get_rightContext, 0); + defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(QStringLiteral("exec"), method_exec, 1); defineDefaultProperty(QStringLiteral("test"), method_test, 1); @@ -333,7 +372,11 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) } uint* matchOffsets = (uint*)alloca(r->value->captureCount() * 2 * sizeof(uint)); - int result = r->value->match(s, offset, matchOffsets); + const int result = r->value->match(s, offset, matchOffsets); + + Scoped<RegExpCtor> regExpCtor(scope, ctx->engine->regExpCtor); + regExpCtor->clearLastMatch(); + if (result == -1) { r->lastIndexProperty(ctx)->value = Primitive::fromInt32(0); return Encode::null(); @@ -351,10 +394,14 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) array->arrayData->put(i, v); } array->setArrayLengthUnchecked(len); - array->memberData[Index_ArrayIndex].value = Primitive::fromInt32(result); array->memberData[Index_ArrayInput].value = arg.asReturnedValue(); + regExpCtor->lastMatch = array; + regExpCtor->lastInput = arg->stringValue(); + regExpCtor->lastMatchStart = matchOffsets[0]; + regExpCtor->lastMatchEnd = matchOffsets[1]; + if (r->global) r->lastIndexProperty(ctx)->value = Primitive::fromInt32(matchOffsets[1]); @@ -395,4 +442,46 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) return Encode::undefined(); } +template <int index> +ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) +{ + Scope scope(ctx); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->engine->regExpCtor.objectValue())->lastMatch); + ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined()); + if (result->isUndefined()) + return ctx->engine->newString(QString())->asReturnedValue(); + return result.asReturnedValue(); +} + +ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) +{ + Scope scope(ctx); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->engine->regExpCtor.objectValue())->lastMatch); + ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined()); + if (result->isUndefined()) + return ctx->engine->newString(QString())->asReturnedValue(); + return result.asReturnedValue(); +} + +ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx) +{ + return static_cast<RegExpCtor*>(ctx->engine->regExpCtor.objectValue())->lastInput.asReturnedValue(); +} + +ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<RegExpCtor> regExpCtor(scope, ctx->engine->regExpCtor); + QString lastInput = regExpCtor->lastInput->toQString(); + return ctx->engine->newString(lastInput.left(regExpCtor->lastMatchStart))->asReturnedValue(); +} + +ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<RegExpCtor> regExpCtor(scope, ctx->engine->regExpCtor); + QString lastInput = regExpCtor->lastInput->toQString(); + return ctx->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd))->asReturnedValue(); +} + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index d306efb218..a4cb4b9fb5 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -107,8 +107,15 @@ struct RegExpCtor: FunctionObject V4_OBJECT RegExpCtor(ExecutionContext *scope); + SafeValue lastMatch; + SafeString lastInput; + int lastMatchStart; + int lastMatchEnd; + void clearLastMatch(); + static ReturnedValue construct(Managed *m, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); + static void markObjects(Managed *that, ExecutionEngine *e); }; struct RegExpPrototype: RegExpObject @@ -120,6 +127,13 @@ struct RegExpPrototype: RegExpObject static ReturnedValue method_test(CallContext *ctx); static ReturnedValue method_toString(CallContext *ctx); static ReturnedValue method_compile(CallContext *ctx); + + template <int index> + static ReturnedValue method_get_lastMatch_n(CallContext *ctx); + static ReturnedValue method_get_lastParen(CallContext *ctx); + static ReturnedValue method_get_input(CallContext *ctx); + static ReturnedValue method_get_leftContext(CallContext *ctx); + static ReturnedValue method_get_rightContext(CallContext *ctx); }; } diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 21f45745cb..2c71a36a3d 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -65,6 +65,9 @@ struct Scope { explicit Scope(ExecutionEngine *e) : engine(e) +#ifndef QT_NO_DEBUG + , size(0) +#endif { mark = engine->jsStackTop; } diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 68160edf5e..bc56fe1f2d 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -136,6 +136,17 @@ QString QQmlBoundSignalExpression::expression() const } } +QV4::Function *QQmlBoundSignalExpression::function() const +{ + if (m_expressionFunctionValid) { + Q_ASSERT (context() && engine()); + QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine()); + QV4::Scoped<QV4::FunctionObject> v(scope, m_v8function.value()); + return v ? v->function : 0; + } + return 0; +} + // Parts of this function mirror code in QQmlExpressionPrivate::value() and v8value(). // Changes made here may need to be made there and vice versa. void QQmlBoundSignalExpression::evaluate(void **a) diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index feb79d5484..fe0dbd380e 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -90,6 +90,7 @@ public: quint16 lineNumber() const { return m_line; } quint16 columnNumber() const { return m_column; } QString expression() const; + QV4::Function *function() const; QObject *target() const { return m_target; } QQmlEngine *engine() const { return context() ? context()->engine : 0; } diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index cd0dea975b..e36f3fd967 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -1681,6 +1681,7 @@ static AST::FunctionDeclaration *convertSignalHandlerExpressionToFunctionDeclara AST::FunctionBody *body = new (pool) AST::FunctionBody(elements); AST::FunctionDeclaration *functionDeclaration = new (pool) AST::FunctionDeclaration(jsEngine->newStringRef(signalName), paramList, body); + functionDeclaration->functionToken = statement->firstSourceLocation(); return functionDeclaration; } diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h index aeda9832f3..d76c9f9f64 100644 --- a/src/qml/qml/qqmlinstruction_p.h +++ b/src/qml/qml/qqmlinstruction_p.h @@ -151,8 +151,10 @@ QT_BEGIN_NAMESPACE #ifdef QML_THREADED_VME_INTERPRETER # define QML_INSTR_HEADER void *code; +# define QML_INSTR_HEADER_INIT this->code = 0; #else # define QML_INSTR_HEADER quint8 instructionType; +# define QML_INSTR_HEADER_INIT this->instructionType = 0; #endif #define QML_INSTR_ENUM(I, FMT) I, @@ -547,6 +549,8 @@ FOR_EACH_QML_INSTR(QML_INSTR_META_TEMPLATE); template<int Instr> class QQmlInstructionData : public QQmlInstructionMeta<Instr>::DataType { +public: + QQmlInstructionData() : QQmlInstructionMeta<Instr>::DataType() { QML_INSTR_HEADER_INIT } }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 1dd8ce0e3e..90d3ca3308 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1836,6 +1836,17 @@ QList<QQmlType*> QQmlMetaType::qmlTypes() } /*! + Returns the list of all registered types. +*/ +QList<QQmlType*> QQmlMetaType::qmlAllTypes() +{ + QReadLocker lock(metaTypeDataLock()); + QQmlMetaTypeData *data = metaTypeData(); + + return data->types; +} + +/*! Returns the list of registered QML singleton types. */ QList<QQmlType*> QQmlMetaType::qmlSingletonTypes() diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 6c19da6b15..019e6b8821 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -80,6 +80,7 @@ public: static QList<QString> qmlTypeNames(); static QList<QQmlType*> qmlTypes(); static QList<QQmlType*> qmlSingletonTypes(); + static QList<QQmlType*> qmlAllTypes(); static QQmlType *qmlType(const QString &qualifiedName, int, int); static QQmlType *qmlType(const QHashedStringRef &name, const QHashedStringRef &module, int, int); diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 7cc37e0556..333c11cb29 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -2309,6 +2309,7 @@ void QQuickFlickable::timelineCompleted() return; } movementEnding(); + d->updateBeginningEnd(); } void QQuickFlickable::movementStarting() diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 6b273dcd43..973f6efdcc 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -324,7 +324,6 @@ void QQuickTouchPoint::setSceneY(qreal sceneY) QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent) : QQuickItem(parent), - _currentWindow(0), _minimumTouchPoints(0), _maximumTouchPoints(INT_MAX), _stealMouse(false) @@ -334,8 +333,8 @@ QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent) if (qmlVisualTouchDebugging()) { setFlag(QQuickItem::ItemHasContents); } -#ifdef Q_OS_MAC - connect(this, &QQuickItem::windowChanged, this, &QQuickMultiPointTouchArea::setTouchEventsEnabledForWindow); +#ifdef Q_OS_OSX + setAcceptHoverEvents(true); // needed to enable touch events on mouse hover. #endif } @@ -548,28 +547,31 @@ void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p) _pressedTouchPoints.append(dtp); } -void QQuickMultiPointTouchArea::setTouchEventsEnabledForWindow(QWindow *window) +#ifdef Q_OS_OSX +void QQuickMultiPointTouchArea::hoverEnterEvent(QHoverEvent *event) +{ + Q_UNUSED(event); + setTouchEventsEnabled(true); +} + +void QQuickMultiPointTouchArea::hoverLeaveEvent(QHoverEvent *event) +{ + Q_UNUSED(event); + setTouchEventsEnabled(false); +} + +void QQuickMultiPointTouchArea::setTouchEventsEnabled(bool enable) { -#ifdef Q_OS_MAC // Resolve function for enabling touch events from the (cocoa) platform plugin. typedef void (*RegisterTouchWindowFunction)(QWindow *, bool); RegisterTouchWindowFunction registerTouchWindow = reinterpret_cast<RegisterTouchWindowFunction>( QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow")); if (!registerTouchWindow) - return; // Not necessarily an error, Qt migh be using a different platform plugin. - - // Disable touch on the old window, enable on the new window. - if (_currentWindow) - registerTouchWindow(_currentWindow, false); - if (window) - registerTouchWindow(window, true); - // Save the current window, setTouchEventsEnabledForWindow will be called - // with a null window on disable. - _currentWindow = window; -#else // Q_OS_MAC - Q_UNUSED(window) -#endif + return; // Not necessarily an error, Qt might be using a different platform plugin. + + registerTouchWindow(window(), enable); } +#endif // Q_OS_OSX void QQuickMultiPointTouchArea::addTouchPrototype(QQuickTouchPoint *prototype) { diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h index 2e1f2a98fb..83cc407401 100644 --- a/src/quick/items/qquickmultipointtoucharea_p.h +++ b/src/quick/items/qquickmultipointtoucharea_p.h @@ -250,9 +250,11 @@ protected: bool shouldFilter(QEvent *event); void grabGesture(); virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - -protected Q_SLOTS: - void setTouchEventsEnabledForWindow(QWindow *window); +#ifdef Q_OS_OSX + void hoverEnterEvent(QHoverEvent *event); + void hoverLeaveEvent(QHoverEvent *event); + void setTouchEventsEnabled(bool enable); +#endif private: void ungrab(); @@ -261,7 +263,6 @@ private: QList<QObject*> _releasedTouchPoints; QList<QObject*> _pressedTouchPoints; QList<QObject*> _movedTouchPoints; - QWindow *_currentWindow; int _minimumTouchPoints; int _maximumTouchPoints; bool _stealMouse; diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp index 419792aaa5..f741a08512 100644 --- a/src/quick/items/qquickpincharea.cpp +++ b/src/quick/items/qquickpincharea.cpp @@ -248,14 +248,13 @@ QQuickPinchAreaPrivate::~QQuickPinchAreaPrivate() QQuickPinchArea::QQuickPinchArea(QQuickItem *parent) : QQuickItem(*(new QQuickPinchAreaPrivate), parent) - , _currentWindow(0) { Q_D(QQuickPinchArea); d->init(); setAcceptedMouseButtons(Qt::LeftButton); setFiltersChildMouseEvents(true); -#ifdef Q_OS_MAC - connect(this, &QQuickItem::windowChanged, this, &QQuickPinchArea::setTouchEventsEnabledForWindow); +#ifdef Q_OS_OSX + setAcceptHoverEvents(true); // needed to enable touch events on mouse hover. #endif } @@ -537,37 +536,39 @@ void QQuickPinchArea::itemChange(ItemChange change, const ItemChangeData &value) QQuickItem::itemChange(change, value); } -QQuickPinch *QQuickPinchArea::pinch() +#ifdef Q_OS_OSX +void QQuickPinchArea::hoverEnterEvent(QHoverEvent *event) { - Q_D(QQuickPinchArea); - if (!d->pinch) - d->pinch = new QQuickPinch; - return d->pinch; + Q_UNUSED(event); + setTouchEventsEnabled(true); } -void QQuickPinchArea::setTouchEventsEnabledForWindow(QWindow *window) +void QQuickPinchArea::hoverLeaveEvent(QHoverEvent *event) +{ + Q_UNUSED(event); + setTouchEventsEnabled(false); +} + +void QQuickPinchArea::setTouchEventsEnabled(bool enable) { -#ifdef Q_OS_MAC // Resolve function for enabling touch events from the (cocoa) platform plugin. typedef void (*RegisterTouchWindowFunction)(QWindow *, bool); RegisterTouchWindowFunction registerTouchWindow = reinterpret_cast<RegisterTouchWindowFunction>( QGuiApplication::platformNativeInterface()->nativeResourceFunctionForIntegration("registertouchwindow")); if (!registerTouchWindow) - return; // Not necessarily an error, Qt migh be using a different platform plugin. - - // Disable touch on the old window, enable on the new window. - if (_currentWindow) - registerTouchWindow(_currentWindow, false); - if (window) - registerTouchWindow(window, true); - // Save the current window, setTouchEventsEnabledForWindow will be called - // with a null window on disable. - _currentWindow = window; -#else // Q_OS_MAC - Q_UNUSED(window) -#endif + return; // Not necessarily an error, Qt might be using a different platform plugin. + + registerTouchWindow(window(), enable); } +#endif // Q_OS_OSX +QQuickPinch *QQuickPinchArea::pinch() +{ + Q_D(QQuickPinchArea); + if (!d->pinch) + d->pinch = new QQuickPinch; + return d->pinch; +} QT_END_NAMESPACE diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h index c991145fc7..81bdbda3a1 100644 --- a/src/quick/items/qquickpincharea_p.h +++ b/src/quick/items/qquickpincharea_p.h @@ -282,9 +282,11 @@ protected: virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); virtual void itemChange(ItemChange change, const ItemChangeData& value); - -private Q_SLOTS: - void setTouchEventsEnabledForWindow(QWindow *window); +#ifdef Q_OS_OSX + void hoverEnterEvent(QHoverEvent *event); + void hoverLeaveEvent(QHoverEvent *event); + void setTouchEventsEnabled(bool enable); +#endif private: void updatePinch(); @@ -292,7 +294,6 @@ private: void handleRelease(); private: - QWindow *_currentWindow; Q_DISABLE_COPY(QQuickPinchArea) Q_DECLARE_PRIVATE(QQuickPinchArea) }; diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index beb2039924..5b5dd0ef03 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -2088,7 +2088,7 @@ QRectF QQuickText::boundingRect() const Q_D(const QQuickText); QRectF rect = d->layedOutTextRect; - rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), d->hAlign)); + rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), effectiveHAlign())); rect.moveTop(QQuickTextUtil::alignedY(rect.height(), height(), d->vAlign)); if (d->style != Normal) @@ -2225,11 +2225,11 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data const QColor linkColor = QColor::fromRgba(d->linkColor); if (d->richText) { - const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), width(), d->hAlign); + const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), width(), effectiveHAlign()); d->ensureDoc(); node->addTextDocument(QPointF(dx, dy), d->extra->doc, color, d->style, styleColor, linkColor); } else if (d->layedOutTextRect.width() > 0) { - const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, width(), d->hAlign); + const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, width(), effectiveHAlign()); int unelidedLineCount = d->lineCount; if (d->elideLayout) unelidedLineCount -= 1; @@ -2501,7 +2501,7 @@ QString QQuickTextPrivate::anchorAt(const QPointF &mousePos) const link = anchorAt(elideLayout, translatedMousePos); return link; } else if (richText && extra.isAllocated() && extra->doc) { - translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), q->width(), hAlign); + translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), q->width(), q->effectiveHAlign()); return extra->doc->documentLayout()->anchorAt(translatedMousePos); } return QString(); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index c57ca5e838..a311971266 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -343,6 +343,8 @@ void QQuickWindowPrivate::syncSceneGraph() if (clearBeforeRendering) mode |= QSGRenderer::ClearColorBuffer; renderer->setClearMode(mode); + + context->endSync(); } diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 700ec051ff..1a9669f9ab 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -599,11 +599,6 @@ void Element::computeBounds() boundsOutsideFloatRange = bounds.isOutsideFloatRange(); } -RenderNodeElement::~RenderNodeElement() -{ - delete fbo; -} - bool Batch::isMaterialCompatible(Element *e) const { // If material has changed between opaque and translucent, it is not compatible @@ -751,6 +746,7 @@ Renderer::Renderer(QSGRenderContext *ctx) , m_nextRenderOrder(0) , m_partialRebuild(false) , m_partialRebuildRoot(0) + , m_useDepthBuffer(true) , m_opaqueBatches(16) , m_alphaBatches(16) , m_batchPool(16) @@ -761,6 +757,8 @@ Renderer::Renderer(QSGRenderContext *ctx) , m_zRange(0) , m_currentMaterial(0) , m_currentShader(0) + , m_currentClip(0) + , m_currentClipType(NoClip) , m_vao(0) { setNodeUpdater(new Updater(this)); @@ -809,6 +807,8 @@ Renderer::Renderer(QSGRenderContext *ctx) m_vao = new QOpenGLVertexArrayObject(this); m_vao->create(); } + + m_useDepthBuffer = ctx->openglContext()->format().depthBufferSize() > 0; } static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs) @@ -1005,6 +1005,8 @@ void Renderer::nodeWasAdded(QSGNode *node, Node *shadowParent) snode->data = e; Q_ASSERT(!m_renderNodeElements.contains(static_cast<QSGRenderNode *>(node))); m_renderNodeElements.insert(e->renderNode, e); + m_useDepthBuffer = false; + m_rebuild |= FullRebuild; } QSGNODE_TRAVERSE(node) @@ -1250,7 +1252,7 @@ void Renderer::buildRenderLists(QSGNode *node) Q_ASSERT(e); bool opaque = gn->inheritedOpacity() > OPAQUE_LIMIT && !(gn->activeMaterial()->flags() & QSGMaterial::Blending); - if (opaque) + if (opaque && m_useDepthBuffer) m_opaqueRenderList << e; else m_alphaRenderList << e; @@ -1631,10 +1633,13 @@ void Renderer::uploadMergedElement(Element *e, int vaOffset, char **vertexData, } } - float *vzorder = (float *) *zData; - float zorder = 1.0f - e->order * m_zRange; - for (int i=0; i<vCount; ++i) - vzorder[i] = zorder; + if (m_useDepthBuffer) { + float *vzorder = (float *) *zData; + float zorder = 1.0f - e->order * m_zRange; + for (int i=0; i<vCount; ++i) + vzorder[i] = zorder; + *zData += vCount * sizeof(float); + } int iCount = g->indexCount(); quint16 *indices = (quint16 *) *indexData; @@ -1658,7 +1663,6 @@ void Renderer::uploadMergedElement(Element *e, int vaOffset, char **vertexData, } *vertexData += vCount * vSize; - *zData += vCount * sizeof(float); *indexData += iCount * sizeof(quint16); *iBase += vCount; *indexCount += iCount; @@ -1754,8 +1758,9 @@ void Renderer::uploadBatch(Batch *b) int bufferSize = b->vertexCount * g->sizeOfVertex(); int ibufferSize = 0; if (b->merged) { - bufferSize += b->vertexCount * sizeof(float); ibufferSize = b->indexCount * sizeof(quint16); + if (m_useDepthBuffer) + bufferSize += b->vertexCount * sizeof(float); } else { ibufferSize = unmergedIndexSize; } @@ -1777,7 +1782,7 @@ void Renderer::uploadBatch(Batch *b) #ifdef QSG_SEPARATE_INDEX_BUFFER char *indexData = b->ibo.data; #else - char *indexData = zData + b->vertexCount * sizeof(float); + char *indexData = zData + (m_useDepthBuffer ? b->vertexCount * sizeof(float) : 0); #endif quint16 iOffset = 0; @@ -1857,7 +1862,7 @@ void Renderer::uploadBatch(Batch *b) dump << ") "; offset += attr.tupleSize * size_of_type(attr.type); } - if (b->merged) { + if (b->merged && m_useDepthBuffer) { float zorder = ((float*)(b->vbo.data + b->vertexCount * g->sizeOfVertex()))[i]; dump << " Z:(" << zorder << ")"; } @@ -1907,10 +1912,10 @@ void Renderer::updateClip(const QSGClipNode *clipList, const Batch *batch) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); if (batch->isOpaque) glDisable(GL_DEPTH_TEST); - ClipType type = updateStencilClip(m_currentClip); + m_currentClipType = updateStencilClip(m_currentClip); if (batch->isOpaque) { glEnable(GL_DEPTH_TEST); - if (type & StencilClip) + if (m_currentClipType & StencilClip) glDepthMask(true); } } @@ -2025,7 +2030,7 @@ void Renderer::renderMergedBatch(const Batch *batch) QSGMaterial *material = gn->activeMaterial(); - ShaderManager::Shader *sms = m_shaderManager->prepareMaterial(material); + ShaderManager::Shader *sms = m_useDepthBuffer ? m_shaderManager->prepareMaterial(material) : m_shaderManager->prepareMaterialNoRewrite(material); QSGMaterialShader *program = sms->program; if (m_currentShader != sms) @@ -2054,7 +2059,8 @@ void Renderer::renderMergedBatch(const Batch *batch) glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, g->sizeOfVertex(), (void *) (qintptr) (offset + draw.vertices)); offset += a.tupleSize * size_of_type(a.type); } - glVertexAttribPointer(sms->pos_order, 1, GL_FLOAT, false, 0, (void *) (qintptr) (draw.zorders)); + if (m_useDepthBuffer) + glVertexAttribPointer(sms->pos_order, 1, GL_FLOAT, false, 0, (void *) (qintptr) (draw.zorders)); glDrawElements(g->drawingMode(), draw.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (indexBase + draw.indices)); } @@ -2136,8 +2142,10 @@ void Renderer::renderUnmergedBatch(const Batch *batch) m_current_determinant = m_current_model_view_matrix.determinant(); m_current_projection_matrix = projectionMatrix(); - m_current_projection_matrix(2, 2) = m_zRange; - m_current_projection_matrix(2, 3) = 1.0f - e->order * m_zRange; + if (m_useDepthBuffer) { + m_current_projection_matrix(2, 2) = m_zRange; + m_current_projection_matrix(2, 3) = 1.0f - e->order * m_zRange; + } program->updateState(state(dirty), material, m_currentMaterial); @@ -2187,25 +2195,25 @@ void Renderer::renderBatches() << " -> Alpha: " << qsg_countNodesInBatches(m_alphaBatches) << " nodes in " << m_alphaBatches.size() << " batches..."; } - for (QHash<QSGRenderNode *, RenderNodeElement *>::const_iterator it = m_renderNodeElements.constBegin(); - it != m_renderNodeElements.constEnd(); ++it) { - prepareRenderNode(it.value()); - } - QRect r = viewportRect(); glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height()); glClearColor(clearColor().redF(), clearColor().greenF(), clearColor().blueF(), clearColor().alphaF()); + + if (m_useDepthBuffer) { #if defined(QT_OPENGL_ES) - glClearDepthf(1); + glClearDepthf(1); #else - glClearDepth(1); + glClearDepth(1); #endif - + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glDepthMask(true); + glDisable(GL_BLEND); + } else { + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + } glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glDepthMask(true); glColorMask(true, true, true, true); glDisable(GL_SCISSOR_TEST); glDisable(GL_STENCIL_TEST); @@ -2232,7 +2240,8 @@ void Renderer::renderBatches() } glEnable(GL_BLEND); - glDepthMask(false); + if (m_useDepthBuffer) + glDepthMask(false); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); if (Q_LIKELY(renderAlpha)) { @@ -2252,7 +2261,6 @@ void Renderer::renderBatches() updateStencilClip(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } void Renderer::deleteRemovedElements() @@ -2404,33 +2412,15 @@ void Renderer::render() m_vao->release(); } -void Renderer::prepareRenderNode(RenderNodeElement *e) +void Renderer::renderRenderNode(Batch *batch) { - if (e->fbo && e->fbo->size() != deviceRect().size()) { - delete e->fbo; - e->fbo = 0; - } + if (Q_UNLIKELY(debug_render)) + qDebug() << " -" << batch << "rendernode"; - if (!e->fbo) - e->fbo = new QOpenGLFramebufferObject(deviceRect().size(), QOpenGLFramebufferObject::CombinedDepthStencil); - e->fbo->bind(); + Q_ASSERT(batch->first->isRenderNode); + RenderNodeElement *e = (RenderNodeElement *) batch->first; - glDisable(GL_STENCIL_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - QSGRenderNode::RenderState state; - QMatrix4x4 pm = projectionMatrix(); - state.projectionMatrix = ± - state.scissorEnabled = false; - state.stencilEnabled = false; + setActiveShader(0, 0); QSGNode *clip = e->renderNode->parent(); e->renderNode->m_clip_list = 0; @@ -2442,6 +2432,16 @@ void Renderer::prepareRenderNode(RenderNodeElement *e) clip = clip->parent(); } + updateClip(e->renderNode->m_clip_list, batch); + + QSGRenderNode::RenderState state; + QMatrix4x4 pm = projectionMatrix(); + state.projectionMatrix = ± + state.scissorEnabled = m_currentClipType & ScissorClip; + state.stencilEnabled = m_currentClipType & StencilClip; + state.scissorRect = m_current_scissor_rect; + state.stencilValue = m_current_stencil_value; + QSGNode *xform = e->renderNode->parent(); QMatrix4x4 matrix; while (xform != rootNode()) { @@ -2463,66 +2463,51 @@ void Renderer::prepareRenderNode(RenderNodeElement *e) opacity = opacity->parent(); } + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DEPTH_TEST); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + e->renderNode->render(state); e->renderNode->m_matrix = 0; + e->renderNode->m_clip_list = 0; - bindable()->bind(); -} - -void Renderer::renderRenderNode(Batch *batch) -{ - updateStencilClip(0); - m_currentClip = 0; - - setActiveShader(0, 0); - - if (!m_shaderManager->blitProgram) { - m_shaderManager->blitProgram = new QOpenGLShaderProgram(); - - QSGShaderSourceBuilder::initializeProgramFromFiles( - m_shaderManager->blitProgram, - QStringLiteral(":/scenegraph/shaders/rendernode.vert"), - QStringLiteral(":/scenegraph/shaders/rendernode.frag")); - m_shaderManager->blitProgram->bindAttributeLocation("av", 0); - m_shaderManager->blitProgram->bindAttributeLocation("at", 1); - m_shaderManager->blitProgram->link(); - - Q_ASSERT(m_shaderManager->blitProgram->isLinked()); + QSGRenderNode::StateFlags changes = e->renderNode->changedStates(); + if (changes & QSGRenderNode::ViewportState) { + QRect r = viewportRect(); + glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height()); } - RenderNodeElement *e = static_cast<RenderNodeElement *>(batch->first); - glBindTexture(GL_TEXTURE_2D, e->fbo->texture()); - - m_shaderManager->blitProgram->bind(); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + if (changes & QSGRenderNode::StencilState) { + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilMask(0xff); + glDisable(GL_STENCIL_TEST); + } - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); + if (changes & (QSGRenderNode::StencilState | QSGRenderNode::ScissorState)) { + glDisable(GL_SCISSOR_TEST); + m_currentClip = 0; + m_currentClipType = NoClip; + } - float z = 1.0f - e->order * m_zRange; + if (changes & QSGRenderNode::DepthState) + glDisable(GL_DEPTH_TEST); - float av[] = { -1, -1, z, - 1, -1, z, - -1, 1, z, - 1, 1, z }; - float at[] = { 0, 0, - 1, 0, - 0, 1, - 1, 1 }; + if (changes & QSGRenderNode::ColorState) + bindable()->reactivate(); - glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, av); - glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, at); + if (changes & QSGRenderNode::BlendState) { + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + if (changes & QSGRenderNode::CullState) { + glFrontFace(isMirrored() ? GL_CW : GL_CCW); + glDisable(GL_CULL_FACE); + } - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glBindTexture(GL_TEXTURE_2D, 0); } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 001c3b21ab..0aa84da185 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -194,15 +194,11 @@ struct RenderNodeElement : public Element { RenderNodeElement(QSGRenderNode *rn) : Element(0) , renderNode(rn) - , fbo(0) { isRenderNode = true; } - ~RenderNodeElement(); - QSGRenderNode *renderNode; - QOpenGLFramebufferObject *fbo; }; struct BatchRootInfo { @@ -436,7 +432,6 @@ private: void renderUnmergedBatch(const Batch *batch); void updateClip(const QSGClipNode *clipList, const Batch *batch); const QMatrix4x4 &matrixForRoot(Node *node); - void prepareRenderNode(RenderNodeElement *e); void renderRenderNode(Batch *batch); void setActiveShader(QSGMaterialShader *program, ShaderManager::Shader *shader); @@ -460,6 +455,8 @@ private: bool m_partialRebuild; QSGNode *m_partialRebuildRoot; + bool m_useDepthBuffer; + QHash<QSGRenderNode *, RenderNodeElement *> m_renderNodeElements; QDataBuffer<Batch *> m_opaqueBatches; QDataBuffer<Batch *> m_alphaBatches; @@ -483,6 +480,7 @@ private: QSGMaterialShader *m_currentProgram; ShaderManager::Shader *m_currentShader; const QSGClipNode *m_currentClip; + ClipType m_currentClipType; // For minimal OpenGL core profile support QOpenGLVertexArrayObject *m_vao; diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 90803db9fe..829d33a0d7 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -210,10 +210,17 @@ void QSGContext::renderContextInitialized(QSGRenderContext *renderContext) static bool dumped = false; if (!dumped && qEnvironmentVariableIsSet("QSG_INFO")) { dumped = true; - qDebug() << "GL_VENDOR: " << (const char *) glGetString(GL_VENDOR); - qDebug() << "GL_RENDERER: " << (const char *) glGetString(GL_RENDERER); - qDebug() << "GL_VERSION: " << (const char *) glGetString(GL_VERSION); - qDebug() << "GL_EXTENSIONS:\n " << QByteArray((const char *) glGetString(GL_EXTENSIONS)).replace(" ", "\n ").constData(); + QSurfaceFormat format = renderContext->openglContext()->format(); + qDebug() << "R/G/B/A Buffers: " << format.redBufferSize() << format.greenBufferSize() << format.blueBufferSize() << format.alphaBufferSize(); + qDebug() << "Depth Buffer: " << format.depthBufferSize(); + qDebug() << "Stencil Buffer: " << format.stencilBufferSize(); + qDebug() << "Samples: " << format.samples(); + qDebug() << "GL_VENDOR: " << (const char *) glGetString(GL_VENDOR); + qDebug() << "GL_RENDERER: " << (const char *) glGetString(GL_RENDERER); + qDebug() << "GL_VERSION: " << (const char *) glGetString(GL_VERSION); + QSet<QByteArray> exts = renderContext->openglContext()->extensions(); + QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e; + qDebug() << "GL_EXTENSIONS: " << all.constData(); } d->mutex.unlock(); @@ -282,8 +289,10 @@ QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc) QSurfaceFormat QSGContext::defaultSurfaceFormat() const { QSurfaceFormat format; - format.setDepthBufferSize(24); - format.setStencilBufferSize(8); + static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER"); + static bool useStencil = qEnvironmentVariableIsEmpty("QSG_NO_STENCIL_BUFFER"); + format.setDepthBufferSize(useDepth ? 24 : 0); + format.setStencilBufferSize(useStencil ? 8 : 0); if (QQuickWindow::hasDefaultAlphaBuffer()) format.setAlphaBufferSize(8); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); @@ -349,6 +358,12 @@ QSGRenderContext::~QSGRenderContext() invalidate(); } +void QSGRenderContext::endSync() +{ + qDeleteAll(m_texturesToDelete); + m_texturesToDelete.clear(); +} + static QBasicMutex qsg_framerender_mutex; void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId) @@ -466,6 +481,9 @@ void QSGRenderContext::invalidate() if (!m_gl) return; + qDeleteAll(m_texturesToDelete); + m_texturesToDelete.clear(); + qDeleteAll(m_textures.values()); m_textures.clear(); @@ -608,10 +626,8 @@ QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, Q void QSGRenderContext::textureFactoryDestroyed(QObject *o) { m_mutex.lock(); - QSGTexture *t = m_textures.take(static_cast<QQuickTextureFactory *>(o)); + m_texturesToDelete << m_textures.take(static_cast<QQuickTextureFactory *>(o)); m_mutex.unlock(); - if (t) - t->deleteLater(); } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index c562a909c5..c1bf78a018 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -94,6 +94,7 @@ public: virtual void invalidate(); virtual void renderNextFrame(QSGRenderer *renderer, GLuint fboId); + virtual void endSync(); virtual QSharedPointer<QSGDepthStencilBuffer> depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo); QSGDepthStencilBufferManager *depthStencilBufferManager(); @@ -124,6 +125,7 @@ protected: QMutex m_mutex; QHash<QQuickTextureFactory *, QSGTexture *> m_textures; + QSet<QSGTexture *> m_texturesToDelete; QSGAtlasTexture::Manager *m_atlasManager; QSGDepthStencilBufferManager *m_depthStencilManager; diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp index fb989fd6fb..810a503cee 100644 --- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp +++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp @@ -385,7 +385,7 @@ void QSGDefaultRectangleNode::updateGeometry() int borderTail = 0; int outerAAHead = 0; int outerAATail = 0; - bool hasFill = m_color.rgba() != 0 || !stops.isEmpty(); + bool hasFill = m_color.alpha() > 0 || !stops.isEmpty(); if (hasFill) indexCount += fillIndexCount; if (m_antialiasing) { @@ -609,7 +609,7 @@ void QSGDefaultRectangleNode::updateGeometry() int borderTail = 0; int outerAAHead = 0; int outerAATail = 0; - bool hasFill = m_color.rgba() != 0 || !stops.isEmpty(); + bool hasFill = m_color.alpha() > 0 || !stops.isEmpty(); if (hasFill) indexCount += fillIndexCount; if (m_antialiasing) { diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 6e0fdc7290..d080c59198 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -48,6 +48,7 @@ #include <QtGui/QGuiApplication> #include <QtGui/QScreen> #include <QtGui/QSurface> +#include <QtGui/qpa/qplatformnativeinterface.h> #include <private/qsgtexture_p.h> @@ -144,10 +145,21 @@ Atlas::Atlas(const QSize &size) { #ifdef QT_OPENGL_ES +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) + QString *deviceName = + static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); + static bool wrongfullyReportsBgra8888Support = deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0; +#else + static bool wrongfullyReportsBgra8888Support = false; +#endif + const char *ext = (const char *) glGetString(GL_EXTENSIONS); - if (strstr(ext, "GL_EXT_bgra") - || strstr(ext, "GL_EXT_texture_format_BGRA8888") - || strstr(ext, "GL_IMG_texture_format_BGRA8888")) { + if (!wrongfullyReportsBgra8888Support + && (strstr(ext, "GL_EXT_bgra") + || strstr(ext, "GL_EXT_texture_format_BGRA8888") + || strstr(ext, "GL_IMG_texture_format_BGRA8888"))) { m_internalFormat = m_externalFormat = GL_BGRA; #ifdef Q_OS_IOS } else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) { diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index d84ccb7a1f..ae1bec3f42 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -47,8 +47,10 @@ #include <qthread.h> #include <private/qqmlprofilerservice_p.h> #include <private/qqmlglobal_p.h> +#include <QtGui/qguiapplication.h> +#include <QtGui/qpa/qplatformnativeinterface.h> -#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && !defined(__UCLIBC__) #define CAN_BACKTRACE_EXECINFO #endif @@ -679,14 +681,25 @@ void QSGPlainTexture::bind() GLenum externalFormat = GL_RGBA; GLenum internalFormat = GL_RGBA; +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) + QString *deviceName = + static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); + static bool wrongfullyReportsBgra8888Support = deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0; +#else + static bool wrongfullyReportsBgra8888Support = false; +#endif + QOpenGLContext *context = QOpenGLContext::currentContext(); if (context->hasExtension(QByteArrayLiteral("GL_EXT_bgra"))) { externalFormat = GL_BGRA; #ifdef QT_OPENGL_ES internalFormat = GL_BGRA; #endif - } else if (context->hasExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888")) - || context->hasExtension(QByteArrayLiteral("GL_IMG_texture_format_BGRA8888"))) { + } else if (!wrongfullyReportsBgra8888Support + && (context->hasExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888")) + || context->hasExtension(QByteArrayLiteral("GL_IMG_texture_format_BGRA8888")))) { externalFormat = GL_BGRA; internalFormat = GL_BGRA; #ifdef Q_OS_IOS diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml new file mode 100644 index 0000000000..25e63669c4 --- /dev/null +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +Rectangle { + width: 400 + height: 400 + + onWidthChanged: console.log(width); + Component.onCompleted: width = 500; +} diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro index 87d8b647d1..647d761dc4 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro +++ b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro @@ -19,4 +19,5 @@ OTHER_FILES += \ data/test.qml \ data/exit.qml \ data/scenegraphTest.qml \ - data/TestImage_2x2.png + data/TestImage_2x2.png \ + data/signalSourceLocation.qml diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 56ed65f54d..9d2e0ecbb4 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -181,6 +181,7 @@ private slots: void scenegraphData(); void profileOnExit(); void controlFromJS(); + void signalSourceLocation(); }; void QQmlProfilerClient::messageReceived(const QByteArray &message) @@ -513,6 +514,35 @@ void tst_QQmlProfilerService::controlFromJS() QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerClient::EndTrace); } +void tst_QQmlProfilerService::signalSourceLocation() +{ + connect(true, "signalSourceLocation.qml"); + QVERIFY(m_client); + QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); + + m_client->setTraceState(true); + while (!(m_process->output().contains(QLatin1String("500")))) + QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); + m_client->setTraceState(false); + QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(complete())), "No trace received in time."); + + // must start with "StartTrace" + QCOMPARE(m_client->traceMessages.first().messageType, (int)QQmlProfilerClient::Event); + QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace); + + QVERIFY(m_client->traceMessages[14].detailData.endsWith("signalSourceLocation.qml")); + QVERIFY(m_client->traceMessages[14].line == 8); + QVERIFY(m_client->traceMessages[14].column == 28); + + QVERIFY(m_client->traceMessages[16].detailData.endsWith("signalSourceLocation.qml")); + QVERIFY(m_client->traceMessages[16].line == 7); + QVERIFY(m_client->traceMessages[16].column == 21); + + // must end with "EndTrace" + QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event); + QCOMPARE(m_client->traceMessages.last().detailType, (int)QQmlProfilerClient::EndTrace); +} + QTEST_MAIN(tst_QQmlProfilerService) #include "tst_qqmlprofilerservice.moc" diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index a1662b495c..ba99b34935 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -148,6 +148,8 @@ private slots: void functionDeclarationsInConditionals(); void arrayPop_QTBUG_35979(); + + void regexpLastMatch(); }; tst_QJSEngine::tst_QJSEngine() @@ -2705,6 +2707,68 @@ void tst_QJSEngine::arrayPop_QTBUG_35979() QCOMPARE(result.toString(), QString("1,3")); } +void tst_QJSEngine::regexpLastMatch() +{ + QJSEngine eng; + + QCOMPARE(eng.evaluate("RegExp.input").toString(), QString()); + + QJSValue hasProperty; + + for (int i = 1; i < 9; ++i) { + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"$" + QString::number(i) + "\")"); + QVERIFY(hasProperty.isBool()); + QVERIFY(hasProperty.toBool()); + } + + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"$0\")"); + QVERIFY(hasProperty.isBool()); + QVERIFY(!hasProperty.toBool()); + + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"$10\")"); + QVERIFY(!hasProperty.toBool()); + + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"lastMatch\")"); + QVERIFY(hasProperty.toBool()); + hasProperty = eng.evaluate("RegExp.hasOwnProperty(\"$&\")"); + QVERIFY(hasProperty.toBool()); + + QJSValue result = eng.evaluate("" + "var re = /h(el)l(o)/\n" + "var text = \"blah hello world\"\n" + "text.match(re)\n"); + QVERIFY(!result.isError()); + QJSValue match = eng.evaluate("RegExp.$1"); + QCOMPARE(match.toString(), QString("el")); + match = eng.evaluate("RegExp.$2"); + QCOMPARE(match.toString(), QString("o")); + for (int i = 3; i <= 9; ++i) { + match = eng.evaluate("RegExp.$" + QString::number(i)); + QVERIFY(match.isString()); + QCOMPARE(match.toString(), QString()); + } + QCOMPARE(eng.evaluate("RegExp.input").toString(), QString("blah hello world")); + QCOMPARE(eng.evaluate("RegExp.lastParen").toString(), QString("o")); + QCOMPARE(eng.evaluate("RegExp.leftContext").toString(), QString("blah ")); + QCOMPARE(eng.evaluate("RegExp.rightContext").toString(), QString(" world")); + + QCOMPARE(eng.evaluate("RegExp.lastMatch").toString(), QString("hello")); + + result = eng.evaluate("" + "var re = /h(ello)/\n" + "var text = \"hello\"\n" + "text.match(re)\n"); + QVERIFY(!result.isError()); + match = eng.evaluate("RegExp.$1"); + QCOMPARE(match.toString(), QString("ello")); + for (int i = 2; i <= 9; ++i) { + match = eng.evaluate("RegExp.$" + QString::number(i)); + QVERIFY(match.isString()); + QCOMPARE(match.toString(), QString()); + } + +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 86321c775e..59b54e7ba5 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -1440,17 +1440,23 @@ void tst_qquickflickable::stopAtBounds_data() { QTest::addColumn<bool>("transpose"); QTest::addColumn<bool>("invert"); - - QTest::newRow("left") << false << false; - QTest::newRow("right") << false << true; - QTest::newRow("top") << true << false; - QTest::newRow("bottom") << true << true; + QTest::addColumn<bool>("pixelAligned"); + + QTest::newRow("left") << false << false << false; + QTest::newRow("right") << false << true << false; + QTest::newRow("top") << true << false << false; + QTest::newRow("bottom") << true << true << false; + QTest::newRow("left,pixelAligned") << false << false << true; + QTest::newRow("right,pixelAligned") << false << true << true; + QTest::newRow("top,pixelAligned") << true << false << true; + QTest::newRow("bottom,pixelAligned") << true << true << true; } void tst_qquickflickable::stopAtBounds() { QFETCH(bool, transpose); QFETCH(bool, invert); + QFETCH(bool, pixelAligned); QQuickView view; view.setSource(testFileUrl("stopAtBounds.qml")); @@ -1469,6 +1475,7 @@ void tst_qquickflickable::stopAtBounds() flickable->setContentY(invert ? 100 : 0); else flickable->setContentX(invert ? 100 : 0); + flickable->setPixelAligned(pixelAligned); const int threshold = qApp->styleHints()->startDragDistance(); @@ -1518,6 +1525,29 @@ void tst_qquickflickable::stopAtBounds() } QTest::mouseRelease(&view, Qt::LeftButton, 0, position); + + if (transpose) { + flickable->setContentY(invert ? 100 : 0); + } else { + flickable->setContentX(invert ? 100 : 0); + } + if (invert) + flick(&view, QPoint(20,20), QPoint(100,100), 100); + else + flick(&view, QPoint(100,100), QPoint(20,20), 100); + + QVERIFY(flickable->isFlicking()); + if (transpose) { + if (invert) + QTRY_COMPARE(flickable->isAtYBeginning(), true); + else + QTRY_COMPARE(flickable->isAtYEnd(), true); + } else { + if (invert) + QTRY_COMPARE(flickable->isAtXBeginning(), true); + else + QTRY_COMPARE(flickable->isAtXEnd(), true); + } } void tst_qquickflickable::nestedMouseAreaUsingTouch() diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index d241ac2d70..e6a74bb062 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -1724,6 +1724,12 @@ void tst_qquicktext::linkInteraction_data() << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center()) << singleLineLink << singleLineLink << singleLineLink; + QTest::newRow("click on mirrored link") + << singleLineText << 240. + << "horizontalAlignment: Text.AlignLeft; LayoutMirroring.enabled: true" + << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignTop).center()) + << singleLineLink + << singleLineLink << singleLineLink; QTest::newRow("click on center aligned link") << singleLineText << 240. << "horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter" @@ -2545,6 +2551,18 @@ void tst_qquicktext::boundingRect() QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); QCOMPARE(text->boundingRect().height(), line.height()); + QQuickItemPrivate::get(text)->setLayoutMirror(true); + QCOMPARE(text->boundingRect().x(), qreal(0)); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(text->boundingRect().height(), line.height()); + + text->setHAlign(QQuickText::AlignLeft); + QCOMPARE(text->boundingRect().x(), text->width() - line.naturalTextWidth()); + QCOMPARE(text->boundingRect().y(), qreal(0)); + QCOMPARE(text->boundingRect().width(), line.naturalTextWidth()); + QCOMPARE(text->boundingRect().height(), line.height()); + text->setWrapMode(QQuickText::Wrap); QCOMPARE(text->boundingRect().right(), text->width()); QCOMPARE(text->boundingRect().y(), qreal(0)); diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 6939ce92e2..d53005109e 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -98,14 +98,14 @@ void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *met const QMetaObject *meta = object->metaObject(); if (verbose) - qDebug() << "Processing object" << meta->className(); + std::cerr << "Processing object" << qPrintable( meta->className() ) << std::endl; collectReachableMetaObjects(meta, metas); for (int index = 0; index < meta->propertyCount(); ++index) { QMetaProperty prop = meta->property(index); if (QQmlMetaType::isQObject(prop.userType())) { if (verbose) - qDebug() << " Processing property" << prop.name(); + std::cerr << " Processing property" << qPrintable( prop.name() ) << std::endl; currentProperty = QString("%1::%2").arg(meta->className(), prop.name()); // if the property was not initialized during construction, @@ -175,20 +175,41 @@ QByteArray convertToId(const QMetaObject *mo) if (!className.isEmpty()) return className; - qWarning() << "Found a QMetaObject without a className, generating a random name"; + std::cerr << "Found a QMetaObject without a className, generating a random name" << std::endl; className = QByteArray("error-unknown-name-"); className.append(QByteArray::number(generatedNames.size())); generatedNames.insert(mo, className); return className; } -QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const QList<QQmlType *> &skip = QList<QQmlType *>()) + +// Collect all metaobjects for types registered with qmlRegisterType() without parameters +void collectReachableMetaObjectsWithoutQmlName( QSet<const QMetaObject *>& metas ) { + foreach (const QQmlType *ty, QQmlMetaType::qmlAllTypes()) { + if ( ! metas.contains(ty->metaObject()) ) { + if (!ty->isComposite()) { + collectReachableMetaObjects(ty, &metas); + } else { + qmlTypesByCompositeName[ty->elementName()] = ty; + } + } + } +} + +QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, + QSet<const QMetaObject *> &noncreatables, + QSet<const QMetaObject *> &singletons, + const QList<QQmlType *> &skip = QList<QQmlType *>()) { QSet<const QMetaObject *> metas; metas.insert(FriendlyQObject::qtMeta()); QHash<QByteArray, QSet<QByteArray> > extensions; foreach (const QQmlType *ty, QQmlMetaType::qmlTypes()) { + if (!ty->isCreatable()) + noncreatables.insert(ty->metaObject()); + if (ty->isSingleton()) + singletons.insert(ty->metaObject()); if (!ty->isComposite()) { qmlTypesByCppName[ty->metaObject()->className()].insert(ty); if (ty->isExtendedType()) @@ -255,15 +276,15 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const if (ty->isSingleton()) { QQmlType::SingletonInstanceInfo *siinfo = ty->singletonInstanceInfo(); if (!siinfo) { - qWarning() << "Internal error, " << tyName - << "(" << QString::fromUtf8(ty->typeName()) << ")" - << " is singleton, but has no singletonInstanceInfo"; + std::cerr << "Internal error, " << qPrintable(tyName) + << "(" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")" + << " is singleton, but has no singletonInstanceInfo" << std::endl; continue; } if (siinfo->qobjectCallback) { if (verbose) - qDebug() << "Trying to get singleton for " << tyName - << " (" << siinfo->typeName << ")"; + std::cerr << "Trying to get singleton for " << qPrintable(tyName) + << " (" << qPrintable( siinfo->typeName ) << ")" << std::endl; siinfo->init(engine); collectReachableMetaObjects(object, &metas); object = siinfo->qobjectApi(engine); @@ -273,8 +294,8 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const } } else { if (verbose) - qDebug() << "Trying to create object " << tyName - << " (" << QString::fromUtf8(ty->typeName()) << ")"; + std::cerr << "Trying to create object " << qPrintable( tyName ) + << " (" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")" << std::endl; object = ty->create(); } @@ -282,15 +303,17 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const if (object) { if (verbose) - qDebug() << "Got " << tyName - << " (" << QString::fromUtf8(ty->typeName()) << ")"; + std::cerr << "Got " << qPrintable( tyName ) + << " (" << qPrintable( QString::fromUtf8(ty->typeName()) ) << ")" << std::endl; collectReachableMetaObjects(object, &metas); } else { - qWarning() << "Could not create" << tyName; + std::cerr << "Could not create" << qPrintable(tyName) << std::endl; } } } + collectReachableMetaObjectsWithoutQmlName(metas); + return metas; } @@ -406,6 +429,12 @@ public: qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString); qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType->minorVersion())); + if (compositeType->isCreatable()) + qml->writeIsCreatable(false); + + if (compositeType->isSingleton()) + qml->writeIsSingleton(true); + for (int index = mainMeta->classInfoCount() - 1 ; index >= 0 ; --index) { QMetaClassInfo classInfo = mainMeta->classInfo(index); if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) { @@ -437,7 +466,7 @@ public: qml->writeEndObject(); } - void dump(const QMetaObject *meta) + void dump(const QMetaObject *meta, bool isUncreatable, bool isSingleton) { qml->writeStartObject("Component"); @@ -469,6 +498,12 @@ public: std::sort(exportStrings.begin(), exportStrings.end()); qml->writeArrayBinding(QLatin1String("exports"), exportStrings); + if (isUncreatable) + qml->writeIsCreatable(false); + + if (isSingleton) + qml->writeIsSingleton(true); + // write meta object revisions QStringList metaObjectRevisions; foreach (const QString &exportString, exportStrings) { @@ -622,7 +657,6 @@ private: } }; - enum ExitCode { EXIT_INVALIDARGUMENTS = 1, EXIT_SEGV = 2, @@ -642,12 +676,12 @@ void sigSegvHandler(int) { void printUsage(const QString &appName) { - qWarning() << qPrintable(QString( + std::cerr << qPrintable(QString( "Usage: %1 [-v] [-noinstantiate] [-defaultplatform] [-[non]relocatable] module.uri version [module/import/path]\n" " %1 [-v] [-noinstantiate] -path path/to/qmldir/directory [version]\n" " %1 [-v] -builtins\n" "Example: %1 Qt.labs.folderlistmodel 2.0 /home/user/dev/qt-install/imports").arg( - appName)); + appName)) << std::endl; } int main(int argc, char *argv[]) @@ -726,14 +760,14 @@ int main(int argc, char *argv[]) || arg == QLatin1String("-defaultplatform")) { continue; } else { - qWarning() << "Invalid argument: " << arg; + std::cerr << "Invalid argument: " << qPrintable(arg) << std::endl; return EXIT_INVALIDARGUMENTS; } } if (action == Uri) { if (positionalArgs.size() != 3 && positionalArgs.size() != 4) { - qWarning() << "Incorrect number of positional arguments"; + std::cerr << "Incorrect number of positional arguments" << std::endl; return EXIT_INVALIDARGUMENTS; } pluginImportUri = positionalArgs[1]; @@ -742,7 +776,7 @@ int main(int argc, char *argv[]) pluginImportPath = positionalArgs[3]; } else if (action == Path) { if (positionalArgs.size() != 2 && positionalArgs.size() != 3) { - qWarning() << "Incorrect number of positional arguments"; + std::cerr << "Incorrect number of positional arguments" << std::endl; return EXIT_INVALIDARGUMENTS; } pluginImportPath = QDir::fromNativeSeparators(positionalArgs[1]); @@ -750,7 +784,7 @@ int main(int argc, char *argv[]) pluginImportVersion = positionalArgs[2]; } else if (action == Builtins) { if (positionalArgs.size() != 1) { - qWarning() << "Incorrect number of positional arguments"; + std::cerr << "Incorrect number of positional arguments" << std::endl; return EXIT_INVALIDARGUMENTS; } } @@ -760,7 +794,7 @@ int main(int argc, char *argv[]) if (!pluginImportPath.isEmpty()) { QDir cur = QDir::current(); cur.cd(pluginImportPath); - pluginImportPath = cur.absolutePath(); + pluginImportPath = cur.canonicalPath(); QDir::setCurrent(pluginImportPath); engine.addImportPath(pluginImportPath); } @@ -773,13 +807,15 @@ int main(int argc, char *argv[]) c.create(); if (!c.errors().isEmpty()) { foreach (const QQmlError &error, c.errors()) - qWarning() << error.toString(); + std::cerr << qPrintable( error.toString() ) << std::endl; return EXIT_IMPORTERROR; } } // find all QMetaObjects reachable from the builtin module - QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(&engine); + QSet<const QMetaObject *> uncreatableMetas; + QSet<const QMetaObject *> singletonMetas; + QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas); QList<QQmlType *> defaultTypes = QQmlMetaType::qmlTypes(); // add some otherwise unreachable QMetaObjects @@ -797,7 +833,7 @@ int main(int argc, char *argv[]) QByteArray importCode; QQmlType *qtObjectType = QQmlMetaType::qmlType(&QObject::staticMetaObject); if (!qtObjectType) { - qWarning() << "Could not find QtObject type"; + std::cerr << "Could not find QtObject type" << std::endl; importCode = QByteArray("import QtQuick 2.0\n"); } else { QString module = qtObjectType->qmlTypeName(); @@ -826,12 +862,12 @@ int main(int argc, char *argv[]) c.create(); if (!c.errors().isEmpty()) { foreach (const QQmlError &error, c.errors()) - qWarning() << error.toString(); + std::cerr << qPrintable( error.toString() ) << std::endl; return EXIT_IMPORTERROR; } } - QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, defaultTypes); + QSet<const QMetaObject *> candidates = collectReachableMetaObjects(&engine, uncreatableMetas, singletonMetas, defaultTypes); candidates.subtract(defaultReachable); // Also eliminate meta objects with the same classname. @@ -873,7 +909,7 @@ int main(int argc, char *argv[]) if (relocatable) dumper.setRelocatableModuleUri(pluginImportUri); foreach (const QMetaObject *meta, nameToMeta) { - dumper.dump(meta); + dumper.dump(meta, uncreatableMetas.contains(meta), singletonMetas.contains(meta)); } foreach (const QQmlType *compositeType, qmlTypesByCompositeName) dumper.dumpComposite(&engine, compositeType, defaultReachableNames); diff --git a/tools/qmlplugindump/qmlstreamwriter.cpp b/tools/qmlplugindump/qmlstreamwriter.cpp index 629e30b814..44bdcfea74 100644 --- a/tools/qmlplugindump/qmlstreamwriter.cpp +++ b/tools/qmlplugindump/qmlstreamwriter.cpp @@ -183,6 +183,16 @@ void QmlStreamWriter::writePotentialLine(const QByteArray &line) } } +void QmlStreamWriter::writeIsCreatable(bool isCreatable) { + writeIndent(); + m_stream->write(QString("isCreatable: %1\n").arg(isCreatable ? "true" : "false").toUtf8()); +} + +void QmlStreamWriter::writeIsSingleton(bool isSingleton) { + writeIndent(); + m_stream->write(QString("isSingleton: %1\n").arg(isSingleton ? "true" : "false").toUtf8()); +} + void QmlStreamWriter::flushPotentialLinesWithNewlines() { if (m_maybeOneline) diff --git a/tools/qmlplugindump/qmlstreamwriter.h b/tools/qmlplugindump/qmlstreamwriter.h index 9d8052911c..ee5740a48b 100644 --- a/tools/qmlplugindump/qmlstreamwriter.h +++ b/tools/qmlplugindump/qmlstreamwriter.h @@ -63,6 +63,8 @@ public: void writeScriptObjectLiteralBinding(const QString &name, const QList<QPair<QString, QString> > &keyValue); void writeArrayBinding(const QString &name, const QStringList &elements); void write(const QString &data); + void writeIsCreatable(bool isCreatable); + void writeIsSingleton(bool isSingleton); private: void writeIndent(); |