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

Change-Id: I0376b25557ba633e5b148c6e9c467d88fae1778f
This commit is contained in:
Qt Forward Merge Bot 2019-10-17 01:00:10 +02:00
commit a298b4dc5f
31 changed files with 471 additions and 211 deletions

View File

@ -39,13 +39,13 @@
\include examples-run.qdocinc
\section1 GridView and PathView
\section1 Using GridView and PathView
\e GridView and \e PathView demonstrate usage of these types to display
views.
\snippet views/gridview/gridview-example.qml 0
\section1 Dynamic List
\section1 Using Dynamic List
\e{Dynamic List} demonstrates animation of runtime additions and removals to
a \l ListView.
@ -66,12 +66,12 @@
\snippet views/listview/expandingdelegates.qml 2
\snippet views/listview/expandingdelegates.qml 3
\section1 Highlight
\section1 Using Highlight
\e Highlight demonstrates adding a custom highlight to a ListView.
\snippet views/listview/highlight.qml 0
\section1 Highlight Ranges
\section1 Using Highlight Ranges
\e{Highlight Ranges} shows the three different highlight range modes of
ListView.
@ -79,13 +79,13 @@
\snippet views/listview/highlightranges.qml 1
\snippet views/listview/highlightranges.qml 2
\section1 Sections
\section1 Using Sections
\e Sections demonstrates the various section headers and footers available
to \l ListView.
\snippet views/listview/sections.qml 0
\section1 Packages
\section1 Using Packages
\e Packages use the \l [QML]{Package} type to transition delegates between
two views.
@ -100,13 +100,13 @@
\snippet views/package/view.qml 0
\section1 ObjectModel
\section1 Using ObjectModel
\e ObjectModel uses an ObjectModel for the model instead of a \l ListModel.
\snippet views/objectmodel/objectmodel.qml 0
\section1 Display Margins
\section1 Using Display Margins
\e{Display Margins} uses delegates to display items and implements a simple
header and footer components.

View File

@ -1631,7 +1631,7 @@ Item {
TestCase {
name: "ItemTests"
when: area.pressed
when: windowShown
id: test1
function test_touch() {

View File

@ -1104,6 +1104,7 @@ void fillUniformArrayFromImage(float* array, const QImage& img, int size)
QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
: QQuickParticlePainter(parent)
, m_color_variation(0.0)
, m_outgoingNode(nullptr)
, m_material(nullptr)
, m_alphaVariation(0.0)
, m_alpha(1.0)
@ -1149,6 +1150,8 @@ void QQuickImageParticle::sceneGraphInvalidated()
{
m_nodes.clear();
m_material = nullptr;
delete m_outgoingNode;
m_outgoingNode = nullptr;
}
void QQuickImageParticle::setImage(const QUrl &image)
@ -1931,8 +1934,11 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData
}
if (m_pleaseReset){
if (node)
delete node;
// Cannot just destroy the node and then return null (in case image
// loading is still in progress). Rather, keep track of the old node
// until we have a new one.
delete m_outgoingNode;
m_outgoingNode = node;
node = nullptr;
m_lastLevel = perfLevel;
@ -1946,6 +1952,9 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData
m_pleaseReset = false;
m_startedImageLoading = 0;//Cancel a part-way build (may still have a pending load)
} else if (!m_material) {
delete node;
node = nullptr;
}
if (m_system && m_system->isRunning() && !m_system->isPaused()){
@ -1959,6 +1968,11 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData
}
}
if (!node) {
node = m_outgoingNode;
m_outgoingNode = nullptr;
}
return node;
}

View File

@ -390,6 +390,7 @@ private:
QColor m_color;
qreal m_color_variation;
QSGNode *m_outgoingNode;
QHash<int, QSGGeometryNode *> m_nodes;
QHash<int, int> m_idxStarts;//TODO: Proper resizing will lead to needing a spriteEngine per particle - do this after sprite engine gains transparent sharing?
QList<QPair<int, int> > m_startsIdx;//Same data, optimized for alternate retrieval

View File

@ -96,8 +96,9 @@ private:
static void printDisassembledOutputWithCalls(QByteArray processedOutput,
const QHash<const void*, const char*>& functions)
{
for (QHash<const void*, const char*>::ConstIterator it = functions.begin(), end = functions.end();
it != end; ++it) {
const auto symbols = Runtime::symbolTable();
const QByteArray padding(" ; ");
for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16);
int idx = 0;
while (idx >= 0) {
@ -107,7 +108,9 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput,
idx = processedOutput.indexOf('\n', idx);
if (idx < 0)
break;
processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; ") + it.value());
const char *functionName = it.value();
processedOutput = processedOutput.insert(
idx, padding + QByteArray(functionName ? functionName : symbols[it.key()]));
}
}
@ -302,27 +305,29 @@ void JIT::PlatformAssemblerCommon::passPointerAsArg(void *ptr, int arg)
storePtr(TrustedImmPtr(ptr), argStackAddress(arg));
}
void PlatformAssemblerCommon::callRuntime(const char *functionName, const void *funcPtr)
void PlatformAssemblerCommon::callRuntime(const void *funcPtr, const char *functionName)
{
#ifndef QT_NO_DEBUG
Q_ASSERT(remainingArgcForCall == 0);
remainingArgcForCall = NoCall;
#endif
callRuntimeUnchecked(functionName, funcPtr);
callRuntimeUnchecked(funcPtr, functionName);
if (argcOnStackForCall > 0) {
addPtr(TrustedImm32(argcOnStackForCall), StackPointerRegister);
argcOnStackForCall = 0;
}
}
void PlatformAssemblerCommon::callRuntimeUnchecked(const char *functionName, const void *funcPtr)
void PlatformAssemblerCommon::callRuntimeUnchecked(const void *funcPtr, const char *functionName)
{
Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr));
functions.insert(funcPtr, functionName);
callAbsolute(funcPtr);
}
void PlatformAssemblerCommon::tailCallRuntime(const char *functionName, const void *funcPtr)
void PlatformAssemblerCommon::tailCallRuntime(const void *funcPtr, const char *functionName)
{
Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr));
functions.insert(funcPtr, functionName);
setTailCallArg(EngineRegister, 1);
setTailCallArg(CppStackFrameRegister, 0);

