• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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(PREVIEW)
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 {
DECLARE_ACE_TYPE(QjsEngineInstance,AceType)41     DECLARE_ACE_TYPE(QjsEngineInstance, AceType)
42 public:
43     explicit QjsEngineInstance(const RefPtr<FrontendDelegate>& delegate, int32_t instanceId)
44         : frontendDelegate_(delegate), instanceId_(instanceId)
45     {}
46     ~QjsEngineInstance() override;
47 
48     void FlushCommandBuffer(void* context, const std::string& command) override;
49 
50     bool InitJsEnv(
51         JSRuntime* runtime, JSContext* context, const std::unordered_map<std::string, void*>& extraNativeObject);
52 
GetQjsRuntime()53     JSRuntime* GetQjsRuntime() const
54     {
55         return runtime_;
56     }
57 
GetQjsContext()58     JSContext* GetQjsContext() const
59     {
60         return context_;
61     }
62 
63     void CallJs(const std::string& callbackId, const std::string& args, bool keepAlive = false, bool isGlobal = false);
64 
65     void CallAnimationStartJs(JSValue animationContext);
66     void CallAnimationFinishJs(JSValue animationContext);
67     void CallAnimationCancelJs(JSValue animationContext);
68     void CallAnimationRepeatJs(JSValue animationContext);
69     void CallAnimationFrameJs(JSValue animationContext, const char* str);
70 
71     JSValue FireJsEvent(const std::string& param);
72 
73     void FreeGroupJsBridge();
74 
SetRunningPage(const RefPtr<JsAcePage> & page)75     void SetRunningPage(const RefPtr<JsAcePage>& page)
76     {
77         std::lock_guard<std::mutex> lock(mutex_);
78         runningPage_ = page;
79     }
80 
GetRunningPage()81     RefPtr<JsAcePage> GetRunningPage() const
82     {
83         std::lock_guard<std::mutex> lock(mutex_);
84         return runningPage_;
85     }
86 
SetStagingPage(const RefPtr<JsAcePage> & page)87     void SetStagingPage(const RefPtr<JsAcePage>& page)
88     {
89         std::lock_guard<std::mutex> lock(mutex_);
90         stagingPage_ = page;
91     }
92 
GetStagingPage()93     RefPtr<JsAcePage> GetStagingPage() const
94     {
95         std::lock_guard<std::mutex> lock(mutex_);
96         return stagingPage_;
97     }
98 
ResetStagingPage(const RefPtr<JsAcePage> & page)99     void ResetStagingPage(const RefPtr<JsAcePage>& page)
100     {
101         std::lock_guard<std::mutex> lock(mutex_);
102         stagingPage_ = page;
103     }
104 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)105     void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher)
106     {
107         dispatcher_ = dispatcher;
108     }
109 
GetDelegate()110     RefPtr<FrontendDelegate> GetDelegate() const
111     {
112         return frontendDelegate_;
113     }
114 
CallPlatformFunction(const std::string & channel,std::vector<uint8_t> && data,int32_t id)115     bool CallPlatformFunction(const std::string& channel, std::vector<uint8_t>&& data, int32_t id)
116     {
117         auto dispatcher = dispatcher_.Upgrade();
118         if (dispatcher) {
119             dispatcher->Dispatch(channel, std::move(data), id);
120             return true;
121         } else {
122             LOGW("Dispatcher Upgrade fail when dispatch request message to platform");
123             return false;
124         }
125     }
126 
CallPlatformFunctionSync(const std::string & channel,std::vector<uint8_t> && data,uint8_t ** resData,int64_t & position)127     bool CallPlatformFunctionSync(
128         const std::string& channel, std::vector<uint8_t>&& data, uint8_t** resData, int64_t& position)
129     {
130         auto dispatcher = dispatcher_.Upgrade();
131         if (dispatcher) {
132             dispatcher->DispatchSync(channel, std::move(data), resData, position);
133             return true;
134         } else {
135             LOGW("Dispatcher Upgrade fail when dispatch request message to platform");
136             return false;
137         }
138     }
139 
140 #if defined(PREVIEW)
CallCurlFunction(const OHOS::Ace::RequestData & requestData,int32_t callbackId)141     bool CallCurlFunction(const OHOS::Ace::RequestData& requestData, int32_t callbackId)
142     {
143         auto dispatcher = dispatcher_.Upgrade();
144         if (dispatcher) {
145             dispatcher->CallCurlFunction(requestData, callbackId);
146             return true;
147         } else {
148             LOGW("Dispatcher Upgrade fail when dispatch request message to platform");
149             return false;
150         }
151     }
152 #endif
153 
PluginErrorCallback(int32_t callbackId,int32_t errorCode,std::string && errorMessage)154     bool PluginErrorCallback(int32_t callbackId, int32_t errorCode, std::string&& errorMessage)
155     {
156         auto dispatcher = dispatcher_.Upgrade();
157         if (dispatcher) {
158             dispatcher->DispatchPluginError(callbackId, errorCode, std::move(errorMessage));
159             return true;
160         } else {
161             LOGW("Dispatcher Upgrade fail when dispatch error message to platform");
162             return false;
163         }
164     }
165 
ChangeLocale(const std::string & language,const std::string & countryOrRegion)166     void ChangeLocale(const std::string& language, const std::string& countryOrRegion)
167     {
168         if (frontendDelegate_) {
169             frontendDelegate_->ChangeLocale(language, countryOrRegion);
170         }
171     }
172 
SetQuickJSNativeEngine(QuickJSNativeEngine * nativeEngine)173     void SetQuickJSNativeEngine(QuickJSNativeEngine* nativeEngine)
174     {
175         nativeEngine_ = nativeEngine;
176     }
177 
GetQuickJSNativeEngine()178     QuickJSNativeEngine* GetQuickJSNativeEngine() const
179     {
180         return nativeEngine_;
181     }
182 
183 private:
184     bool IsDragEvent(const std::string& param);
185     JSRuntime* runtime_ = nullptr;
186     JSContext* context_ = nullptr;
187     RefPtr<FrontendDelegate> frontendDelegate_;
188     int32_t instanceId_;
189 
190     // runningPage_ is the page that is loaded and rendered successfully, while stagingPage_ is to
191     // handle all page routing situation, which include two stages:
192     // - Loading stage: when a new page is loaded by qjs engine but not rendered, stagingPage_ point to
193     //   a new created page, which is different with runningPage_, the DOM build operations should call
194     //   this one, such as domCreateBody, domAddElement.
195     // - Running stage: If the stagingPage_ rendered successfully, the runningPage_ will update to stagingPage_.
196     //   If the stagingPage_ render failed, it will reset to runningPage_. So in running stage, runningPage_
197     //   and stagingPage_ point to the same page. But it's better to use runningPage_ in dom update tasks,
198     //   such as removeElement, updateElementAttrs and updateElementStyles.
199     RefPtr<JsAcePage> runningPage_;
200     RefPtr<JsAcePage> stagingPage_;
201 
202     WeakPtr<JsMessageDispatcher> dispatcher_;
203     QuickJSNativeEngine* nativeEngine_ = nullptr;
204     mutable std::mutex mutex_;
205 
206     ACE_DISALLOW_COPY_AND_MOVE(QjsEngineInstance);
207 };
208 
209 class QjsEngine : public JsEngine {
DECLARE_ACE_TYPE(QjsEngine,JsEngine)210     DECLARE_ACE_TYPE(QjsEngine, JsEngine)
211 public:
212     explicit QjsEngine(int32_t instanceId) : instanceId_(instanceId) {}
213     ~QjsEngine() override;
214 
215     bool Initialize(const RefPtr<FrontendDelegate>& delegate) override;
216 
217     // Load and initialize a JS bundle into the JS Framework
218     void LoadJs(const std::string& url, const RefPtr<JsAcePage>& page, bool isMainPage) override;
219 
220     // Update running page
221     void UpdateRunningPage(const RefPtr<JsAcePage>& page) override;
222 
223     // Update staging page
224     void UpdateStagingPage(const RefPtr<JsAcePage>& page) override;
225 
226     // Reset staging page
227     void ResetStagingPage() override;
228 
229     void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher) override;
230 
231     // Fire AsyncEvent on JS
232     void FireAsyncEvent(const std::string& eventId, const std::string& param) override;
233 
234     // Fire SyncEvent on JS
235     void FireSyncEvent(const std::string& eventId, const std::string& param) override;
236 
237     void FireExternalEvent(const std::string& componentId, const uint32_t nodeId, const bool isDestroy) override;
238 
239     // Timer callback
240     void TimerCallback(const std::string& callbackId, const std::string& delay, bool isInterval) override;
241 
242     // destroy page instance
243     void DestroyPageInstance(int32_t pageId) override;
244 
245     void MediaQueryCallback(const std::string& callbackId, const std::string& args) override;
246 
247     void RequestAnimationCallback(const std::string& callbackId, uint64_t timeStamp) override;
248 
249     void JsCallback(const std::string& callbackId, const std::string& args) override;
250 
251     // destroy application instance according packageName
DestroyApplication(const std::string & packageName)252     void DestroyApplication(const std::string& packageName) override {}
253 
254     void UpdateApplicationState(const std::string& packageName, Frontend::State state) override;
255 
256     bool OnStartContinuation() override;
257 
258     void OnCompleteContinuation(int32_t code) override;
259 
260     void OnRemoteTerminated() override;
261 
262     void OnSaveData(std::string& data) override;
263 
264     bool OnRestoreData(const std::string& data) override;
265 
266     void RunGarbageCollection() override;
267 
268     RefPtr<GroupJsBridge> GetGroupJsBridge() override;
269 
GetFrontend()270     FrontendDelegate* GetFrontend() override
271     {
272         return AceType::RawPtr(engineInstance_->GetDelegate());
273     }
274 
275     static std::map<const std::string, std::string> dataMap_;
276 
277 private:
278     void GetLoadOptions(std::string& optionStr, bool isMainPage, const RefPtr<JsAcePage>& page);
279     RefPtr<QjsEngineInstance> engineInstance_;
280     int32_t instanceId_;
281     void RegisterWorker();
282     void RegisterInitWorkerFunc();
283     void RegisterAssetFunc();
284     void SetPostTask(NativeEngine* nativeEngine);
285     ACE_DISALLOW_COPY_AND_MOVE(QjsEngine);
286 };
287 
288 } // namespace OHOS::Ace::Framework
289 
290 #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_QUICKJS_QJS_ENGINE_H
291