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 #include "frameworks/bridge/declarative_frontend/jsview/js_view_functions.h"
17
18 #include "base/log/ace_trace.h"
19 #include "core/pipeline/base/composed_element.h"
20 #include "frameworks/bridge/declarative_frontend/engine/js_execution_scope_defines.h"
21 #include "frameworks/bridge/declarative_frontend/jsview/js_view.h"
22 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
23
24 namespace OHOS::Ace::Framework {
25
ViewFunctions(JSRef<JSObject> jsObject,JSRef<JSFunc> jsRenderFunction)26 ViewFunctions::ViewFunctions(JSRef<JSObject> jsObject, JSRef<JSFunc> jsRenderFunction)
27 {
28 jsObject_ = jsObject;
29
30 JSRef<JSVal> jsAppearFunc = jsObject->GetProperty("aboutToAppear");
31 if (jsAppearFunc->IsFunction()) {
32 jsAppearFunc_ = JSRef<JSFunc>::Cast(jsAppearFunc);
33 }
34
35 JSRef<JSVal> jsDisappearFunc = jsObject->GetProperty("aboutToDisappear");
36 if (jsDisappearFunc->IsFunction()) {
37 jsDisappearFunc_ = JSRef<JSFunc>::Cast(jsDisappearFunc);
38 } else {
39 LOGD("aboutToDisappear is not a function");
40 }
41
42 JSRef<JSVal> jsAboutToBeDeletedFunc = jsObject->GetProperty("aboutToBeDeleted");
43 if (jsAboutToBeDeletedFunc->IsFunction()) {
44 jsAboutToBeDeletedFunc_ = JSRef<JSFunc>::Cast(jsAboutToBeDeletedFunc);
45 } else {
46 LOGD("aboutToBeDeleted is not a function");
47 }
48
49 JSRef<JSVal> jsAboutToRenderFunc = jsObject->GetProperty("aboutToRender");
50 if (jsAboutToRenderFunc->IsFunction()) {
51 jsAboutToRenderFunc_ = JSRef<JSFunc>::Cast(jsAboutToRenderFunc);
52 } else {
53 LOGD("aboutToRender is not a function");
54 }
55
56 JSRef<JSVal> jsRenderDoneFunc = jsObject->GetProperty("onRenderDone");
57 if (jsRenderDoneFunc->IsFunction()) {
58 jsRenderDoneFunc_ = JSRef<JSFunc>::Cast(jsRenderDoneFunc);
59 } else {
60 LOGD("onRenderDone is not a function");
61 }
62
63 JSRef<JSVal> jsAboutToBuildFunc = jsObject->GetProperty("aboutToBuild");
64 if (jsAboutToBuildFunc->IsFunction()) {
65 jsAboutToBuildFunc_ = JSRef<JSFunc>::Cast(jsAboutToBuildFunc);
66 } else {
67 LOGD("aboutToBuild is not a function");
68 }
69
70 JSRef<JSVal> jsBuildDoneFunc = jsObject->GetProperty("onBuildDone");
71 if (jsBuildDoneFunc->IsFunction()) {
72 jsBuildDoneFunc_ = JSRef<JSFunc>::Cast(jsBuildDoneFunc);
73 } else {
74 LOGD("onBuildDone is not a function");
75 }
76
77 JSRef<JSVal> jsTransitionFunc = jsObject->GetProperty("pageTransition");
78 if (jsTransitionFunc->IsFunction()) {
79 jsTransitionFunc_ = JSRef<JSFunc>::Cast(jsTransitionFunc);
80 } else {
81 LOGD("transition is not a function");
82 }
83
84 JSRef<JSVal> jsOnHideFunc = jsObject->GetProperty("onPageHide");
85 if (jsOnHideFunc->IsFunction()) {
86 jsOnHideFunc_ = JSRef<JSFunc>::Cast(jsOnHideFunc);
87 } else {
88 LOGD("onHide is not a function");
89 }
90
91 JSRef<JSVal> jsOnShowFunc = jsObject->GetProperty("onPageShow");
92 if (jsOnShowFunc->IsFunction()) {
93 jsOnShowFunc_ = JSRef<JSFunc>::Cast(jsOnShowFunc);
94 } else {
95 LOGD("onShow is not a function");
96 }
97
98 JSRef<JSVal> jsBackPressFunc = jsObject->GetProperty("onBackPress");
99 if (jsBackPressFunc->IsFunction()) {
100 jsBackPressFunc_ = JSRef<JSFunc>::Cast(jsBackPressFunc);
101 } else {
102 LOGD("onBackPress is not a function");
103 }
104
105 JSRef<JSVal> jsUpdateWithValueParamsFunc = jsObject->GetProperty("updateWithValueParams");
106 if (jsUpdateWithValueParamsFunc->IsFunction()) {
107 LOGD("updateWithValueParams is a function");
108 jsUpdateWithValueParamsFunc_ = JSRef<JSFunc>::Cast(jsUpdateWithValueParamsFunc);
109 } else {
110 LOGD("updateWithValueParams is not a function");
111 }
112
113 jsRenderFunc_ = jsRenderFunction;
114 }
115
ExecuteRender()116 void ViewFunctions::ExecuteRender()
117 {
118 if (jsRenderFunc_.IsEmpty()) {
119 LOGE("no render function in View!");
120 return;
121 }
122
123 auto func = jsRenderFunc_.Lock();
124 JSRef<JSVal> jsThis = jsObject_.Lock();
125 jsRenderResult_ = func->Call(jsThis);
126 }
127
ExecuteAppear()128 void ViewFunctions::ExecuteAppear()
129 {
130 ExecuteFunction(jsAppearFunc_, "aboutToAppear");
131 }
132
ExecuteDisappear()133 void ViewFunctions::ExecuteDisappear()
134 {
135 ExecuteFunction(jsDisappearFunc_, "aboutToDisappear");
136 }
137
ExecuteAboutToBeDeleted()138 void ViewFunctions::ExecuteAboutToBeDeleted()
139 {
140 ExecuteFunction(jsAboutToBeDeletedFunc_, "aboutToDisappear");
141 }
142
ExecuteAboutToRender()143 void ViewFunctions::ExecuteAboutToRender()
144 {
145 // for developer callback.
146 ExecuteFunction(jsAboutToBuildFunc_, "aboutToBuild");
147 // for state manager mark rendering progress.
148 ExecuteFunction(jsAboutToRenderFunc_, "aboutToRender");
149 }
150
ExecuteOnRenderDone()151 void ViewFunctions::ExecuteOnRenderDone()
152 {
153 // for state manager reset rendering progress.
154 ExecuteFunction(jsRenderDoneFunc_, "onRenderDone");
155 // for developer callback.
156 ExecuteFunction(jsBuildDoneFunc_, "onBuildDone");
157 }
158
ExecuteTransition()159 void ViewFunctions::ExecuteTransition()
160 {
161 ExecuteFunction(jsTransitionFunc_, "pageTransition");
162 }
163
HasPageTransition() const164 bool ViewFunctions::HasPageTransition() const
165 {
166 return !jsTransitionFunc_.IsEmpty();
167 }
168
ExecuteShow()169 void ViewFunctions::ExecuteShow()
170 {
171 ExecuteFunction(jsOnShowFunc_, "onPageShow");
172 }
173
ExecuteHide()174 void ViewFunctions::ExecuteHide()
175 {
176 ExecuteFunction(jsOnHideFunc_, "onPageHide");
177 }
178
ExecuteUpdateWithValueParams(const std::string & jsonData)179 void ViewFunctions::ExecuteUpdateWithValueParams(const std::string& jsonData)
180 {
181 ExecuteFunctionWithParams(jsUpdateWithValueParamsFunc_, "updateWithValueParams", jsonData);
182 }
183
ExecuteOnBackPress()184 bool ViewFunctions::ExecuteOnBackPress()
185 {
186 auto ret = ExecuteFunctionWithReturn(jsBackPressFunc_, "onBackPress");
187 if (!ret->IsEmpty() && ret->IsBoolean()) {
188 return ret->ToBoolean();
189 }
190 return false;
191 }
192
ExecuteFunction(JSWeak<JSFunc> & func,const char * debugInfo)193 void ViewFunctions::ExecuteFunction(JSWeak<JSFunc>& func, const char* debugInfo)
194 {
195 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
196 if (func.IsEmpty()) {
197 LOGD("View doesn't have %{public}s() method!", debugInfo);
198 return;
199 }
200 ACE_SCOPED_TRACE("%s", debugInfo);
201 JSRef<JSVal> jsObject = jsObject_.Lock();
202 func.Lock()->Call(jsObject);
203 }
204
ExecuteFunctionWithReturn(JSWeak<JSFunc> & func,const char * debugInfo)205 JSRef<JSVal> ViewFunctions::ExecuteFunctionWithReturn(JSWeak<JSFunc>& func, const char* debugInfo)
206 {
207 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_, JSRef<JSVal>::Make())
208 if (func.IsEmpty()) {
209 LOGD("View doesn't have %{public}s() method!", debugInfo);
210 return JSRef<JSVal>::Make();
211 }
212 ACE_SCOPED_TRACE("%s", debugInfo);
213 JSRef<JSVal> jsObject = jsObject_.Lock();
214 JSRef<JSVal> result = func.Lock()->Call(jsObject);
215 if (result.IsEmpty()) {
216 LOGE("Error calling %{public}s", debugInfo);
217 }
218 return result;
219 }
220
ExecuteFunctionWithParams(JSWeak<JSFunc> & func,const char * debugInfo,const std::string & jsonData)221 void ViewFunctions::ExecuteFunctionWithParams(JSWeak<JSFunc>& func, const char* debugInfo, const std::string& jsonData)
222 {
223 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
224 if (func.IsEmpty()) {
225 LOGD("View doesn't have %{public}s() method!", debugInfo);
226 return;
227 }
228
229 JSRef<JSObject> obj = JSRef<JSObject>::New();
230 JSRef<JSVal> param = obj->ToJsonObject(jsonData.c_str());
231
232 JSRef<JSVal> jsObject = jsObject_.Lock();
233 JSRef<JSVal> result = func.Lock()->Call(jsObject, 1, ¶m);
234 if (result.IsEmpty()) {
235 LOGE("Error calling %{public}s", debugInfo);
236 }
237 }
238
Destroy(JSView * parentCustomView)239 void ViewFunctions::Destroy(JSView* parentCustomView)
240 {
241 LOGD("Destroy");
242 // Might be called from parent view, before any result has been produced??
243 if (jsRenderResult_.IsEmpty()) {
244 LOGD("ViewFunctions::Destroy() -> no previous render result to delete");
245 return;
246 }
247
248 auto renderRes = jsRenderResult_.Lock();
249 if (renderRes.IsEmpty() || !renderRes->IsObject()) {
250 LOGD("ViewFunctions::Destroy() -> result not an object");
251 return;
252 }
253
254 JSRef<JSObject> obj = JSRef<JSObject>::Cast(renderRes);
255 if (!obj.IsEmpty()) {
256 JSView* view = obj->Unwrap<JSView>();
257 view->Destroy(parentCustomView);
258 }
259 jsRenderResult_.Reset();
260 LOGD("ViewFunctions::Destroy() end");
261 }
262
263 } // namespace OHOS::Ace::Framework
264