View File

@ -706,9 +706,9 @@ public:
void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg);
void passPointerAsArg(void *ptr, int arg);
void callRuntime(const char *functionName, const void *funcPtr);
void callRuntimeUnchecked(const char *functionName, const void *funcPtr);
void tailCallRuntime(const char *functionName, const void *funcPtr);
void callRuntime(const void *funcPtr, const char *functionName = nullptr);
void callRuntimeUnchecked(const void *funcPtr, const char *functionName = nullptr);
void tailCallRuntime(const void *funcPtr, const char *functionName = nullptr);
void setTailCallArg(RegisterID src, int arg);
Address jsAlloca(int slotCount);
void storeInt32AsValue(int srcInt, Address destAddr);

View File

@ -61,7 +61,8 @@ namespace JIT {
#define ASM_GENERATE_RUNTIME_CALL(function, destination) \
pasm()->GENERATE_RUNTIME_CALL(function, destination)
#define callHelper(x) PlatformAssemblerCommon::callRuntimeUnchecked(#x, reinterpret_cast<void *>(&x))
#define callHelper(x) \
PlatformAssemblerCommon::callRuntimeUnchecked(reinterpret_cast<void *>(&x), #x)
const QV4::Value::ValueTypeInternal IntegerTag = QV4::Value::ValueTypeInternal::Integer;
@ -83,10 +84,9 @@ public:
: PlatformAssemblerCommon(constantTable)
{}
void callRuntime(const char *functionName, const void *funcPtr,
CallResultDestination dest)
void callRuntime(const void *funcPtr, CallResultDestination dest)
{
PlatformAssemblerCommon::callRuntime(functionName, funcPtr);
PlatformAssemblerCommon::callRuntime(funcPtr);
if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator();
}
@ -240,7 +240,7 @@ public:
auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2);
move(AccumulatorRegister, registerForArg(0));
callRuntimeUnchecked("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper));
callHelper(toInt32Helper);
saveReturnValueInAccumulator();
isInt.link(this);
@ -383,10 +383,9 @@ public:
: PlatformAssemblerCommon(constantTable)
{}
void callRuntime(const char *functionName, const void *funcPtr,
CallResultDestination dest)
void callRuntime(const void *funcPtr, CallResultDestination dest)
{
PlatformAssemblerCommon::callRuntime(functionName, funcPtr);
PlatformAssemblerCommon::callRuntime(funcPtr);
if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator();
}
@ -491,7 +490,7 @@ public:
move(AccumulatorRegisterValue, registerForArg(0));
move(AccumulatorRegisterTag, registerForArg(1));
}
callRuntimeUnchecked("toNumberHelper", reinterpret_cast<void *>(&toNumberHelper));
callHelper(toNumberHelper);
saveReturnValueInAccumulator();
if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
@ -548,7 +547,7 @@ public:
move(AccumulatorRegisterValue, registerForArg(0));
move(AccumulatorRegisterTag, registerForArg(1));
}
callRuntimeUnchecked("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper));
callHelper(toInt32Helper);
saveReturnValueInAccumulator();
if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
@ -570,7 +569,7 @@ public:
move(AccumulatorRegisterValue, registerForArg(0));
move(AccumulatorRegisterTag, registerForArg(1));
}
callRuntimeUnchecked("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper));
callHelper(toInt32Helper);
saveReturnValueInAccumulator();
if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
@ -1267,7 +1266,7 @@ void BaselineAssembler::cmpeqInt(int lhs)
else
pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
pasm()->pushAccumulatorAsArg(0);
pasm()->callRuntimeUnchecked("Equal", (void*)Runtime::Equal::call);
pasm()->callRuntimeUnchecked((void*)Runtime::Equal::call);
pasm()->saveReturnValueInAccumulator();
if (PlatformAssembler::ArgInRegCount < 2)
pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
@ -1291,7 +1290,7 @@ void BaselineAssembler::cmpneInt(int lhs)
else
pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
pasm()->pushAccumulatorAsArg(0);
pasm()->callRuntimeUnchecked("NotEqual", (void*)Runtime::NotEqual::call);
pasm()->callRuntimeUnchecked((void*)Runtime::NotEqual::call);
pasm()->saveReturnValueInAccumulator();
if (PlatformAssembler::ArgInRegCount < 2)
pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
@ -1305,7 +1304,7 @@ void BaselineAssembler::cmpneInt(int lhs)
done.link(pasm());
}
void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName, int lhs)
void BaselineAssembler::cmp(int cond, CmpFunc function, int lhs)
{
auto c = static_cast<PlatformAssembler::RelationalCondition>(cond);
auto done = pasm()->binopBothIntPath(regAddr(lhs), [this, c](){
@ -1321,7 +1320,7 @@ void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName
pasm()->passAccumulatorAsArg(1);
pasm()->passJSSlotAsArg(lhs, 0);
callRuntime(functionName, reinterpret_cast<void*>(function), CallResultDestination::InAccumulator);
callRuntime(reinterpret_cast<void*>(function), CallResultDestination::InAccumulator);
checkException();
// done.
@ -1331,50 +1330,42 @@ void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName
void BaselineAssembler::cmpeq(int lhs)
{
cmp(PlatformAssembler::Equal, &Runtime::CompareEqual::call,
"CompareEqual", lhs);
cmp(PlatformAssembler::Equal, &Runtime::CompareEqual::call, lhs);
}
void BaselineAssembler::cmpne(int lhs)
{
cmp(PlatformAssembler::NotEqual, &Runtime::CompareNotEqual::call,
"CompareNotEqual", lhs);
cmp(PlatformAssembler::NotEqual, &Runtime::CompareNotEqual::call, lhs);
}
void BaselineAssembler::cmpgt(int lhs)
{
cmp(PlatformAssembler::GreaterThan, &Runtime::CompareGreaterThan::call,
"CompareGreaterThan", lhs);
cmp(PlatformAssembler::GreaterThan, &Runtime::CompareGreaterThan::call, lhs);
}
void BaselineAssembler::cmpge(int lhs)
{
cmp(PlatformAssembler::GreaterThanOrEqual, &Runtime::CompareGreaterEqual::call,
"CompareGreaterEqual", lhs);
cmp(PlatformAssembler::GreaterThanOrEqual, &Runtime::CompareGreaterEqual::call, lhs);
}
void BaselineAssembler::cmplt(int lhs)
{
cmp(PlatformAssembler::LessThan, &Runtime::CompareLessThan::call,
"CompareLessThan", lhs);
cmp(PlatformAssembler::LessThan, &Runtime::CompareLessThan::call, lhs);
}
void BaselineAssembler::cmple(int lhs)
{
cmp(PlatformAssembler::LessThanOrEqual, &Runtime::CompareLessEqual::call,
"CompareLessEqual", lhs);
cmp(PlatformAssembler::LessThanOrEqual, &Runtime::CompareLessEqual::call, lhs);
}
void BaselineAssembler::cmpStrictEqual(int lhs)
{
cmp(PlatformAssembler::Equal, &Runtime::CompareStrictEqual::call,
"RuntimeHelpers::strictEqual", lhs);
cmp(PlatformAssembler::Equal, &Runtime::CompareStrictEqual::call, lhs);
}
void BaselineAssembler::cmpStrictNotEqual(int lhs)
{
cmp(PlatformAssembler::NotEqual, &Runtime::CompareStrictNotEqual::call,
"RuntimeHelpers::strictNotEqual", lhs);
cmp(PlatformAssembler::NotEqual, &Runtime::CompareStrictNotEqual::call, lhs);
}
int BaselineAssembler::jump(int offset)
@ -1463,9 +1454,9 @@ void BaselineAssembler::passPointerAsArg(void *ptr, int arg)
pasm()->passPointerAsArg(ptr, arg);
}
void BaselineAssembler::callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest)
void BaselineAssembler::callRuntime(const void *funcPtr, CallResultDestination dest)
{
pasm()->callRuntime(functionName, funcPtr, dest);
pasm()->callRuntime(funcPtr, dest);
}
void BaselineAssembler::saveAccumulatorInFrame()
@ -1498,8 +1489,9 @@ void BaselineAssembler::jsTailCall(int func, int thisObject, int argc, int argv)
pasm()->storeInt32AsValue(argv, Address(tos.base, argvOffset));
pasm()->moveReg(regAddr(thisObject), Address(tos.base, thisOffset));
pasm()->moveReg(regAddr(func), Address(tos.base, funcOffset));
pasm()->tailCallRuntime("TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing",
reinterpret_cast<void *>(TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing));
pasm()->tailCallRuntime(
reinterpret_cast<void *>(TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing),
"TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing");
}
void BaselineAssembler::checkException()

