1 | // Copyright (C) 2019 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include <private/qqmlscriptdata_p.h> |
5 | #include <private/qqmlcontext_p.h> |
6 | #include <private/qqmlengine_p.h> |
7 | #include <private/qqmlscriptblob_p.h> |
8 | #include <private/qv4engine_p.h> |
9 | #include <private/qv4scopedvalue_p.h> |
10 | #include <private/qv4object_p.h> |
11 | #include <private/qv4qmlcontext_p.h> |
12 | #include <private/qv4module_p.h> |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | QQmlScriptData::QQmlScriptData() |
17 | : m_loaded(false) |
18 | { |
19 | } |
20 | |
21 | QQmlRefPointer<QQmlContextData> QQmlScriptData::qmlContextDataForContext( |
22 | const QQmlRefPointer<QQmlContextData> &parentQmlContextData) |
23 | { |
24 | Q_ASSERT(parentQmlContextData && parentQmlContextData->engine()); |
25 | |
26 | if (!m_precompiledScript || m_precompiledScript->isESModule()) |
27 | return nullptr; |
28 | |
29 | QQmlRefPointer<QQmlContextData> qmlContextData = m_precompiledScript->isSharedLibrary() |
30 | ? QQmlContextData::createRefCounted(parent: QQmlRefPointer<QQmlContextData>()) |
31 | : QQmlContextData::createRefCounted(parent: parentQmlContextData); |
32 | |
33 | qmlContextData->setInternal(true); |
34 | qmlContextData->setJSContext(true); |
35 | if (m_precompiledScript->isSharedLibrary()) |
36 | qmlContextData->setPragmaLibraryContext(true); |
37 | else |
38 | qmlContextData->setPragmaLibraryContext(parentQmlContextData->isPragmaLibraryContext()); |
39 | qmlContextData->setBaseUrl(url); |
40 | qmlContextData->setBaseUrlString(urlString); |
41 | |
42 | // For backward compatibility, if there are no imports, we need to use the |
43 | // imports from the parent context. See QTBUG-17518. |
44 | if (!typeNameCache->isEmpty()) { |
45 | qmlContextData->setImports(typeNameCache); |
46 | } else if (!m_precompiledScript->isSharedLibrary()) { |
47 | qmlContextData->setImports(parentQmlContextData->imports()); |
48 | qmlContextData->setImportedScripts(parentQmlContextData->importedScripts()); |
49 | } |
50 | |
51 | if (m_precompiledScript->isSharedLibrary()) |
52 | qmlContextData->setEngine(parentQmlContextData->engine()); // Fix for QTBUG-21620 |
53 | |
54 | QV4::ExecutionEngine *v4 = parentQmlContextData->engine()->handle(); |
55 | QV4::Scope scope(v4); |
56 | QV4::ScopedObject scriptsArray(scope); |
57 | if (qmlContextData->importedScripts().isNullOrUndefined()) { |
58 | scriptsArray = v4->newArrayObject(count: scripts.size()); |
59 | qmlContextData->setImportedScripts( |
60 | QV4::PersistentValue(v4, scriptsArray.asReturnedValue())); |
61 | } else { |
62 | scriptsArray = qmlContextData->importedScripts().valueRef(); |
63 | } |
64 | QV4::ScopedValue v(scope); |
65 | for (int ii = 0; ii < scripts.size(); ++ii) { |
66 | v = scripts.at(i: ii)->scriptData()->scriptValueForContext(parentCtxt: qmlContextData); |
67 | scriptsArray->put(idx: ii, v); |
68 | } |
69 | |
70 | return qmlContextData; |
71 | } |
72 | |
73 | QV4::ReturnedValue QQmlScriptData::scriptValueForContext( |
74 | const QQmlRefPointer<QQmlContextData> &parentQmlContextData) |
75 | { |
76 | if (m_loaded) |
77 | return m_value.value(); |
78 | |
79 | Q_ASSERT(parentQmlContextData && parentQmlContextData->engine()); |
80 | QV4::ExecutionEngine *v4 = parentQmlContextData->engine()->handle(); |
81 | QV4::Scope scope(v4); |
82 | |
83 | QV4::Scoped<QV4::QmlContext> qmlExecutionContext(scope); |
84 | if (auto qmlContextData = qmlContextDataForContext(parentQmlContextData)) { |
85 | qmlExecutionContext = QV4::QmlContext::create(parent: v4->rootContext(), context: std::move(qmlContextData), |
86 | /* scopeObject: */ scopeObject: nullptr); |
87 | } |
88 | |
89 | QV4::Scoped<QV4::Module> module(scope, m_precompiledScript->instantiate(engine: v4)); |
90 | if (module) { |
91 | if (qmlExecutionContext) { |
92 | module->d()->scope->outer.set(e: v4, newVal: qmlExecutionContext->d()); |
93 | qmlExecutionContext->d()->qml()->module.set(e: v4, newVal: module->d()); |
94 | } |
95 | |
96 | module->evaluate(); |
97 | } |
98 | |
99 | if (v4->hasException) { |
100 | QQmlError error = v4->catchExceptionAsQmlError(); |
101 | if (error.isValid()) |
102 | QQmlEnginePrivate::get(e: v4)->warning(error); |
103 | } |
104 | |
105 | QV4::ScopedValue value(scope); |
106 | if (qmlExecutionContext) |
107 | value = qmlExecutionContext->d()->qml(); |
108 | else if (module) |
109 | value = module->d(); |
110 | |
111 | if (m_precompiledScript->isSharedLibrary() || m_precompiledScript->isESModule()) { |
112 | m_loaded = true; |
113 | m_value.set(engine: v4, value); |
114 | } |
115 | |
116 | return value->asReturnedValue(); |
117 | } |
118 | |
119 | QT_END_NAMESPACE |
120 | |