Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2024 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #pragma once
23 :
24 : #include <string>
25 : #include <utility>
26 :
27 : #include <QJSValue>
28 : #include <QJSEngine>
29 : #include <QObject>
30 :
31 : #include "io/path.h"
32 : #include "modularity/ioc.h"
33 :
34 : namespace muse::api {
35 : struct ApiContext {
36 : int apiversion = 0;
37 : io::path_t bundlePath;
38 : std::string scopeId;
39 : };
40 :
41 : struct JsPromise {
42 : QJSValue promise;
43 : QJSValue resolve;
44 : QJSValue reject;
45 :
46 0 : static JsPromise make(QJSEngine* engine)
47 : {
48 0 : QJSValue holder = engine->newObject();
49 0 : QJSValue factory = engine->evaluate(QStringLiteral(
50 : R"(
51 : (function (holder) {
52 : holder.promise = new Promise(function (resolve, reject) {
53 : holder.resolve = resolve
54 : holder.reject = reject
55 : })
56 : })
57 0 : )"));
58 0 : factory.call({ holder });
59 0 : return { holder.property("promise"), holder.property("resolve"), holder.property("reject") };
60 0 : }
61 : };
62 :
63 : class IApiEngine
64 : {
65 : public:
66 0 : virtual ~IApiEngine() = default;
67 :
68 : virtual const modularity::ContextPtr& iocContext() const = 0;
69 :
70 : virtual int apiversion() const = 0;
71 0 : virtual ApiContext apiContext() const
72 : {
73 0 : return ApiContext{ apiversion(), {}, {} };
74 : }
75 :
76 : virtual QJSValue newQObject(QObject* o) = 0;
77 : virtual QJSValue newObject() = 0;
78 : virtual QJSValue newArray(size_t length = 0) = 0;
79 : virtual QJSValue newArrayBuffer(const QByteArray& data) = 0;
80 : virtual JsPromise newPromise() = 0;
81 : virtual QJSValue freeze(const QJSValue& val) = 0;
82 : virtual QJSValue evaluate(const QString& code) = 0;
83 : };
84 :
85 : class JsApiEngine : public muse::api::IApiEngine
86 : {
87 : public:
88 0 : JsApiEngine(QJSEngine* e, const modularity::ContextPtr& iocContext, ApiContext context = {})
89 0 : : m_engine(e), m_iocContext(iocContext), m_context(std::move(context))
90 : {
91 0 : bool ok = false;
92 0 : m_apiversion = m_engine->property("apiversion").toInt(&ok);
93 0 : if (!ok) {
94 0 : m_apiversion = 2;
95 : }
96 0 : m_context.apiversion = m_apiversion;
97 0 : m_freezeFn = m_engine->evaluate("Object.freeze");
98 0 : }
99 :
100 0 : const modularity::ContextPtr& iocContext() const override
101 : {
102 0 : return m_iocContext;
103 : }
104 :
105 0 : int apiversion() const override
106 : {
107 0 : return m_apiversion;
108 : }
109 :
110 0 : ApiContext apiContext() const override
111 : {
112 0 : return m_context;
113 : }
114 :
115 0 : QJSValue newQObject(QObject* o) override
116 : {
117 0 : if (!o->parent()) {
118 0 : o->setParent(m_engine);
119 : }
120 0 : return m_engine->newQObject(o);
121 : }
122 :
123 0 : QJSValue newObject() override
124 : {
125 0 : return m_engine->newObject();
126 : }
127 :
128 0 : QJSValue newArray(size_t length = 0) override
129 : {
130 0 : return m_engine->newArray(uint(length));
131 : }
132 :
133 0 : QJSValue newArrayBuffer(const QByteArray& data) override
134 : {
135 0 : return m_engine->toScriptValue(data);
136 : }
137 :
138 0 : JsPromise newPromise() override
139 : {
140 0 : return muse::api::JsPromise::make(m_engine);
141 : }
142 :
143 0 : QJSValue freeze(const QJSValue& val) override
144 : {
145 0 : return m_freezeFn.call({ val });
146 0 : }
147 :
148 0 : QJSValue evaluate(const QString& code) override
149 : {
150 0 : return m_engine->evaluate(code);
151 : }
152 :
153 : private:
154 : QJSEngine* m_engine = nullptr;
155 : const modularity::ContextPtr& m_iocContext;
156 : ApiContext m_context;
157 : mutable int m_apiversion = -1;
158 : QJSValue m_freezeFn;
159 : };
160 : }
|