View File

@ -62,16 +62,11 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
#define JIT_STRINGIFYx(s) #s
#define JIT_STRINGIFY(s) JIT_STRINGIFYx(s)
#define GENERATE_RUNTIME_CALL(function, destination) \
callRuntime(JIT_STRINGIFY(function), \
reinterpret_cast<void *>(&Runtime::function::call), \
callRuntime(reinterpret_cast<void *>(&Runtime::function::call), \
destination)
#define GENERATE_TAIL_CALL(function) \
tailCallRuntime(JIT_STRINGIFY(function), \
reinterpret_cast<void *>(&function))
tailCallRuntime(reinterpret_cast<void *>(&function))
class BaselineAssembler {
public:
@ -153,7 +148,7 @@ public:
void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg);
void passPointerAsArg(void *ptr, int arg);
void callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest);
void callRuntime(const void *funcPtr, CallResultDestination dest);
void saveAccumulatorInFrame();
void loadAccumulatorFromFrame();
void jsTailCall(int func, int thisObject, int argc, int argv);
@ -179,7 +174,7 @@ protected:
private:
typedef unsigned(*CmpFunc)(const Value&,const Value&);
void cmp(int cond, CmpFunc function, const char *functionName, int lhs);
void cmp(int cond, CmpFunc function, int lhs);
};
} // namespace JIT

View File

