• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_QUICKJS_QJS_ENGINE_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_QUICKJS_QJS_ENGINE_H
18 
19 #include <cstdlib>
20 #include <mutex>
21 #include <vector>
22 
23 #include "third_party/quickjs/quickjs.h"
24 
25 #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
26 #include "adapter/preview/osal/request_data.h"
27 #endif
28 #include "base/memory/ace_type.h"
29 #include "base/utils/noncopyable.h"
30 #include "core/common/ace_page.h"
31 #include "core/common/js_message_dispatcher.h"
32 #include "frameworks/bridge/js_frontend/engine/common/js_engine.h"
33 #include "frameworks/bridge/js_frontend/engine/quickjs/animation_bridge.h"
34 #include "frameworks/bridge/js_frontend/engine/quickjs/animator_bridge.h"
35 #include "native_engine/impl/quickjs/quickjs_native_engine.h"
36 
37 namespace OHOS::Ace::Framework {
38 
39 // Each JsFrontend holds only one QjsEngineInstance.
40 class QjsEngineInstance final : public AceType, public JsEngineInstance {
41 public:
QjsEngineInstance(const RefPtr<FrontendDelegate> & delegate,int32_t instanceId)42     explicit QjsEngineInstance(const RefPtr<FrontendDelegate>& delegate, int32_t instanceId)
43         : frontendDelegate_(delegate), instanceId_(instanceId)
44     {}
45     ~QjsEngineInstance() override;
46 
47     void FlushCommandBuffer(void* context, const std::string& command) override;
48 
49     bool InitJsEnv(
50         JSRuntime* runtime, JSContext* context, const std::unordered_map<std::string, void*>& extraNativeObject);
51 
GetQjsRuntime()52     JSRuntime* GetQjsRuntime() const
53     {
54         return runtime_;
55     }
56 
GetQjsContext()57     JSContext* GetQjsContext() const
58     {
59         return context_;
60     }
61 
62     void CallJs(const std::string& callbackId, const std::string& args, bool keepAlive = false, bool isGlobal = false);
63 
64     void CallAnimationStartJs(JSValue animationContext);
65     void CallAnimationFinishJs(JSValue animationContext);
66     void CallAnimationCancelJs(JSValue animationContext);
67     void CallAnimationRepeatJs(JSValue animationContext);
68     void CallAnimationFrameJs(JSValue animationContext, const char* str);
69 
70     JSValue FireJsEvent(const std::string& param);
71 
72     void FreeGroupJsBridge();
73 
SetRunningPage(const RefPtr<JsAcePage> & page)74     void SetRunningPage(const RefPtr<JsAcePage>& page)
75     {
76         std::lock_guard<std::mutex> lock(mutex_);
77         runningPage_ = page;
78     }
79 
GetRunningPage()80     RefPtr<JsAcePage> GetRunningPage() const
81     {
82         std::lock_guard<std::mutex> lock(mutex_);
83         return runningPage_;
84     }
85 
SetStagingPage(const RefPtr<JsAcePage> & page)86     void SetStagingPage(const RefPtr<JsAcePage>& page)
87     {
88         std::lock_guard<std::mutex> lock(mutex_);
89         stagingPage_ = page;
90     }
91 
GetStagingPage()92     RefPtr<JsAcePage> GetStagingPage() const
93     {
94         std::lock_guard<std::mutex> lock(mutex_);
95         return stagingPage_;
96     }
97 
ResetStagingPage(const RefPtr<JsAcePage> & page)98     void ResetStagingPage(const RefPtr<JsAcePage>& page)
99     {
100         std::lock_guard<std::mutex> lock(mutex_);
101         stagingPage_ = page;
102     }
103 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)104     void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher)
105     {
106         dispatcher_ = dispatcher;
107     }
108 
GetDelegate()109     RefPtr<FrontendDelegate> GetDelegate() const
110     {
111         return frontendDelegate_;
112     }
113 
CallPlatformFunction(const std::string & channel,std::vector<uint8_t> && data,int32_t id)114     bool CallPlatformFunction(const std::string& channel, std::vector<uint8_t>&& data, int32_t id)
115     {
116         auto dispatcher = dispatcher_.Upgrade();
117         if (dispatcher) {
118             dispatcher->Dispatch(channel, std::move(data), id);
119             return true;
120         } else {
121             LOGW("Dispatcher Upgrade fail when dispatch request mesaage to platform");
122             return false;
123         }
124     }
125 
CallPlatformFunctionSync(const std::string & channel,std::vector<uint8_t> && data,uint8_t ** resData,long & position)126     bool CallPlatformFunctionSync(
127         const std::string& channel, std::vector<uint8_t>&& data, uint8_t** resData, long& position)
128     {
129         auto dispatcher = dispatcher_.Upgrade();
130         if (dispatcher) {
131             dispatcher->DispatchSync(channel, std::move(data), resData, position);
132             return true;
133         } else {
134             LOGW("Dispatcher Upgrade fail when dispatch request mesaage to platform");
135             return false;
136         }
137     }
138 
139 #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
CallCurlFunction(const OHOS::Ace::RequestData & requestData,int32_t callbackId)140     bool CallCurlFunction(const OHOS::Ace::RequestData& requestData, int32_t callbackId)
141     {
142         auto dispatcher = dispatcher_.Upgrade();
143         if (dispatcher) {
144             dispatcher->CallCurlFunction(requestData, callbackId);
145             return true;
146         } else {
147             LOGW("Dispatcher Upgrade fail when dispatch request mesaage to platform");
148             return false;
149         }
150     }
151 #endif
152 
PluginErrorCallback(int32_t callbackId,int32_t errorCode,std::string && errorMessage)153     bool PluginErrorCallback(int32_t callbackId, int32_t errorCode, std::string&& errorMessage)
154     {
155         auto dispatcher = dispatcher_.Upgrade();
156         if (dispatcher) {
157             dispatcher->DispatchPluginError(callbackId, errorCode, std::move(errorMessage));
158             return true;
159         } else {
160             LOGW("Dispatcher Upgrade fail when dispatch error mesaage to platform");
161             return false;
162         }
163     }
164 
ChangeLocale(const std::string & language,const std::string & countryOrRegion)165     void ChangeLocale(const std::string& language, const std::string& countryOrRegion)
166     {
167         if (frontendDelegate_) {
168             frontendDelegate_->ChangeLocale(language, countryOrRegion);
169         }
170     }
171 
SetQuickJSNativeEngine(QuickJSNativeEngine * nativeEngine)172     void SetQuickJSNativeEngine(QuickJSNativeEngine* nativeEngine)
173     {
174         nativeEngine_ = nativeEngine;
175     }
176 
GetQuickJSNativeEngine()177     QuickJSNativeEngine* GetQuickJSNativeEngine() const
178     {
179         return nativeEngine_;
180     }
181 
182 private:
183     JSRuntime* runtime_ = nullptr;
184     JSContext* context_ = nullptr;
185     RefPtr<FrontendDelegate> frontendDelegate_;
186     int32_t instanceId_;
187 
188     // runningPage_ is the page that is loaded and rendered successfully, while stagingPage_ is to
189     // handle all page routing situation, which include two stages:
190     // - Loading stage: when a new page is loaded by qjs engine but not rendered, stagingPage_ point to
191     //   a new created page, which is different with runningPage_, the DOM build operations should call
192     //   this one, such as domCreateBody, domAddElement.
193     // - Running stage: If the stagingPage_ rendered successfully, the runningPage_ will update to stagingPage_.
194     //   If the stagingPage_ render failed, it will reset to runningPage_. So in running stage, runningPage_
195     //   and stagingPage_ point to the same page. But it's better to use runningPage_ in dom update tasks,
196     //   such as removeElement, updateElementAttrs and updateElementStyles.
197     RefPtr<JsAcePage> runningPage_;
198     RefPtr<JsAcePage> stagingPage_;
199 
200     WeakPtr<JsMessageDispatcher> dispatcher_;
201     QuickJSNativeEngine* nativeEngine_ = nullptr;
202     mutable std::mutex mutex_;
203 
204     ACE_DISALLOW_COPY_AND_MOVE(QjsEngineInstance);
205 };
206 
207 class QjsEngine : public JsEngine {
208 public:
QjsEngine(int32_t instanceId)209     explicit QjsEngine(int32_t instanceId) : instanceId_(instanceId) {};
210     ~QjsEngine() override;
211 
212     bool Initialize(const RefPtr<FrontendDelegate>& delegate) override;
213 
214     // Load and initialize a JS bundle into the JS Framework
215     void LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage) override;
216 
217     // Update running page
218     void UpdateRunningPage(const RefPtr<JsAcePage>& page) override;
219 
220     // Update staging page
221     void UpdateStagingPage(const RefPtr<JsAcePage>& page) override;
222 
223     // Reset staging page
224     void ResetStagingPage() override;
225 
226     void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) override;
227 
228     // Fire AsyncEvent on JS
229     void FireAsyncEvent(const std::string& eventId, const std::string& param) override;
230 
231     // Fire SyncEvent on JS
232     void FireSyncEvent(const std::string& eventId, const std::string& param) override;
233 
234     void FireExternalEvent(const std::string& componentId, const uint32_t nodeId) override;
235 
236     // Timer callback
237     void TimerCallback(const std::string& callbackId, const std::string& delay, bool isInterval) override;
238 
239     // destroy page instance
240     void DestroyPageInstance(int32_t pageId) override;
241 
242     void MediaQueryCallback(const std::string& callbackId, const std::string& args) override;
243 
244     void RequestAnimationCallback(const std::string& callbackId, uint64_t timeStamp) override;
245 
246     void JsCallback(const std::string& callbackId, const std::string& args) override;
247 
248     // destroy application instance according packageName
DestroyApplication(const std::string & packageName)249     void DestroyApplication(const std::string& packageName) override {}
250 
251     void UpdateApplicationState(const std::string& packageName, Frontend::State state) override;
252 
253     bool OnStartContinuation() override;
254 
255     void OnCompleteContinuation(int32_t code) override;
256 
257     void OnRemoteTerminated() override;
258 
259     void OnSaveData(std::string& data) override;
260 
261     bool OnRestoreData(const std::string& data) override;
262 
263     void RunGarbageCollection() override;
264 
265     RefPtr<GroupJsBridge> GetGroupJsBridge() override;
266 
GetFrontend()267     virtual FrontendDelegate* GetFrontend() override
268     {
269         return AceType::RawPtr(engineInstance_->GetDelegate());
270     }
271 
RunNativeEngineLoop()272     void RunNativeEngineLoop() override
273     {
274         if (nativeEngine_ != nullptr) {
275             nativeEngine_->Loop(LOOP_NOWAIT, false);
276         }
277     }
278 
279 private:
280     void GetLoadOptions(std::string& optionStr, bool isMainPage, const RefPtr<JsAcePage>& page);
281     RefPtr<QjsEngineInstance> engineInstance_;
282     int32_t instanceId_;
283     void RegisterWorker();
284     void RegisterInitWorkerFunc();
285     void RegisterAssetFunc();
286     void SetPostTask(NativeEngine* nativeEngine);
287     QuickJSNativeEngine* nativeEngine_ = nullptr;
288     ACE_DISALLOW_COPY_AND_MOVE(QjsEngine);
289 };
290 
291 } // namespace OHOS::Ace::Framework
292 
293 #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_QUICKJS_QJS_ENGINE_H
294