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