@ -2316,6 +2316,133 @@ Bool Runtime::CompareStrictNotEqual::call(const Value &left, const Value &right)
return ! RuntimeHelpers::strictEqual(left, right);
}
template<typename Operation>
static inline const void *symbol()
{
return reinterpret_cast<void *>(&Operation::call);
}
QHash<const void *, const char *> Runtime::symbolTable()
{
static const QHash<const void *, const char *> symbols({
#ifndef V4_BOOTSTRAP
{symbol<CallGlobalLookup>(), "CallGlobalLookup" },
{symbol<CallQmlContextPropertyLookup>(), "CallQmlContextPropertyLookup" },
{symbol<CallName>(), "CallName" },
{symbol<CallProperty>(), "CallProperty" },
{symbol<CallPropertyLookup>(), "CallPropertyLookup" },
{symbol<CallElement>(), "CallElement" },
{symbol<CallValue>(), "CallValue" },
{symbol<CallWithReceiver>(), "CallWithReceiver" },
{symbol<CallPossiblyDirectEval>(), "CallPossiblyDirectEval" },
{symbol<CallWithSpread>(), "CallWithSpread" },
{symbol<TailCall>(), "TailCall" },
{symbol<Construct>(), "Construct" },
{symbol<ConstructWithSpread>(), "ConstructWithSpread" },
{symbol<StoreNameStrict>(), "StoreNameStrict" },
{symbol<StoreNameSloppy>(), "StoreNameSloppy" },
{symbol<StoreProperty>(), "StoreProperty" },
{symbol<StoreElement>(), "StoreElement" },
{symbol<LoadProperty>(), "LoadProperty" },
{symbol<LoadName>(), "LoadName" },
{symbol<LoadElement>(), "LoadElement" },
{symbol<LoadSuperProperty>(), "LoadSuperProperty" },
{symbol<StoreSuperProperty>(), "StoreSuperProperty" },
{symbol<LoadSuperConstructor>(), "LoadSuperConstructor" },
{symbol<LoadGlobalLookup>(), "LoadGlobalLookup" },
{symbol<LoadQmlContextPropertyLookup>(), "LoadQmlContextPropertyLookup" },
{symbol<GetLookup>(), "GetLookup" },
{symbol<SetLookupStrict>(), "SetLookupStrict" },
{symbol<SetLookupSloppy>(), "SetLookupSloppy" },
{symbol<TypeofValue>(), "TypeofValue" },
{symbol<TypeofName>(), "TypeofName" },
{symbol<DeleteProperty_NoThrow>(), "DeleteProperty_NoThrow" },
{symbol<DeleteProperty>(), "DeleteProperty" },
{symbol<DeleteName_NoThrow>(), "DeleteName_NoThrow" },
{symbol<DeleteName>(), "DeleteName" },
{symbol<ThrowException>(), "ThrowException" },
{symbol<PushCallContext>(), "PushCallContext" },
{symbol<PushWithContext>(), "PushWithContext" },
{symbol<PushCatchContext>(), "PushCatchContext" },
{symbol<PushBlockContext>(), "PushBlockContext" },
{symbol<CloneBlockContext>(), "CloneBlockContext" },
{symbol<PushScriptContext>(), "PushScriptContext" },
{symbol<PopScriptContext>(), "PopScriptContext" },
{symbol<ThrowReferenceError>(), "ThrowReferenceError" },
{symbol<ThrowOnNullOrUndefined>(), "ThrowOnNullOrUndefined" },
{symbol<Closure>(), "Closure" },
{symbol<ConvertThisToObject>(), "ConvertThisToObject" },
{symbol<DeclareVar>(), "DeclareVar" },
{symbol<CreateMappedArgumentsObject>(), "CreateMappedArgumentsObject" },
{symbol<CreateUnmappedArgumentsObject>(), "CreateUnmappedArgumentsObject" },
{symbol<CreateRestParameter>(), "CreateRestParameter" },
{symbol<ArrayLiteral>(), "ArrayLiteral" },
{symbol<ObjectLiteral>(), "ObjectLiteral" },
{symbol<CreateClass>(), "CreateClass" },
{symbol<GetIterator>(), "GetIterator" },
{symbol<IteratorNext>(), "IteratorNext" },
{symbol<IteratorNextForYieldStar>(), "IteratorNextForYieldStar" },
{symbol<IteratorClose>(), "IteratorClose" },
{symbol<DestructureRestElement>(), "DestructureRestElement" },
{symbol<ToObject>(), "ToObject" },
{symbol<ToBoolean>(), "ToBoolean" },
{symbol<ToNumber>(), "ToNumber" },
{symbol<UMinus>(), "UMinus" },
{symbol<Instanceof>(), "Instanceof" },
{symbol<In>(), "In" },
{symbol<Add>(), "Add" },
{symbol<Sub>(), "Sub" },
{symbol<Mul>(), "Mul" },
{symbol<Div>(), "Div" },
{symbol<Mod>(), "Mod" },
{symbol<Exp>(), "Exp" },
{symbol<BitAnd>(), "BitAnd" },
{symbol<BitOr>(), "BitOr" },
{symbol<BitXor>(), "BitXor" },
{symbol<Shl>(), "Shl" },
{symbol<Shr>(), "Shr" },
{symbol<UShr>(), "UShr" },
{symbol<GreaterThan>(), "GreaterThan" },
{symbol<LessThan>(), "LessThan" },
{symbol<GreaterEqual>(), "GreaterEqual" },
{symbol<LessEqual>(), "LessEqual" },
{symbol<Equal>(), "Equal" },
{symbol<NotEqual>(), "NotEqual" },
{symbol<StrictEqual>(), "StrictEqual" },
{symbol<StrictNotEqual>(), "StrictNotEqual" },
{symbol<CompareGreaterThan>(), "CompareGreaterThan" },
{symbol<CompareLessThan>(), "CompareLessThan" },
{symbol<CompareGreaterEqual>(), "CompareGreaterEqual" },
{symbol<CompareLessEqual>(), "CompareLessEqual" },
{symbol<CompareEqual>(), "CompareEqual" },
{symbol<CompareNotEqual>(), "CompareNotEqual" },
{symbol<CompareStrictEqual>(), "CompareStrictEqual" },
{symbol<CompareStrictNotEqual>(), "CompareStrictNotEqual" },
{symbol<CompareInstanceof>(), "CompareInstanceOf" },
{symbol<CompareIn>(), "CompareIn" },
{symbol<RegexpLiteral>(), "RegexpLiteral" },
{symbol<GetTemplateObject>(), "GetTemplateObject" }
#endif
});
return symbols;
}
} // namespace QV4
QT_END_NAMESPACE

View File

