• 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 FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_QUICKJS_QJS_DECLARATIVE_ENGINE_H
17 #define FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_QUICKJS_QJS_DECLARATIVE_ENGINE_H
18 
19 #include <unordered_map>
20 
21 #include "third_party/quickjs/quickjs.h"
22 
23 #if defined(PREVIEW)
24 #include "adapter/preview/osal/request_data.h"
25 #endif
26 #include "frameworks/bridge/js_frontend/engine/common/js_engine.h"
27 #include "frameworks/bridge/js_frontend/js_ace_page.h"
28 
29 namespace OHOS::Ace::Framework {
30 
31 class QJSDeclarativeEngineInstance final : public AceType, public JsEngineInstance {
32 public:
33     explicit QJSDeclarativeEngineInstance(const RefPtr<FrontendDelegate>& delegate, int32_t instanceId = 0)
context_(nullptr)34         : context_(nullptr), frontendDelegate_(delegate), instanceId_(instanceId), dispatcher_(nullptr)
35     {}
36 
37     ~QJSDeclarativeEngineInstance() override;
38     void FlushCommandBuffer(void* context, const std::string& command) override;
39     bool InitJSEnv(
40         JSRuntime* runtime, JSContext* context, const std::unordered_map<std::string, void*>& extraNativeObject);
41 
42     bool InitAceModules(const char* start, size_t length, const char* fileName);
43 
44     void InitJsNativeModuleObject(JSContext* ctx);
45     void InitJsExportsUtilObject(JSContext* ctx);
46 
47     void loadDocument();
48 
49     void FreeGroupJsBridge();
50 
GetQJSRuntime()51     static JSRuntime* GetQJSRuntime()
52     {
53         return runtime_;
54     }
55 
GetQJSContext()56     JSContext* GetQJSContext() const
57     {
58         return context_;
59     }
60 
61     static QJSDeclarativeEngineInstance* UnWrapEngineInstance(JSContext* ctx);
62 
GetRunningPage()63     RefPtr<JsAcePage> GetRunningPage() const
64     {
65         std::lock_guard<std::mutex> lock(mutex_);
66         return runningPage_;
67     }
68 
69     static RefPtr<JsAcePage> GetRunningPage(JSContext* ctx);
70     static RefPtr<JsAcePage> GetStagingPage(JSContext* ctx);
71     static JSContext* GetCurrentContext();
72 
73     void SetStagingPage(const RefPtr<JsAcePage>& page);
74 
GetStagingPage()75     RefPtr<JsAcePage> GetStagingPage() const
76     {
77         std::lock_guard<std::mutex> lock(mutex_);
78         return stagingPage_;
79     }
80     void ResetStagingPage(const RefPtr<JsAcePage>& page);
81 
82     void SetRunningPage(const RefPtr<JsAcePage>& page);
83 
84     static void PostJsTask(JSContext* ctx, std::function<void()>&& task);
85     static void TriggerPageUpdate(JSContext* ctx);
86     static RefPtr<PipelineBase> GetPipelineContext(JSContext* ctx);
87 
SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher> & dispatcher)88     void SetJsMessageDispatcher(const RefPtr<JsMessageDispatcher>& dispatcher)
89     {
90         dispatcher_ = dispatcher;
91     }
92 
GetDelegate()93     RefPtr<FrontendDelegate> GetDelegate() const
94     {
95         return frontendDelegate_;
96     }
97 
98     JSValue CompileSource(std::string instanceName, std::string url, const char* buf, size_t bufSize);
99 
CallPlatformFunction(const std::string & channel,std::vector<uint8_t> && data,int32_t id,int32_t groupType)100     void CallPlatformFunction(const std::string& channel, std::vector<uint8_t>&& data, int32_t id, int32_t groupType)
101     {
102         auto dispatcher = dispatcher_.Upgrade();
103         if (dispatcher) {
104             dispatcher->Dispatch(channel, std::move(data), id, groupType);
105         }
106     }
107 
108     void CallAnimationFinishJs(JSValue animationContext);
109     void CallAnimationCancelJs(JSValue animationContext);
110 
111 #if defined(PREVIEW)
CallCurlFunction(const OHOS::Ace::RequestData & requestData,int32_t callbackId)112     bool CallCurlFunction(const OHOS::Ace::RequestData& requestData, int32_t callbackId)
113     {
114         auto dispatcher = dispatcher_.Upgrade();
115         if (dispatcher) {
116             dispatcher->CallCurlFunction(requestData, callbackId);
117             return true;
118         } else {
119             LOGW("Dispatcher Upgrade fail when dispatch request message to platform");
120             return false;
121         }
122     }
123 #endif
124 
125     bool ExecuteDocumentJS(JSValue jsCode);
126 
127     void FireAsyncEvent(const std::string& eventId, const std::string& param);
128 
129     /** Pushes the given command on the currently loading page
130      * if conditions apply also flushed the command queue
131      * if forceFlush=true is specified the command buffer will be flushed.
132      * even if conditions are not met.
133      */
134     void PushJSCommand(const RefPtr<JsCommand>& jsCommand, bool forceFlush = false) const;
135     static void PushJSCommand(JSContext* ctx, const RefPtr<JsCommand>& jsCommand, bool forceFlush = false);
136 
PluginErrorCallback(int32_t callbackId,int32_t errorCode,std::string && errorMessage)137     void PluginErrorCallback(int32_t callbackId, int32_t errorCode, std::string&& errorMessage)
138     {
139         auto dispatcher = dispatcher_.Upgrade();
140         if (dispatcher) {
141             dispatcher->DispatchPluginError(callbackId, errorCode, std::move(errorMessage));
142         }
143     }
144 
ChangeLocale(const std::string & language,const std::string & countryOrRegion)145     void ChangeLocale(const std::string& language, const std::string& countryOrRegion)
146     {
147         if (frontendDelegate_) {
148             frontendDelegate_->ChangeLocale(language, countryOrRegion);
149         }
150     }
151 
152     void RunGarbageCollection();
153 
154     static std::unique_ptr<JsonValue> GetI18nStringResource(
155         const std::string& targetStringKey, const std::string& targetStringValue);
156     static std::string GetMediaResource(const std::string& targetMediaFileName);
157     static int EvalBuf(JSContext* ctx, const char* buf, size_t bufLen, const char* filename, int evalFlags);
158 
159 #if defined(PREVIEW)
SetPreviewFlag(bool flag)160     void SetPreviewFlag(bool flag)
161     {
162         isComponentPreview_ = flag;
163     }
164 
GetPreviewFlag()165     bool GetPreviewFlag() const
166     {
167         return isComponentPreview_;
168     }
169 
GetRequiredComponent()170     std::string GetRequiredComponent() const
171     {
172         return requiredComponent_;
173     }
174 
SetRequiredComponent(const std::string & componentName)175     void SetRequiredComponent(const std::string& componentName)
176     {
177         requiredComponent_ = componentName;
178     }
179 
AddPreviewComponent(const std::string & componentName,JSValue & componentObj)180     void AddPreviewComponent(const std::string& componentName, JSValue& componentObj)
181     {
182         previewComponents_.insert_or_assign(componentName, componentObj);
183     }
184 
GetPreviewComponent(const std::string & componentName)185     JSValue GetPreviewComponent(const std::string& componentName)
186     {
187         auto iter = previewComponents_.find(componentName);
188         if (iter != previewComponents_.end()) {
189             return iter->second;
190         }
191         return JS_UNDEFINED;
192     }
193 #endif
194 
195 private:
196 #if defined(PREVIEW)
197     bool isComponentPreview_ = false;
198     std::string requiredComponent_ {};
199     std::unordered_map<std::string, JSValue> previewComponents_;
200 #endif
201 
202     void output_object_code(JSContext* ctx, int fho, JSValueConst obj);
203     JSValue eval_binary_buf(JSContext* ctx, const uint8_t* buf, size_t buf_len);
204 
205     thread_local static JSRuntime* runtime_;
206     JSContext* context_ = nullptr;
207     RefPtr<FrontendDelegate> frontendDelegate_;
208     int32_t instanceId_;
209     static std::map<std::string, std::string> mediaResourceFileMap_;
210     static std::unique_ptr<JsonValue> currentConfigResourceData_;
211 
212     // runningPage_ is the page that is loaded and rendered successfully, while stagingPage_ is to
213     // handle all page routing situation, which include two stages:
214     // - Loading stage: when a new page is loaded by qjs engine but not rendered, stagingPage_ point to
215     //   a new created page, which is different with runningPage_, the DOM build operations should call
216     //   this one, such as domCreateBody, domAddElement.
217     // - Running stage: If the stagingPage_ rendered successfully, the runningPage_ will update to stagingPage_.
218     //   If the stagingPage_ render failed, it will reset to runningPage_. So in running stage, runningPage_
219     //   and stagingPage_ point to the same page. But it's better to use runningPage_ in dom update tasks,
220     //   such as removeElement, updateElementAttrs and updateElementStyles.
221     RefPtr<JsAcePage> runningPage_;
222     RefPtr<JsAcePage> stagingPage_;
223 
224     WeakPtr<JsMessageDispatcher> dispatcher_;
225     mutable std::mutex mutex_;
226 
227     ACE_DISALLOW_COPY_AND_MOVE(QJSDeclarativeEngineInstance);
228 };
229 
230 } // namespace OHOS::Ace::Framework
231 
232 #endif // FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_ENGINE_QUICKJS_QJS_DECLARATIVE_ENGINE_H
233