1 /*
2 * Copyright (c) 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 #include "bridge/declarative_frontend/jsview/js_view_functions.h"
17
18 #include <memory>
19 #include <string>
20
21 #include "base/geometry/calc_dimension.h"
22 #include "base/geometry/dimension.h"
23 #include "base/log/ace_performance_check.h"
24 #include "base/log/ace_trace.h"
25 #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h"
26 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
27 #include "bridge/declarative_frontend/jsview/js_view.h"
28 #include "bridge/declarative_frontend/jsview/js_view_measure_layout.h"
29 #include "bridge/declarative_frontend/view_stack_processor.h"
30 #include "core/components_ng/base/frame_node.h"
31 #include "core/components_ng/layout/layout_wrapper.h"
32 #include "core/pipeline/base/composed_element.h"
33
34 namespace OHOS::Ace::Framework {
35
36 #ifdef USE_ARK_ENGINE
37
38 namespace {
39
GenConstraint(const std::optional<NG::LayoutConstraintF> & parentConstraint)40 JSRef<JSObject> GenConstraint(const std::optional<NG::LayoutConstraintF>& parentConstraint)
41 {
42 auto minSize = parentConstraint->minSize;
43 auto maxSize = parentConstraint->maxSize;
44 JSRef<JSObject> constraint = JSRef<JSObject>::New();
45 constraint->SetProperty<double>("minWidth", minSize.Width());
46 constraint->SetProperty<double>("minHeight", minSize.Height());
47 constraint->SetProperty<double>("maxWidth", maxSize.Width());
48 constraint->SetProperty<double>("maxHeight", maxSize.Height());
49 return constraint;
50 }
51
GenPadding(const std::unique_ptr<NG::PaddingProperty> & paddingNative)52 JSRef<JSObject> GenPadding(const std::unique_ptr<NG::PaddingProperty>& paddingNative)
53 {
54 JSRef<JSObject> padding = JSRef<JSObject>::New();
55 padding->SetProperty("top", paddingNative->top->ToString());
56 padding->SetProperty("right", paddingNative->right->ToString());
57 padding->SetProperty("bottom", paddingNative->bottom->ToString());
58 padding->SetProperty("left", paddingNative->left->ToString());
59 return padding;
60 }
61
GenEdgeWidths(const std::unique_ptr<NG::BorderWidthProperty> & edgeWidthsNative)62 JSRef<JSObject> GenEdgeWidths(const std::unique_ptr<NG::BorderWidthProperty>& edgeWidthsNative)
63 {
64 JSRef<JSObject> edgeWidths = JSRef<JSObject>::New();
65 edgeWidths->SetProperty("top", edgeWidthsNative->topDimen->ToString());
66 edgeWidths->SetProperty("right", edgeWidthsNative->rightDimen->ToString());
67 edgeWidths->SetProperty("bottom", edgeWidthsNative->bottomDimen->ToString());
68 edgeWidths->SetProperty("left", edgeWidthsNative->leftDimen->ToString());
69 return edgeWidths;
70 }
71
GenBorderInfo(const RefPtr<NG::LayoutWrapper> & layoutWrapper)72 JSRef<JSObject> GenBorderInfo(const RefPtr<NG::LayoutWrapper>& layoutWrapper)
73 {
74 JSRef<JSObject> borderInfo = JSRef<JSObject>::New();
75 auto layoutProperty = layoutWrapper->GetLayoutProperty();
76 if (!layoutProperty) {
77 return borderInfo;
78 }
79
80 const std::unique_ptr<NG::PaddingProperty> defaultPadding = std::make_unique<NG::PaddingProperty>();
81 const std::unique_ptr<NG::BorderWidthProperty>& defaultEdgeWidth = std::make_unique<NG::BorderWidthProperty>();
82 borderInfo->SetPropertyObject("borderWidth",
83 GenEdgeWidths(
84 layoutProperty->GetBorderWidthProperty() ? layoutProperty->GetBorderWidthProperty() : defaultEdgeWidth));
85
86 borderInfo->SetPropertyObject("margin",
87 GenPadding(layoutProperty->GetMarginProperty() ? layoutProperty->GetMarginProperty() : defaultPadding));
88 borderInfo->SetPropertyObject("padding",
89 GenPadding(layoutProperty->GetPaddingProperty() ? layoutProperty->GetPaddingProperty() : defaultPadding));
90
91 return borderInfo;
92 }
93
GenPositionInfo(const RefPtr<NG::LayoutWrapper> & layoutWrapper)94 JSRef<JSObject> GenPositionInfo(const RefPtr<NG::LayoutWrapper>& layoutWrapper)
95 {
96 auto offset = layoutWrapper->GetGeometryNode()->GetFrameOffset();
97 JSRef<JSObject> position = JSRef<JSObject>::New();
98 position->SetProperty("x", offset.GetX());
99 position->SetProperty("y", offset.GetY());
100 return position;
101 }
102
GenSelfLayoutInfo(NG::LayoutWrapper * layoutWrapper)103 JSRef<JSObject> GenSelfLayoutInfo(NG::LayoutWrapper* layoutWrapper)
104 {
105 JSRef<JSObject> selfLayoutInfo = JSRef<JSObject>::New();
106 auto layoutProperty = layoutWrapper->GetLayoutProperty();
107 if (!layoutProperty) {
108 return selfLayoutInfo;
109 }
110
111 const std::unique_ptr<NG::PaddingProperty> defaultPadding = std::make_unique<NG::PaddingProperty>();
112 const std::unique_ptr<NG::BorderWidthProperty>& defaultEdgeWidth = std::make_unique<NG::BorderWidthProperty>();
113 selfLayoutInfo->SetPropertyObject("borderWidth",
114 GenEdgeWidths(
115 layoutProperty->GetBorderWidthProperty() ? layoutProperty->GetBorderWidthProperty() : defaultEdgeWidth));
116 selfLayoutInfo->SetPropertyObject("margin",
117 GenPadding(layoutProperty->GetMarginProperty() ? layoutProperty->GetMarginProperty() : defaultPadding));
118 selfLayoutInfo->SetPropertyObject("padding",
119 GenPadding(layoutProperty->GetPaddingProperty() ? layoutProperty->GetPaddingProperty() : defaultPadding));
120 selfLayoutInfo->SetProperty(
121 "width", layoutProperty->GetCalcLayoutConstraint()
122 ? layoutProperty->GetCalcLayoutConstraint()->selfIdealSize->Width()->GetDimension().ConvertToVp()
123 : 0.0f);
124 selfLayoutInfo->SetProperty(
125 "height", layoutProperty->GetCalcLayoutConstraint()
126 ? layoutProperty->GetCalcLayoutConstraint()->selfIdealSize->Height()->GetDimension().ConvertToVp()
127 : 0.0f);
128
129 return selfLayoutInfo;
130 }
131
FillSubComponetProperty(JSRef<JSObject> & info,const RefPtr<NG::LayoutWrapper> & layoutWrapper,const size_t & index)132 void FillSubComponetProperty(JSRef<JSObject>& info, const RefPtr<NG::LayoutWrapper>& layoutWrapper, const size_t& index)
133 {
134 info->SetProperty<std::string>("name", layoutWrapper->GetHostNode()->GetTag());
135 info->SetProperty<std::string>("id", std::to_string(layoutWrapper->GetHostNode()->GetId()));
136 info->SetPropertyObject("constraint", GenConstraint(layoutWrapper->GetLayoutProperty()->GetLayoutConstraint()));
137 info->SetPropertyObject("borderInfo", GenBorderInfo(layoutWrapper));
138 info->SetPropertyObject("position", GenPositionInfo(layoutWrapper));
139 }
140
FillPlaceSizeProperty(JSRef<JSObject> & info,const RefPtr<NG::LayoutWrapper> & layoutWrapper)141 void FillPlaceSizeProperty(JSRef<JSObject>& info, const RefPtr<NG::LayoutWrapper>& layoutWrapper)
142 {
143 auto frameRect = layoutWrapper->GetGeometryNode()->GetFrameRect();
144 JSRef<JSObject> size = JSRef<JSObject>::New();
145
146 Dimension measureWidth(frameRect.GetSize().Width(), DimensionUnit::PX);
147 Dimension measureHeight(frameRect.GetSize().Height(), DimensionUnit::PX);
148 size->SetProperty("width", measureWidth.ConvertToVp());
149 size->SetProperty("height", measureHeight.ConvertToVp());
150 info->SetPropertyObject("measureResult", size);
151 }
152
GenLayoutChildArray(std::list<RefPtr<NG::LayoutWrapper>> children)153 JSRef<JSArray> GenLayoutChildArray(std::list<RefPtr<NG::LayoutWrapper>> children)
154 {
155 JSRef<JSArray> childInfo = JSRef<JSArray>::New();
156 JSRef<JSFunc> layoutFunc = JSRef<JSFunc>::New<FunctionCallback>(ViewMeasureLayout::JSLayout);
157 size_t index = 0;
158
159 for (const auto& iter : children) {
160 JSRef<JSObject> info = JSRef<JSObject>::New();
161 FillSubComponetProperty(info, iter, index);
162 info->SetPropertyObject("layout", layoutFunc);
163 childInfo->SetValueAt(index++, info);
164 }
165
166 return childInfo;
167 }
168
GenPlaceChildrenArray(std::list<RefPtr<NG::LayoutWrapper>> children)169 JSRef<JSArray> GenPlaceChildrenArray(std::list<RefPtr<NG::LayoutWrapper>> children)
170 {
171 JSRef<JSArray> childInfo = JSRef<JSArray>::New();
172 JSRef<JSFunc> layoutFunc = JSRef<JSFunc>::New<FunctionCallback>(ViewMeasureLayout::JSPlaceChildren);
173 size_t index = 0;
174
175 for (const auto& iter : children) {
176 JSRef<JSObject> info = JSRef<JSObject>::New();
177 FillPlaceSizeProperty(info, iter);
178 info->SetPropertyObject("layout", layoutFunc);
179 childInfo->SetValueAt(index++, info);
180 }
181
182 return childInfo;
183 }
184
GenMeasureChildArray(std::list<RefPtr<NG::LayoutWrapper>> children,bool isMeasureSize)185 JSRef<JSArray> GenMeasureChildArray(std::list<RefPtr<NG::LayoutWrapper>> children, bool isMeasureSize)
186 {
187 JSRef<JSArray> childInfo = JSRef<JSArray>::New();
188 JSRef<JSFunc> measureFunc = JSRef<JSFunc>::New<FunctionCallback>(ViewMeasureLayout::JSMeasure);
189 size_t index = 0;
190
191 for (const auto& iter : children) {
192 JSRef<JSObject> info = JSRef<JSObject>::New();
193 if (!isMeasureSize) {
194 FillSubComponetProperty(info, iter, index);
195 }
196 info->SetPropertyObject("measure", measureFunc);
197 childInfo->SetValueAt(index++, info);
198 }
199
200 return childInfo;
201 }
202
203 } // namespace
204
ExecuteLayout(NG::LayoutWrapper * layoutWrapper)205 void ViewFunctions::ExecuteLayout(NG::LayoutWrapper* layoutWrapper)
206 {
207 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
208 ACE_SCOPED_TRACE("ViewFunctions::ExecuteLayout");
209 auto children = layoutWrapper->GetAllChildrenWithBuild();
210 auto parentConstraint = layoutWrapper->GetGeometryNode()->GetParentLayoutConstraint();
211 auto constraint = GenConstraint(parentConstraint);
212 auto childArray = GenLayoutChildArray(children);
213 JSRef<JSVal> params[2] = { childArray, constraint };
214
215 ViewMeasureLayout::SetLayoutChildren(layoutWrapper->GetAllChildrenWithBuild());
216 ViewMeasureLayout::SetDefaultMeasureConstraint(parentConstraint.value());
217 jsLayoutFunc_.Lock()->Call(jsObject_.Lock(), 2, params);
218
219 for (const auto& child : children) {
220 if (child->GetLayoutProperty()->GetPositionProperty()) {
221 child->Layout();
222 }
223 }
224 }
225
ExecuteMeasure(NG::LayoutWrapper * layoutWrapper)226 void ViewFunctions::ExecuteMeasure(NG::LayoutWrapper* layoutWrapper)
227 {
228 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
229 ACE_SCOPED_TRACE("ViewFunctions::ExecuteMeasure");
230 auto children = layoutWrapper->GetAllChildrenWithBuild();
231 auto parentConstraint = layoutWrapper->GetGeometryNode()->GetParentLayoutConstraint();
232 auto constraint = GenConstraint(parentConstraint);
233 auto childArray = GenMeasureChildArray(children, false);
234 JSRef<JSVal> params[2];
235
236 params[0] = childArray;
237 params[1] = constraint;
238
239 ViewMeasureLayout::SetMeasureChildren(children);
240 ViewMeasureLayout::SetDefaultMeasureConstraint(parentConstraint.value());
241 jsMeasureFunc_.Lock()->Call(jsObject_.Lock(), 2, params);
242
243 for (const auto& child : children) {
244 if (child->GetGeometryNode()->GetFrameRect().IsEmpty()) {
245 child->Measure(parentConstraint.value());
246 }
247 }
248 }
249
ExecutePlaceChildren(NG::LayoutWrapper * layoutWrapper)250 void ViewFunctions::ExecutePlaceChildren(NG::LayoutWrapper* layoutWrapper)
251 {
252 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
253 ACE_SCOPED_TRACE("ViewFunctions::ExecutePlaceChildren");
254 auto children = layoutWrapper->GetAllChildrenWithBuild();
255 auto parentConstraint = layoutWrapper->GetGeometryNode()->GetParentLayoutConstraint();
256
257 auto selfLayoutInfo = GenSelfLayoutInfo(layoutWrapper);
258 auto childArray = GenPlaceChildrenArray(children);
259 auto constraint = GenConstraint(parentConstraint);
260
261 JSRef<JSVal> params[3] = { selfLayoutInfo, childArray, constraint };
262
263 ViewMeasureLayout::SetLayoutChildren(layoutWrapper->GetAllChildrenWithBuild());
264 ViewMeasureLayout::SetDefaultMeasureConstraint(parentConstraint.value());
265 jsPlaceChildrenFunc_.Lock()->Call(jsObject_.Lock(), 3, params);
266
267 for (const auto& child : children) {
268 if (child->GetLayoutProperty()->GetPositionProperty()) {
269 child->Layout();
270 }
271 }
272 }
273
ExecuteMeasureSize(NG::LayoutWrapper * layoutWrapper)274 void ViewFunctions::ExecuteMeasureSize(NG::LayoutWrapper* layoutWrapper)
275 {
276 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
277 ACE_SCOPED_TRACE("ViewFunctions::ExecutePlaceChildren");
278 auto children = layoutWrapper->GetAllChildrenWithBuild();
279 auto parentConstraint = layoutWrapper->GetGeometryNode()->GetParentLayoutConstraint();
280
281 auto selfLayoutInfo = GenSelfLayoutInfo(layoutWrapper);
282 auto childArray = GenMeasureChildArray(children, true);
283 auto constraint = GenConstraint(parentConstraint);
284
285 JSRef<JSVal> params[3];
286
287 params[0] = selfLayoutInfo;
288 params[1] = childArray;
289 params[2] = constraint;
290
291 ViewMeasureLayout::SetMeasureChildren(children);
292 ViewMeasureLayout::SetDefaultMeasureConstraint(parentConstraint.value());
293 JSRef<JSObject> result = jsMeasureSizeFunc_.Lock()->Call(jsObject_.Lock(), 3, params);
294
295 for (const auto& child : children) {
296 if (child->GetGeometryNode()->GetFrameRect().IsEmpty()) {
297 child->Measure(parentConstraint.value());
298 }
299 }
300
301 CalcDimension measureWidth;
302 CalcDimension measureHeight;
303 if (!JSViewAbstract::ParseJsDimensionVp(result->GetProperty("width"), measureWidth)) {
304 measureWidth = { -1.0f };
305 }
306 if (!JSViewAbstract::ParseJsDimensionVp(result->GetProperty("height"), measureHeight)) {
307 measureWidth = { -1.0f };
308 }
309 NG::SizeF frameSize = { measureWidth.ConvertToPx(), measureHeight.ConvertToPx() };
310 layoutWrapper->GetGeometryNode()->SetFrameSize(frameSize);
311 NG::CalcSize idealSize = { NG::CalcLength(measureWidth.ConvertToPx()),
312 NG::CalcLength(measureHeight.ConvertToPx()) };
313 layoutWrapper->GetLayoutProperty()->UpdateUserDefinedIdealSize(idealSize);
314 }
315
ExecuteReload(bool deep)316 void ViewFunctions::ExecuteReload(bool deep)
317 {
318 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
319 ACE_SCOPED_TRACE("ViewFunctions::ExecuteReload");
320 auto func = jsReloadFunc_.Lock();
321 if (!func.IsEmpty()) {
322 JSRef<JSVal> params[1];
323 params[0] = JSRef<JSVal>(JSVal(JsiValueConvertor::toJsiValue(deep)));
324 func->Call(jsObject_.Lock(), 1, params);
325 } else {
326 LOGE("the reload func is null");
327 }
328 }
329
ExecuteForceNodeRerender(int32_t elemId)330 void ViewFunctions::ExecuteForceNodeRerender(int32_t elemId)
331 {
332 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
333 ACE_SCOPED_TRACE("ViewFunctions::ExecuteForceNodeRerender");
334 auto func = jsForceRerenderNodeFunc_.Lock();
335 if (!func.IsEmpty()) {
336 JSRef<JSVal> params[1];
337 params[0] = JSRef<JSVal>(JSVal(JsiValueConvertor::toJsiValue(elemId)));
338 func->Call(jsObject_.Lock(), 1, params);
339 } else {
340 LOGE("the force node rerender func is null");
341 }
342 }
343
ExecuteRecycle(const std::string & viewName)344 void ViewFunctions::ExecuteRecycle(const std::string& viewName)
345 {
346 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
347 ACE_SCOPED_TRACE("ViewFunctions::ExecuteRecycle");
348 auto func = jsRecycleFunc_.Lock();
349 if (!func->IsEmpty()) {
350 auto recycleNodeName = JSRef<JSVal>::Make(ToJSValue(viewName));
351 func->Call(jsObject_.Lock(), 1, &recycleNodeName);
352 } else {
353 LOGE("the recycle func is null");
354 }
355 }
356
ExecuteSetActive(bool active)357 void ViewFunctions::ExecuteSetActive(bool active)
358 {
359 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
360 auto func = jsSetActive_.Lock();
361 if (!func->IsEmpty()) {
362 auto isActive = JSRef<JSVal>::Make(ToJSValue(active));
363 func->Call(jsObject_.Lock(), 1, &isActive);
364 } else {
365 LOGE("the set active func is null");
366 }
367 }
368
369 #else
370
371 void ViewFunctions::ExecuteLayout(NG::LayoutWrapper* layoutWrapper) {}
372
373 void ViewFunctions::ExecuteMeasure(NG::LayoutWrapper* layoutWrapper) {}
374
375 void ViewFunctions::ExecutePlaceChildren(NG::LayoutWrapper* layoutWrapper) {}
376
377 void ViewFunctions::ExecuteMeasureSize(NG::LayoutWrapper* layoutWrapper) {}
378
379 void ViewFunctions::ExecuteReload(bool deep) {}
380
381 void ViewFunctions::ExecuteForceNodeRerender(int32_t elemId) {}
382
383 #endif
384
InitViewFunctions(const JSRef<JSObject> & jsObject,const JSRef<JSFunc> & jsRenderFunction,bool partialUpdate)385 void ViewFunctions::InitViewFunctions(
386 const JSRef<JSObject>& jsObject, const JSRef<JSFunc>& jsRenderFunction, bool partialUpdate)
387 {
388 jsObject_ = jsObject;
389
390 if (partialUpdate) {
391 if (jsObject->GetProperty("initialRender")->IsFunction()) {
392 JSRef<JSVal> jsRenderFunc = jsObject->GetProperty("initialRenderView");
393 if (jsRenderFunc->IsFunction()) {
394 jsRenderFunc_ = JSRef<JSFunc>::Cast(jsRenderFunc);
395 } else {
396 LOGE("View lacks mandatory 'initialRenderView()' function, fatal internal error.");
397 }
398 } else {
399 LOGE("View lacks mandatory 'initialRender()' function, fatal internal error.");
400 }
401
402 JSRef<JSVal> jsRerenderFunc = jsObject->GetProperty("rerender");
403 if (jsRerenderFunc->IsFunction()) {
404 jsRerenderFunc_ = JSRef<JSFunc>::Cast(jsRerenderFunc);
405 } else {
406 LOGE("View lacks mandatory 'rerender()' function, fatal internal error.");
407 }
408
409 JSRef<JSVal> jsReloadFunc = jsObject->GetProperty("forceCompleteRerender");
410 if (jsReloadFunc->IsFunction()) {
411 jsReloadFunc_ = JSRef<JSFunc>::Cast(jsReloadFunc);
412 } else {
413 LOGE("View lacks mandatory 'forceCompleteRerender()' function, fatal internal error.");
414 }
415
416 JSRef<JSVal> jsForceRerenderNodeFunc = jsObject->GetProperty("forceRerenderNode");
417 if (jsForceRerenderNodeFunc->IsFunction()) {
418 jsForceRerenderNodeFunc_ = JSRef<JSFunc>::Cast(jsForceRerenderNodeFunc);
419 } else {
420 LOGE("View lacks mandatory 'forceRerenderNode()' function, fatal internal error.");
421 }
422
423 JSRef<JSVal> jsRecycleFunc = jsObject->GetProperty("recycleSelf");
424 if (jsRecycleFunc->IsFunction()) {
425 jsRecycleFunc_ = JSRef<JSFunc>::Cast(jsRecycleFunc);
426 } else {
427 LOGD("View is not a recycle node");
428 }
429
430 JSRef<JSVal> jsAboutToRecycleFunc = jsObject->GetProperty("aboutToRecycle");
431 if (jsAboutToRecycleFunc->IsFunction()) {
432 jsAboutToRecycleFunc_ = JSRef<JSFunc>::Cast(jsAboutToRecycleFunc);
433 }
434
435 JSRef<JSVal> jsSetActive = jsObject->GetProperty("setActiveInternal");
436 if (jsSetActive->IsFunction()) {
437 jsSetActive_ = JSRef<JSFunc>::Cast(jsSetActive);
438 } else {
439 LOGD("View don't have the ability to prevent inactive update");
440 }
441 }
442
443 JSRef<JSVal> jsAppearFunc = jsObject->GetProperty("aboutToAppear");
444 if (jsAppearFunc->IsFunction()) {
445 jsAppearFunc_ = JSRef<JSFunc>::Cast(jsAppearFunc);
446 }
447
448 JSRef<JSVal> jsDisappearFunc = jsObject->GetProperty("aboutToDisappear");
449 if (jsDisappearFunc->IsFunction()) {
450 jsDisappearFunc_ = JSRef<JSFunc>::Cast(jsDisappearFunc);
451 } else {
452 LOGD("aboutToDisappear is not a function");
453 }
454
455 JSRef<JSVal> jsLayoutFunc = jsObject->GetProperty("onLayout");
456 if (jsLayoutFunc->IsFunction()) {
457 jsLayoutFunc_ = JSRef<JSFunc>::Cast(jsLayoutFunc);
458 }
459
460 JSRef<JSVal> jsMeasureFunc = jsObject->GetProperty("onMeasure");
461 if (jsMeasureFunc->IsFunction()) {
462 jsMeasureFunc_ = JSRef<JSFunc>::Cast(jsMeasureFunc);
463 }
464
465 JSRef<JSVal> jsPlaceChildrenFunc = jsObject->GetProperty("onPlaceChildren");
466 if (jsPlaceChildrenFunc->IsFunction()) {
467 jsPlaceChildrenFunc_ = JSRef<JSFunc>::Cast(jsPlaceChildrenFunc);
468 }
469
470 JSRef<JSVal> jsMeasureSizeFunc = jsObject->GetProperty("onMeasureSize");
471 if (jsMeasureSizeFunc->IsFunction()) {
472 jsMeasureSizeFunc_ = JSRef<JSFunc>::Cast(jsMeasureSizeFunc);
473 }
474
475 JSRef<JSVal> jsAboutToBeDeletedFunc = jsObject->GetProperty("aboutToBeDeleted");
476 if (jsAboutToBeDeletedFunc->IsFunction()) {
477 jsAboutToBeDeletedFunc_ = JSRef<JSFunc>::Cast(jsAboutToBeDeletedFunc);
478 } else {
479 LOGD("aboutToBeDeleted is not a function");
480 }
481
482 JSRef<JSVal> jsAboutToRenderFunc = jsObject->GetProperty("aboutToRender");
483 if (jsAboutToRenderFunc->IsFunction()) {
484 jsAboutToRenderFunc_ = JSRef<JSFunc>::Cast(jsAboutToRenderFunc);
485 } else {
486 LOGD("aboutToRender is not a function");
487 }
488
489 JSRef<JSVal> jsRenderDoneFunc = jsObject->GetProperty("onRenderDone");
490 if (jsRenderDoneFunc->IsFunction()) {
491 jsRenderDoneFunc_ = JSRef<JSFunc>::Cast(jsRenderDoneFunc);
492 } else {
493 LOGD("onRenderDone is not a function");
494 }
495
496 JSRef<JSVal> jsAboutToBuildFunc = jsObject->GetProperty("aboutToBuild");
497 if (jsAboutToBuildFunc->IsFunction()) {
498 jsAboutToBuildFunc_ = JSRef<JSFunc>::Cast(jsAboutToBuildFunc);
499 } else {
500 LOGD("aboutToBuild is not a function");
501 }
502
503 JSRef<JSVal> jsBuildDoneFunc = jsObject->GetProperty("onBuildDone");
504 if (jsBuildDoneFunc->IsFunction()) {
505 jsBuildDoneFunc_ = JSRef<JSFunc>::Cast(jsBuildDoneFunc);
506 } else {
507 LOGD("onBuildDone is not a function");
508 }
509
510 JSRef<JSVal> jsTransitionFunc = jsObject->GetProperty("pageTransition");
511 if (jsTransitionFunc->IsFunction()) {
512 jsTransitionFunc_ = JSRef<JSFunc>::Cast(jsTransitionFunc);
513 } else {
514 LOGD("transition is not a function");
515 }
516
517 JSRef<JSVal> jsOnHideFunc = jsObject->GetProperty("onPageHide");
518 if (jsOnHideFunc->IsFunction()) {
519 jsOnHideFunc_ = JSRef<JSFunc>::Cast(jsOnHideFunc);
520 } else {
521 LOGD("onHide is not a function");
522 }
523
524 JSRef<JSVal> jsOnShowFunc = jsObject->GetProperty("onPageShow");
525 if (jsOnShowFunc->IsFunction()) {
526 jsOnShowFunc_ = JSRef<JSFunc>::Cast(jsOnShowFunc);
527 } else {
528 LOGD("onShow is not a function");
529 }
530
531 JSRef<JSVal> jsBackPressFunc = jsObject->GetProperty("onBackPress");
532 if (jsBackPressFunc->IsFunction()) {
533 jsBackPressFunc_ = JSRef<JSFunc>::Cast(jsBackPressFunc);
534 } else {
535 LOGD("onBackPress is not a function");
536 }
537
538 JSRef<JSVal> jsSetInitiallyProvidedValueFunc = jsObject->GetProperty("setInitiallyProvidedValue");
539 if (jsSetInitiallyProvidedValueFunc->IsFunction()) {
540 jsSetInitiallyProvidedValueFunc_ = JSRef<JSFunc>::Cast(jsSetInitiallyProvidedValueFunc);
541 }
542
543 if (!partialUpdate) {
544 JSRef<JSVal> jsUpdateWithValueParamsFunc = jsObject->GetProperty("updateWithValueParams");
545 if (jsUpdateWithValueParamsFunc->IsFunction()) {
546 LOGD("updateWithValueParams is a function");
547 jsUpdateWithValueParamsFunc_ = JSRef<JSFunc>::Cast(jsUpdateWithValueParamsFunc);
548 } else {
549 LOGD("updateWithValueParams is not a function");
550 }
551 jsRenderFunc_ = jsRenderFunction;
552 }
553 }
554
ViewFunctions(const JSRef<JSObject> & jsObject,const JSRef<JSFunc> & jsRenderFunction)555 ViewFunctions::ViewFunctions(const JSRef<JSObject>& jsObject, const JSRef<JSFunc>& jsRenderFunction)
556 {
557 ACE_DCHECK(jsObject);
558 InitViewFunctions(jsObject, jsRenderFunction, false);
559 }
560
ExecuteRender()561 void ViewFunctions::ExecuteRender()
562 {
563 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
564 if (jsRenderFunc_.IsEmpty()) {
565 LOGE("no render function in View!");
566 return;
567 }
568
569 auto func = jsRenderFunc_.Lock();
570 JSRef<JSVal> jsThis = jsObject_.Lock();
571 if (!jsThis->IsUndefined()) {
572 jsRenderResult_ = func->Call(jsThis);
573 } else {
574 LOGE("jsView Object is undefined and will not execute render function");
575 }
576 }
577
ExecuteAppear()578 void ViewFunctions::ExecuteAppear()
579 {
580 ExecuteFunction(jsAppearFunc_, "aboutToAppear");
581 }
582
ExecuteDisappear()583 void ViewFunctions::ExecuteDisappear()
584 {
585 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
586 if (jsDisappearFunc_.IsEmpty()) {
587 LOGD("View doesn't have %{public}s() method!", "aboutToDisappear");
588 return;
589 }
590 ACE_SCOPED_TRACE("%s", "aboutToDisappear");
591 JSRef<JSVal> jsObject = jsObject_.Lock();
592 std::string functionName("aboutToDisappear");
593 AceScopedPerformanceCheck scoped(functionName);
594 if (!jsObject->IsUndefined()) {
595 jsDisappearFunc_.Lock()->Call(jsObject);
596 } else {
597 LOGE("jsView Object is undefined and will not execute aboutToDisappear function");
598 }
599 }
600
ExecuteAboutToRecycle()601 void ViewFunctions::ExecuteAboutToRecycle()
602 {
603 ExecuteFunction(jsAboutToRecycleFunc_, "aboutToRecycle");
604 }
605
HasLayout() const606 bool ViewFunctions::HasLayout() const
607 {
608 return !jsLayoutFunc_.IsEmpty();
609 }
610
HasMeasure() const611 bool ViewFunctions::HasMeasure() const
612 {
613 return !jsMeasureFunc_.IsEmpty();
614 }
615
HasPlaceChildren() const616 bool ViewFunctions::HasPlaceChildren() const
617 {
618 return !jsPlaceChildrenFunc_.IsEmpty();
619 }
620
HasMeasureSize() const621 bool ViewFunctions::HasMeasureSize() const
622 {
623 return !jsMeasureSizeFunc_.IsEmpty();
624 }
625
ExecuteAboutToBeDeleted()626 void ViewFunctions::ExecuteAboutToBeDeleted()
627 {
628 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
629 if (jsAboutToBeDeletedFunc_.IsEmpty()) {
630 LOGD("View doesn't have %{public}s() method!", "aboutToBeDeleted");
631 return;
632 }
633 ACE_SCOPED_TRACE("%s", "aboutToBeDeleted");
634 JSRef<JSVal> jsObject = jsObject_.Lock();
635 std::string functionName("aboutToBeDeleted");
636 AceScopedPerformanceCheck scoped(functionName);
637 if (!jsObject->IsUndefined()) {
638 jsAboutToBeDeletedFunc_.Lock()->Call(jsObject);
639 } else {
640 LOGE("jsView Object is undefined and will not execute aboutToBeDeleted function");
641 }
642 }
643
ExecuteAboutToRender()644 void ViewFunctions::ExecuteAboutToRender()
645 {
646 // for developer callback.
647 ExecuteFunction(jsAboutToBuildFunc_, "aboutToBuild");
648 // for state manager mark rendering progress.
649 ExecuteFunction(jsAboutToRenderFunc_, "aboutToRender");
650 }
651
ExecuteOnRenderDone()652 void ViewFunctions::ExecuteOnRenderDone()
653 {
654 // for state manager reset rendering progress.
655 ExecuteFunction(jsRenderDoneFunc_, "onRenderDone");
656 // for developer callback.
657 ExecuteFunction(jsBuildDoneFunc_, "onBuildDone");
658 }
659
ExecuteTransition()660 void ViewFunctions::ExecuteTransition()
661 {
662 ExecuteFunction(jsTransitionFunc_, "pageTransition");
663 }
664
HasPageTransition() const665 bool ViewFunctions::HasPageTransition() const
666 {
667 return !jsTransitionFunc_.IsEmpty();
668 }
669
ExecuteShow()670 void ViewFunctions::ExecuteShow()
671 {
672 ExecuteFunction(jsOnShowFunc_, "onPageShow");
673 }
674
ExecuteHide()675 void ViewFunctions::ExecuteHide()
676 {
677 ExecuteFunction(jsOnHideFunc_, "onPageHide");
678 }
679
ExecuteInitiallyProvidedValue(const std::string & jsonData)680 void ViewFunctions::ExecuteInitiallyProvidedValue(const std::string& jsonData)
681 {
682 ExecuteFunctionWithParams(jsSetInitiallyProvidedValueFunc_, "setInitiallyProvidedValue", jsonData);
683 }
684
685 // Method not needed for Partial Update code path
ExecuteUpdateWithValueParams(const std::string & jsonData)686 void ViewFunctions::ExecuteUpdateWithValueParams(const std::string& jsonData)
687 {
688 ExecuteFunctionWithParams(jsUpdateWithValueParamsFunc_, "updateWithValueParams", jsonData);
689 }
690
ExecuteOnBackPress()691 bool ViewFunctions::ExecuteOnBackPress()
692 {
693 auto ret = ExecuteFunctionWithReturn(jsBackPressFunc_, "onBackPress");
694 if (!ret->IsEmpty() && ret->IsBoolean()) {
695 return ret->ToBoolean();
696 }
697 return false;
698 }
699
ExecuteFunction(JSWeak<JSFunc> & func,const char * debugInfo)700 void ViewFunctions::ExecuteFunction(JSWeak<JSFunc>& func, const char* debugInfo)
701 {
702 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
703 if (func.IsEmpty()) {
704 LOGD("View doesn't have %{public}s() method!", debugInfo);
705 return;
706 }
707 ACE_SCOPED_TRACE("%s", debugInfo);
708 JSRef<JSVal> jsObject = jsObject_.Lock();
709 if (!jsObject->IsUndefined()) {
710 std::string functionName(debugInfo);
711 AceScopedPerformanceCheck scoped(functionName);
712 func.Lock()->Call(jsObject);
713 } else {
714 LOGE("jsObject is undefined. Internal error while trying to exec %{public}s", debugInfo);
715 }
716 }
717
ExecuteFunctionWithReturn(JSWeak<JSFunc> & func,const char * debugInfo)718 JSRef<JSVal> ViewFunctions::ExecuteFunctionWithReturn(JSWeak<JSFunc>& func, const char* debugInfo)
719 {
720 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_, JSRef<JSVal>::Make())
721 if (func.IsEmpty()) {
722 LOGD("View doesn't have %{public}s() method!", debugInfo);
723 return JSRef<JSVal>::Make();
724 }
725 ACE_SCOPED_TRACE("%s", debugInfo);
726 JSRef<JSVal> jsObject = jsObject_.Lock();
727 std::string functionName(debugInfo);
728 AceScopedPerformanceCheck scoped(functionName);
729 JSRef<JSVal> result = func.Lock()->Call(jsObject);
730 if (result.IsEmpty()) {
731 LOGE("Error calling %{public}s", debugInfo);
732 }
733 return result;
734 }
735
ExecuteFunctionWithParams(JSWeak<JSFunc> & func,const char * debugInfo,const std::string & jsonData)736 void ViewFunctions::ExecuteFunctionWithParams(JSWeak<JSFunc>& func, const char* debugInfo, const std::string& jsonData)
737 {
738 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
739 if (func.IsEmpty()) {
740 LOGD("View doesn't have %{public}s() method!", debugInfo);
741 return;
742 }
743
744 JSRef<JSObject> obj = JSRef<JSObject>::New();
745 JSRef<JSVal> param = obj->ToJsonObject(jsonData.c_str());
746
747 JSRef<JSVal> jsObject = jsObject_.Lock();
748 JSRef<JSVal> result = func.Lock()->Call(jsObject, 1, ¶m);
749 if (result.IsEmpty()) {
750 LOGE("Error calling %{public}s", debugInfo);
751 }
752 }
753
754 // Baseline version of Destroy
Destroy(JSView * parentCustomView)755 void ViewFunctions::Destroy(JSView* parentCustomView)
756 {
757 LOGD("Destroy");
758 // Might be called from parent view, before any result has been produced??
759 if (jsRenderResult_.IsEmpty()) {
760 LOGD("ViewFunctions::Destroy() -> no previous render result to delete");
761 return;
762 }
763
764 auto renderRes = jsRenderResult_.Lock();
765 if (renderRes.IsEmpty() || !renderRes->IsObject()) {
766 LOGD("ViewFunctions::Destroy() -> result not an object");
767 return;
768 }
769
770 JSRef<JSObject> obj = JSRef<JSObject>::Cast(renderRes);
771 if (!obj.IsEmpty()) {
772 // jsRenderResult_ maybe an js exception, not a JSView
773 JSView* view = obj->Unwrap<JSView>();
774 if (view != nullptr) {
775 view->Destroy(parentCustomView);
776 }
777 }
778 jsRenderResult_.Reset();
779 LOGD("ViewFunctions::Destroy() end");
780 }
781
782 // PartialUpdate version of Destroy
Destroy()783 void ViewFunctions::Destroy()
784 {
785 LOGD("Destroy");
786
787 // Might be called from parent view, before any result has been produced??
788 if (jsRenderResult_.IsEmpty()) {
789 LOGD("ViewFunctions::Destroy() -> no previous render result to delete");
790 return;
791 }
792
793 auto renderRes = jsRenderResult_.Lock();
794 if (renderRes.IsEmpty() || !renderRes->IsObject()) {
795 LOGD("ViewFunctions::Destroy() -> result not an object");
796 return;
797 }
798
799 // merging: when would a render function return a JSView ?
800 JSRef<JSObject> obj = JSRef<JSObject>::Cast(renderRes);
801 if (!obj.IsEmpty()) {
802 // jsRenderResult_ maybe an js exception, not a JSView
803 JSView* view = obj->Unwrap<JSView>();
804 if (view != nullptr) {
805 LOGE("NOTE NOTE NOTE render returned a JSView object that's dangling!");
806 }
807 }
808 jsObject_.Reset();
809 jsRenderResult_.Reset();
810
811 LOGD("ViewFunctions::Destroy() end");
812 }
813
814 // Partial update method
ExecuteRerender()815 void ViewFunctions::ExecuteRerender()
816 {
817 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(context_)
818 if (jsRerenderFunc_.IsEmpty()) {
819 LOGE("no rerender function in View!");
820 return;
821 }
822
823 auto func = jsRerenderFunc_.Lock();
824 JSRef<JSVal> jsThis = jsObject_.Lock();
825 if (!jsThis->IsUndefined()) {
826 jsRenderResult_ = func->Call(jsThis);
827 } else {
828 LOGE("jsView Object is undefined and will not execute rerender function");
829 }
830 }
831
832 // Partial update method
ViewFunctions(const JSRef<JSObject> & jsObject)833 ViewFunctions::ViewFunctions(const JSRef<JSObject>& jsObject)
834 {
835 InitViewFunctions(jsObject, JSRef<JSFunc>(), true);
836 }
837
838 } // namespace OHOS::Ace::Framework
839