@ -501,6 +501,8 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
static const int tailCall_argv = -3;
static const int tailCall_argc = -4;
};
static QHash<const void *, const char *> symbolTable();
};
static_assert(std::is_standard_layout<Runtime>::value, "Runtime needs to be standard layout in order for us to be able to use offsetof");

View File

@ -298,8 +298,9 @@ protected:
case QMetaType::Int:
if (result.isInteger())
return doStore<int>(result.integerValue(), pd, flags);
else if (result.isNumber())
return doStore<int>(result.doubleValue(), pd, flags);
else if (result.isNumber()) {
return doStore<int>(QV4::StaticValue::toInteger(result.doubleValue()), pd, flags);
}
break;
case QMetaType::Double:
if (result.isNumber())

View File

@ -969,6 +969,7 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
if (!state->creator->populateDeferredProperties(object, deferredData))
state->errors << state->creator->errors;
deferredData->bindings.clear();
deferredState->constructionStates += state;
}

View File

@ -2141,6 +2141,40 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr
return true;
}
bool QQmlImportDatabase::removeDynamicPlugin(const QString &filePath)
{
StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
QMutexLocker lock(&plugins->mutex);
auto it = plugins->find(QFileInfo(filePath).absoluteFilePath());
if (it == plugins->end())
return false;
QPluginLoader *loader = it->loader;
if (!loader)
return false;
if (!loader->unload()) {
qWarning("Unloading %s failed: %s", qPrintable(it->uri),
qPrintable(loader->errorString()));
}
delete loader;
plugins->erase(it);
return true;
}
QStringList QQmlImportDatabase::dynamicPlugins() const
{
StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
QMutexLocker lock(&plugins->mutex);
QStringList results;
for (auto it = plugins->constBegin(), end = plugins->constEnd(); it != end; ++it) {
if (it->loader != nullptr)
results.append(it.key());
}
return results;
}
#endif // QT_CONFIG(library)
void QQmlImportDatabase::clearDirCache()

View File

@ -203,7 +203,7 @@ private:
QQmlImportsPrivate *d;
};
class QQmlImportDatabase
class Q_QML_PRIVATE_EXPORT QQmlImportDatabase
{
Q_DECLARE_TR_FUNCTIONS(QQmlImportDatabase)
public:
@ -214,6 +214,8 @@ public:
#if QT_CONFIG(library)
bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors);
bool removeDynamicPlugin(const QString &filePath);
QStringList dynamicPlugins() const;
#endif
QStringList importPathList(PathType type = LocalOrRemote) const;

View File

@ -234,73 +234,23 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
return instance;
}
// ### unify or keep in sync with populateDeferredBinding()
bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData)
void QQmlObjectCreator::beginPopulateDeferred(QQmlContextData *newContext)
{
QQmlData *declarativeData = QQmlData::get(instance);
context = deferredData->context;
sharedState->rootContext = context;
QObject *bindingTarget = instance;
QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
QObject *scopeObject = instance;
qSwap(_scopeObject, scopeObject);
QV4::Scope valueScope(v4);
context = newContext;
sharedState->rootContext = newContext;
Q_ASSERT(topLevelCreator);
Q_ASSERT(!sharedState->allJavaScriptObjects);
QV4::Scope valueScope(v4);
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
qSwap(_qmlContext, qmlContext);
qSwap(_propertyCache, cache);
qSwap(_qobject, instance);
int objectIndex = deferredData->deferredIdx;
qSwap(_compiledObjectIndex, objectIndex);
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
qSwap(_compiledObject, obj);
qSwap(_ddata, declarativeData);
qSwap(_bindingTarget, bindingTarget);
qSwap(_vmeMetaObject, vmeMetaObject);
setupBindings(/*applyDeferredBindings=*/true);
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
qSwap(_ddata, declarativeData);
qSwap(_compiledObject, obj);
qSwap(_compiledObjectIndex, objectIndex);
qSwap(_qobject, instance);
qSwap(_propertyCache, cache);
qSwap(_qmlContext, qmlContext);
qSwap(_scopeObject, scopeObject);
deferredData->bindings.clear();
phase = ObjectsCreated;
return errors.isEmpty();
}
// ### unify or keep in sync with populateDeferredProperties()
bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding)
void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
const QQmlPropertyPrivate *qmlProperty,
const QV4::CompiledData::Binding *binding)
{
Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
QObject *instance = qmlProperty.object();
QQmlData *declarativeData = QQmlData::get(instance);
context = deferredData->context;
sharedState->rootContext = context;
QObject *bindingTarget = instance;
QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
@ -312,9 +262,6 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
QV4::Scope valueScope(v4);
Q_ASSERT(topLevelCreator);
if (!sharedState->allJavaScriptObjects)
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
qSwap(_qmlContext, qmlContext);
@ -322,7 +269,7 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_propertyCache, cache);
qSwap(_qobject, instance);
int objectIndex = deferredData->deferredIdx;
int objectIndex = deferredIndex;
qSwap(_compiledObjectIndex, objectIndex);
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
@ -332,22 +279,29 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_bindingTarget, bindingTarget);
qSwap(_vmeMetaObject, vmeMetaObject);
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
if (binding) {
Q_ASSERT(qmlProperty);
Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
const QQmlPropertyData &property = QQmlPropertyPrivate::get(qmlProperty)->core;
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
if (property.isQList()) {
void *argv[1] = { (void*)&_currentList };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv);
} else if (_currentList.object) {
_currentList = QQmlListProperty<void>();
const QQmlPropertyData &property = qmlProperty->core;
if (property.isQList()) {
void *argv[1] = { (void*)&_currentList };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv);
} else if (_currentList.object) {
_currentList = QQmlListProperty<void>();
}
setPropertyBinding(&property, binding);
qSwap(_currentList, savedList);
} else {
setupBindings(/*applyDeferredBindings=*/true);
}
setPropertyBinding(&property, binding);
qSwap(_currentList, savedList);
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
qSwap(_ddata, declarativeData);
@ -358,12 +312,29 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_qmlContext, qmlContext);
qSwap(_scopeObject, scopeObject);
}
phase = ObjectsCreated;
bool QQmlObjectCreator::populateDeferredProperties(QObject *instance,
const QQmlData::DeferredData *deferredData)
{
beginPopulateDeferred(deferredData->context);
populateDeferred(instance, deferredData->deferredIdx);
finalizePopulateDeferred();
return errors.isEmpty();
}
void QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding)
{
populateDeferred(qmlProperty.object(), deferredIndex, QQmlPropertyPrivate::get(qmlProperty),
binding);
}
void QQmlObjectCreator::finalizePopulateDeferred()
{
phase = ObjectsCreated;
}
void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
{
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite;

View File

@ -112,8 +112,14 @@ public:
~QQmlObjectCreator();
QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr);
bool populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData);
bool populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding);
bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData);
void beginPopulateDeferred(QQmlContextData *context);
void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding);
void finalizePopulateDeferred();
QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt);
void clear();
@ -139,6 +145,11 @@ private:
bool populateInstance(int index, QObject *instance,
QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
// If qmlProperty and binding are null, populate all properties, otherwise only the given one.
void populateDeferred(QObject *instance, int deferredIndex,
const QQmlPropertyPrivate *qmlProperty = nullptr,
const QV4::CompiledData::Binding *binding = nullptr);
void setupBindings(bool applyDeferredBindings = false);
bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);

