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