View File

@ -62,7 +62,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/qvariant.h>
#include <QtCore/qurl.h>
#include <QPointer>
#include <QtCore/qpointer.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qdebug.h>

View File

@ -2060,20 +2060,19 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
firstDirtyPos = nodeIterator->startPos();
// ### this could be optimized if the first and last dirty nodes are not connected
// as the intermediate text nodes would usually only need to be transformed differently.
int lastDirtyPos = firstDirtyPos;
QQuickTextNode *firstCleanNode = nullptr;
auto it = d->textNodeMap.constEnd();
while (it != nodeIterator) {
--it;
if (it->dirty()) {
lastDirtyPos = it->startPos();
if (it->dirty())
break;
}
firstCleanNode = it->textNode();
}
do {
rootNode->removeChildNode(nodeIterator->textNode());
delete nodeIterator->textNode();
nodeIterator = d->textNodeMap.erase(nodeIterator);
} while (nodeIterator != d->textNodeMap.constEnd() && nodeIterator->startPos() <= lastDirtyPos);
} while (nodeIterator != d->textNodeMap.constEnd() && nodeIterator->textNode() != firstCleanNode);
}
// FIXME: the text decorations could probably be handled separately (only updated for affected textFrames)

View File

@ -2259,8 +2259,8 @@ void QQuickTextInput::remove(int start, int end)
d->m_cursor -= qMin(d->m_cursor, end) - start;
if (d->m_selstart > start)
d->m_selstart -= qMin(d->m_selstart, end) - start;
if (d->m_selend > end)
d->m_selend -= qMin(d->m_selend, end) - start;
if (d->m_selend >= end)
d->m_selend -= end - start;
}
d->addCommand(QQuickTextInputPrivate::Command(
QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));

View File

@ -4220,16 +4220,18 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The OpenGL context used for rendering the scene graph will be bound
at this point.
When using the RHI and a graphics API other than OpenGL, the signal is
emitted after the preparations for the frame have been done, meaning there
is a command buffer in recording mode, where applicable. If desired, the
slot function connected to this signal can query native resources like the
command before via QSGRendererInterface. Note however that the recording of
the main render pass is not yet started at this point and it is not
possible to add commands within that pass. Instead, use
beforeRenderPassRecording() for that. However, connecting to this signal is
still important if the recording of copy type of commands is desired since
those cannot be enqueued within a render pass.
When using the RHI, the signal is emitted after the preparations for the
frame have been done, meaning there is a command buffer in recording mode,
where applicable. If desired, the slot function connected to this signal
can query native resources like the command before via
QSGRendererInterface. Note however that the recording of the main render
pass is not yet started at this point and it is not possible to add
commands within that pass. Starting a pass means clearing the color, depth,
and stencil buffers so it is not possible to achieve an underlay type of
rendering by just connecting to this signal. Rather, connect to
beforeRenderPassRecording(). However, connecting to this signal is still
important if the recording of copy type of commands is desired since those
cannot be enqueued within a render pass.
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that
@ -4252,18 +4254,17 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The OpenGL context used for rendering the scene graph will be bound at this point.
When using the RHI and a graphics API other than OpenGL, the signal is
emitted after scene graph has added its commands to the command buffer,
which is not yet submitted to the graphics queue. If desired, the slot
function connected to this signal can query native resources, like the
command buffer, before via QSGRendererInterface. Note however that the
render pass (or passes) are already recorded at this point and it is not
possible to add more commands within the scenegraph's pass. Instead, use
afterRenderPassRecording() for that. This signal has therefore limited use
and is rarely needed in an RHI-based setup. Rather, it is the combination
of beforeRendering() + beforeRenderPassRecording() or beforeRendering() +
afterRenderPassRecording() that is typically used to achieve under- or
overlaying of the custom rendering.
When using the RHI, the signal is emitted after scene graph has added its
commands to the command buffer, which is not yet submitted to the graphics
queue. If desired, the slot function connected to this signal can query
native resources, like the command buffer, before via QSGRendererInterface.
Note however that the render pass (or passes) are already recorded at this
point and it is not possible to add more commands within the scenegraph's
pass. Instead, use afterRenderPassRecording() for that. This signal has
therefore limited use and is rarely needed in an RHI-based setup. Rather,
it is the combination of beforeRendering() + beforeRenderPassRecording() or
beforeRendering() + afterRenderPassRecording() that is typically used to
achieve under- or overlaying of the custom rendering.
\warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that

View File

@ -0,0 +1,6 @@
pragma Singleton
import dumper.Imports 1.0
Imports {
property int something: 2
}

View File

@ -17,7 +17,7 @@ HEADERS += \
imports.h
!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
cp.files = qmldir plugins.qmltypes CompositeImports.qml
cp.files = qmldir plugins.qmltypes CompositeImports.qml Derived.qml
cp.path = $$OUT_PWD
COPIES += cp
}

View File

@ -14,4 +14,14 @@ Module {
exports: ["dumper.Imports/Imports 1.0"]
exportMetaObjectRevisions: [0]
}
Component {
prototype: "Imports"
name: "dumper.Imports/Derived 1.0"
exports: ["dumper.Imports/Derived 1.0"]
exportMetaObjectRevisions: [0]
isComposite: true
isCreatable: false
isSingleton: true
Property { name: "something"; type: "int" }
}
}

View File

@ -1,3 +1,4 @@
module dumper.Imports
plugin Imports
CompositeImports 1.0 CompositeImports.qml
singleton Derived 1.0 Derived.qml

View File

@ -0,0 +1,14 @@
import QtQuick 2.11
Item {
visible: true
width: 320
height: 200
property int val: other.val
Rectangle {
id: other
anchors.fill: parent;
property int val: undefined / 2
}
}

View File

@ -56,6 +56,7 @@ private slots:
void bindingOverwriting();
void bindToQmlComponent();
void bindingDoesNoWeirdConversion();
void bindNaNToInt();
private:
QQmlEngine engine;
@ -398,6 +399,16 @@ void tst_qqmlbinding::bindingDoesNoWeirdConversion()
QVERIFY(colorLabel);
}
//QTBUG-72442
void tst_qqmlbinding::bindNaNToInt()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("nanPropertyToInt.qml"));
QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(c.create()));
QVERIFY(item != nullptr);
QCOMPARE(item->property("val").toInt(), 0);
}
QTEST_MAIN(tst_qqmlbinding)
#include "tst_qqmlbinding.moc"

View File

@ -32,6 +32,7 @@
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
#include <private/qqmlimport_p.h>
#include <private/qqmlengine_p.h>
#include "../../shared/util.h"
class tst_QQmlImport : public QQmlDataTest
@ -46,6 +47,7 @@ private slots:
void completeQmldirPaths();
void interceptQmldir();
void singletonVersionResolution();
void removeDynamicPlugin();
void cleanup();
};
@ -260,6 +262,25 @@ void tst_QQmlImport::singletonVersionResolution()
}
}
void tst_QQmlImport::removeDynamicPlugin()
{
qmlClearTypeRegistrations();
QQmlEngine engine;
{
// Load something that adds a dynamic plugin
QQmlComponent component(&engine);
component.setData(QByteArray("import QtTest 1.0; TestResult{}"), QUrl());
QVERIFY(component.isReady());
}
QQmlImportDatabase *imports = &QQmlEnginePrivate::get(&engine)->importDatabase;
const QStringList &plugins = imports->dynamicPlugins();
QVERIFY(!plugins.isEmpty());
for (const QString &plugin : plugins)
QVERIFY(imports->removeDynamicPlugin(plugin));
QVERIFY(imports->dynamicPlugins().isEmpty());
qmlClearTypeRegistrations();
}
QTEST_MAIN(tst_QQmlImport)

View File

@ -4728,11 +4728,13 @@ static void beginDeferredOnce(QQmlEnginePrivate *enginePriv,
typedef QMultiHash<int, const QV4::CompiledData::Binding *> QV4PropertyBindingHash;
auto it = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.second);
auto last = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.first);
state->creator->beginPopulateDeferred(deferData->context);
while (it != last) {
if (!state->creator->populateDeferredBinding(property, deferData, *it))
state->errors << state->creator->errors;
state->creator->populateDeferredBinding(property, deferData->deferredIdx, *it);
++it;
}
state->creator->finalizePopulateDeferred();
state->errors << state->creator->errors;
deferredState->constructionStates += state;

View File

@ -0,0 +1,22 @@
import QtQuick 2.12
Item {
id: root
width: 600
height: 300
TextInput {
id: qwe
objectName: "qwe"
width: 500
height: 100
font.pixelSize: 50
text: "123456"
focus: true
}
Component.onCompleted: {
qwe.insert(0, "***")
qwe.remove(0, 3)
}
}

View File

@ -230,6 +230,7 @@ private slots:
void padding();
void QTBUG_51115_readOnlyResetsSelection();
void QTBUG_77814_InsertRemoveNoSelection();
private:
void simulateKey(QWindow *, int key);
@ -7003,6 +7004,18 @@ void tst_qquicktextinput::QTBUG_51115_readOnlyResetsSelection()
QCOMPARE(obj->selectedText(), QString());
}
void tst_qquicktextinput::QTBUG_77814_InsertRemoveNoSelection()
{
QQuickView view;
view.setSource(testFileUrl("qtbug77841.qml"));
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
QQuickTextInput *textInput = view.rootObject()->findChild<QQuickTextInput*>("qwe");
QVERIFY(textInput);
QCOMPARE(textInput->selectedText(), QString());
}
QTEST_MAIN(tst_qquicktextinput)
#include "tst_qquicktextinput.moc"

View File

@ -380,23 +380,21 @@ public:
relocatableModuleUri = uri;
}
const QString getExportString(QString qmlTyName, int majorVersion, int minorVersion)
QString getExportString(const QQmlType &type, const QmlVersionInfo &versionInfo)
{
if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) {
qmlTyName.remove(0, relocatableModuleUri.size() + 1);
}
if (qmlTyName.startsWith("./")) {
qmlTyName.remove(0, 2);
}
if (qmlTyName.startsWith(QLatin1Char('/'))) {
qmlTyName.remove(0, 1);
}
const QString exportString = enquote(
QString("%1 %2.%3").arg(
qmlTyName,
QString::number(majorVersion),
QString::number(minorVersion)));
return exportString;
const QString module = type.module().isEmpty() ? versionInfo.pluginImportUri
: type.module();
const int majorVersion = type.majorVersion() >= 0 ? type.majorVersion()
: versionInfo.majorVersion;
const int minorVersion = type.minorVersion() >= 0 ? type.minorVersion()
: versionInfo.minorVersion;
const QString versionedElement = type.elementName()
+ QString::fromLatin1(" %1.%2").arg(majorVersion).arg(minorVersion);
return enquote((module == relocatableModuleUri)
? versionedElement
: module + QLatin1Char('/') + versionedElement);
}
void writeMetaContent(const QMetaObject *meta, KnownAttributes *knownAttributes = nullptr)
@ -441,8 +439,9 @@ public:
}
}
QString getPrototypeNameForCompositeType(const QMetaObject *metaObject, QSet<QByteArray> &defaultReachableNames,
QList<const QMetaObject *> *objectsToMerge, const QmlVersionInfo &versionInfo)
QString getPrototypeNameForCompositeType(
const QMetaObject *metaObject, QList<const QMetaObject *> *objectsToMerge,
const QmlVersionInfo &versionInfo)
{
auto ty = QQmlMetaType::qmlType(metaObject);
QString prototypeName;
@ -454,24 +453,28 @@ public:
&& !objectsToMerge->contains(metaObject))
objectsToMerge->append(metaObject);
const QMetaObject *superMetaObject = metaObject->superClass();
if (!superMetaObject)
if (!superMetaObject) {
prototypeName = "QObject";
else
} else {
QQmlType superType = QQmlMetaType::qmlType(superMetaObject);
if (superType.isValid() && !superType.isComposite())
return convertToId(superMetaObject->className());
prototypeName = getPrototypeNameForCompositeType(
superMetaObject, defaultReachableNames, objectsToMerge, versionInfo);
superMetaObject, objectsToMerge, versionInfo);
}
} else {
prototypeName = convertToId(metaObject->className());
}
return prototypeName;
}
void dumpComposite(QQmlEngine *engine, const QList<QQmlType> &compositeType, QSet<QByteArray> &defaultReachableNames, const QmlVersionInfo &versionInfo)
void dumpComposite(QQmlEngine *engine, const QList<QQmlType> &compositeType, const QmlVersionInfo &versionInfo)
{
for (const QQmlType &type : compositeType)
dumpCompositeItem(engine, type, defaultReachableNames, versionInfo);
dumpCompositeItem(engine, type, versionInfo);
}
void dumpCompositeItem(QQmlEngine *engine, const QQmlType &compositeType, QSet<QByteArray> &defaultReachableNames, const QmlVersionInfo &versionInfo)
void dumpCompositeItem(QQmlEngine *engine, const QQmlType &compositeType, const QmlVersionInfo &versionInfo)
{
QQmlComponent e(engine, compositeType.sourceUrl());
if (!e.isReady()) {
@ -492,13 +495,17 @@ public:
QList<const QMetaObject *> objectsToMerge;
KnownAttributes knownAttributes;
// Get C++ base class name for the composite type
QString prototypeName = getPrototypeNameForCompositeType(mainMeta, defaultReachableNames,
&objectsToMerge, versionInfo);
QString prototypeName = getPrototypeNameForCompositeType(mainMeta, &objectsToMerge,
versionInfo);
qml->writeScriptBinding(QLatin1String("prototype"), enquote(prototypeName));
QString qmlTyName = compositeType.qmlTypeName();
const QString exportString = getExportString(qmlTyName, compositeType.majorVersion(), compositeType.minorVersion());
const QString exportString = getExportString(compositeType, versionInfo);
// TODO: why don't we simply output the compositeType.elementName() here?
// That would make more sense, but it would change the format quite a bit.
qml->writeScriptBinding(QLatin1String("name"), exportString);
qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString);
qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType.minorVersion()));
qml->writeBooleanBinding(QLatin1String("isComposite"), true);
@ -565,7 +572,7 @@ public:
if (attachedType != meta)
attachedTypeId = convertToId(attachedType);
}
const QString exportString = getExportString(type.qmlTypeName(), type.majorVersion(), type.minorVersion());
const QString exportString = getExportString(type, { QString(), -1, -1, false });
int metaObjectRevision = type.metaObjectRevision();
if (extendedObject) {
// emulate custom metaobjectrevision out of import
@ -1239,9 +1246,6 @@ int main(int argc, char *argv[])
QSet<const QMetaObject *> uncreatableMetas;
QSet<const QMetaObject *> singletonMetas;
// QQuickKeyEvent, QQuickPinchEvent, QQuickDropEvent are not exported
QSet<QByteArray> defaultReachableNames;
// this will hold the meta objects we want to dump information of
QSet<const QMetaObject *> metas;
@ -1370,7 +1374,7 @@ int main(int argc, char *argv[])
QMap<QString, QList<QQmlType>>::const_iterator iter = compositeTypes.constBegin();
for (; iter != compositeTypes.constEnd(); ++iter)
dumper.dumpComposite(&engine, iter.value(), defaultReachableNames, info);
dumper.dumpComposite(&engine, iter.value(), info);
// define QEasingCurve as an extension of QQmlEasingValueType, this way
// properties using the QEasingCurve type get useful type information.