• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 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 #include "bridge/declarative_frontend/jsview/js_base_node.h"
16 
17 #include <memory>
18 #include <queue>
19 #include <string>
20 
21 #include "canvas_napi/js_canvas.h"
22 #include "jsnapi_expo.h"
23 
24 #include "base/geometry/dimension.h"
25 #include "base/log/ace_trace.h"
26 #include "base/memory/ace_type.h"
27 #include "base/memory/referenced.h"
28 #include "base/utils/utils.h"
29 #include "bridge/common/utils/engine_helper.h"
30 #include "bridge/declarative_frontend/engine/jsi/nativeModule/ui_context_helper.h"
31 #include "bridge/declarative_frontend/engine/functions/js_function.h"
32 #include "bridge/declarative_frontend/engine/js_converter.h"
33 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
34 #include "bridge/declarative_frontend/engine/js_types.h"
35 #include "bridge/declarative_frontend/jsview/js_utils.h"
36 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
37 #include "bridge/js_frontend/engine/jsi/js_value.h"
38 #include "core/components_ng/base/frame_node.h"
39 #include "core/components_ng/base/modifier.h"
40 #include "core/components_ng/base/ui_node.h"
41 #include "core/components_ng/base/view_stack_processor.h"
42 #include "core/components_ng/pattern/custom_frame_node/custom_frame_node.h"
43 #include "core/components_ng/pattern/render_node/render_node_pattern.h"
44 #include "core/components_ng/pattern/stack/stack_pattern.h"
45 #include "core/components_ng/render/drawing_forward.h"
46 #include "core/event/touch_event.h"
47 #include "core/pipeline/pipeline_base.h"
48 #include "core/pipeline_ng/pipeline_context.h"
49 
50 namespace OHOS::Ace::Framework {
51 namespace {
52 const std::unordered_set<std::string> EXPORT_TEXTURE_SUPPORT_TYPES = { V2::JS_VIEW_ETS_TAG, V2::COMMON_VIEW_ETS_TAG };
53 constexpr int32_t INFO_LENGTH_LIMIT = 2;
54 constexpr int32_t BUILD_PARAM_INDEX_TWO = 2;
55 constexpr int32_t BUILD_PARAM_INDEX_THREE = 3;
56 constexpr int32_t BUILD_PARAM_INDEX_FOUR = 4;
57 constexpr int32_t BUILD_PARAM_INDEX_THIS_OBJ = 5;
58 } // namespace
59 
BuildNode(const JSCallbackInfo & info)60 void JSBaseNode::BuildNode(const JSCallbackInfo& info)
61 {
62     ACE_REUSE_DETECTION_SCOPED_TRACE("JSBaseNode:BuildNode");
63     auto builder = info[0];
64     CHECK_NULL_VOID(builder->IsFunction());
65     auto buildFunc = AceType::MakeRefPtr<JsFunction>(info.This(), JSRef<JSFunc>::Cast(builder));
66 
67     auto infoLen = info.Length();
68     JSRef<JSVal> param;
69     if (infoLen >= INFO_LENGTH_LIMIT && (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)
70         || (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE) && info[1]->IsObject()))) {
71         param = info[1];
72     }
73 
74     auto lazyBuilderFunc = [buildFunc, param, renderType = renderType_]() mutable {
75         NG::ViewStackProcessor::GetInstance()->SetIsBuilderNode(true);
76         NG::ViewStackProcessor::GetInstance()->SetIsExportTexture(renderType == NodeRenderType::RENDER_TYPE_TEXTURE);
77         if (!param->IsEmpty()) {
78             buildFunc->ExecuteJS(1, &param);
79         } else {
80             buildFunc->ExecuteJS();
81         }
82     };
83 
84     NG::ScopedViewStackProcessor builderViewStackProcessor;
85     lazyBuilderFunc();
86     auto parent = viewNode_ ? viewNode_->GetParent() : nullptr;
87     auto newNode = NG::ViewStackProcessor::GetInstance()->Finish();
88     realNode_ = newNode;
89     if (newNode) {
90         newNode->SetBuilderFunc(std::move(lazyBuilderFunc));
91     }
92 
93     if (newNode && (infoLen >= BUILD_PARAM_INDEX_TWO + 1)) {
94         auto updateTsNodeBuilder = info[BUILD_PARAM_INDEX_TWO];
95         EcmaVM* vm = info.GetVm();
96         auto updateTsFunc = AceType::MakeRefPtr<JsFunction>(info.This(), JSRef<JSFunc>::Cast(updateTsNodeBuilder));
97         auto updateNodeFunc = [updateTsFunc, vm](int32_t instanceId, RefPtr<NG::UINode>& node) mutable {
98             JSRef<JSVal> param[2];
99             param[0] = JSRef<JSVal>::Make(ToJSValue(instanceId));
100             param[1] = JSRef<JSVal>::Make(panda::NativePointerRef::New(vm, AceType::RawPtr(node)));
101             updateTsFunc->ExecuteJS(2, param);
102         };
103         newNode->SetUpdateNodeFunc(std::move(updateNodeFunc));
104     }
105 
106     bool isSupportLazyBuild = false;
107     if (infoLen >= BUILD_PARAM_INDEX_FOUR + 1) {
108         auto jsLazyBuildSupported = info[BUILD_PARAM_INDEX_FOUR];
109         if (jsLazyBuildSupported->IsBoolean()) {
110             isSupportLazyBuild = jsLazyBuildSupported->ToBoolean();
111         }
112     }
113 
114     // If the node is a UINode, amount it to a BuilderProxyNode if needProxy.
115     auto flag = AceType::InstanceOf<NG::FrameNode>(newNode);
116     auto isSupportExportTexture = newNode ? EXPORT_TEXTURE_SUPPORT_TYPES.count(newNode->GetTag()) > 0 : false;
117     if (!flag && newNode) {
118         auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
119         auto proxyNode = NG::FrameNode::GetOrCreateFrameNode(
120             "BuilderProxyNode", nodeId, []() { return AceType::MakeRefPtr<NG::StackPattern>(); });
121         auto stackLayoutAlgorithm = proxyNode->GetLayoutProperty<NG::LayoutProperty>();
122         stackLayoutAlgorithm->UpdateAlignment(Alignment::TOP_LEFT);
123         proxyNode->AddChild(newNode);
124         newNode = proxyNode;
125     }
126 
127     if (newNode && (infoLen >= BUILD_PARAM_INDEX_THREE + 1)) {
128         auto updateTsNodeConfig = info[BUILD_PARAM_INDEX_THREE];
129         EcmaVM* vm = info.GetVm();
130         auto updateTsConfig = AceType::MakeRefPtr<JsFunction>(info.This(), JSRef<JSFunc>::Cast(updateTsNodeConfig));
131         auto updateNodeConfig = [updateTsConfig, vm]() mutable {
132             updateTsConfig->ExecuteJS();
133         };
134         newNode->SetUpdateNodeConfig(std::move(updateNodeConfig));
135     }
136     if (parent) {
137         if (newNode) {
138             parent->ReplaceChild(viewNode_, newNode);
139             newNode->MarkNeedFrameFlushDirty(NG::PROPERTY_UPDATE_MEASURE);
140         } else {
141             parent->RemoveChild(viewNode_);
142             parent->MarkNeedFrameFlushDirty(NG::PROPERTY_UPDATE_MEASURE);
143         }
144     }
145     viewNode_ = newNode ? AceType::DynamicCast<NG::FrameNode>(newNode) : nullptr;
146     CHECK_NULL_VOID(viewNode_);
147     ProccessNode(isSupportExportTexture, isSupportLazyBuild);
148     UpdateEnd(info);
149     CHECK_NULL_VOID(viewNode_);
150 
151     JSRef<JSObject> thisObj = info[BUILD_PARAM_INDEX_THIS_OBJ];
152     auto updateInstance = thisObj->GetProperty("updateInstance");
153     if (!updateInstance->IsFunction()) {
154         return;
155     }
156     EcmaVM* vm = info.GetVm();
157     auto updateInstanceFunc = AceType::MakeRefPtr<JsFunction>(thisObj, JSRef<JSFunc>::Cast(updateInstance));
158     CHECK_NULL_VOID(updateInstanceFunc);
159     auto updateJSInstanceCallback = [updateInstanceFunc, vm](int32_t instanceId) {
160         auto uiContext = NG::UIContextHelper::GetUIContext(vm, instanceId);
161         auto jsVal = JSRef<JSVal>::Make(uiContext);
162         updateInstanceFunc->ExecuteJS(1, &jsVal);
163     };
164     viewNode_->RegisterUpdateJSInstanceCallback(updateJSInstanceCallback);
165 }
166 
ProccessNode(bool isSupportExportTexture,bool isSupportLazyBuild)167 void JSBaseNode::ProccessNode(bool isSupportExportTexture, bool isSupportLazyBuild)
168 {
169     CHECK_NULL_VOID(viewNode_);
170     CHECK_NULL_VOID(realNode_);
171     viewNode_->SetIsRootBuilderNode(true);
172     realNode_->SetJsBuilderNodeId(viewNode_->GetId());
173     if (isSupportExportTexture) {
174         viewNode_->CreateExportTextureInfoIfNeeded();
175         auto exportTextureInfo = viewNode_->GetExportTextureInfo();
176         CHECK_NULL_VOID(exportTextureInfo);
177         exportTextureInfo->SetSurfaceId(surfaceId_);
178         exportTextureInfo->SetCurrentRenderType(renderType_);
179     }
180     if (!isSupportLazyBuild) {
181         viewNode_->Build(nullptr);
182     }
183 }
184 
Create(const JSCallbackInfo & info)185 void JSBaseNode::Create(const JSCallbackInfo& info)
186 {
187     if (info.Length() >= 1 && !info[0]->IsFunction()) {
188         return;
189     }
190     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE) && info.Length() >= INFO_LENGTH_LIMIT
191         && !(info[1]->IsObject() || info[1]->IsUndefined() || info[1]->IsNull())) {
192         return;
193     }
194     BuildNode(info);
195     EcmaVM* vm = info.GetVm();
196     info.SetReturnValue(JSRef<JSVal>::Make(panda::NativePointerRef::New(vm, AceType::RawPtr(viewNode_))));
197 }
198 
ConstructorCallback(const JSCallbackInfo & info)199 void JSBaseNode::ConstructorCallback(const JSCallbackInfo& info)
200 {
201     std::string surfaceId;
202     NodeRenderType renderType = NodeRenderType::RENDER_TYPE_DISPLAY;
203     NG::OptionalSizeF selfIdealSize;
204     if (info.Length() > 0 && info[0]->IsObject()) {
205         auto renderOption = JSRef<JSObject>::Cast(info[0]);
206         auto size = renderOption->GetProperty("selfIdealSize");
207         if (size->IsObject()) {
208             auto sizeObj = JSRef<JSObject>::Cast(size);
209             auto width = sizeObj->GetProperty("width");
210             auto widthValue = width->IsNumber() ? width->ToNumber<float>() : 0.0f;
211             widthValue = LessNotEqual(widthValue, 0.0f) ? 0.0f : widthValue;
212             auto height = sizeObj->GetProperty("height");
213             auto heightValue = height->IsNumber() ? height->ToNumber<float>() : 0.0f;
214             heightValue = LessNotEqual(heightValue, 0.0f) ? 0.0f : heightValue;
215             selfIdealSize.SetWidth(PipelineBase::Vp2PxWithCurrentDensity(widthValue));
216             selfIdealSize.SetHeight(PipelineBase::Vp2PxWithCurrentDensity(heightValue));
217         }
218         auto type = renderOption->GetProperty("type");
219         if (type->IsNumber()) {
220             renderType = static_cast<NodeRenderType>(type->ToNumber<uint32_t>());
221         }
222         auto id = renderOption->GetProperty("surfaceId");
223         if (id->IsString()) {
224             surfaceId = id->ToString();
225         }
226     }
227     auto instance = AceType::MakeRefPtr<JSBaseNode>(selfIdealSize, renderType, surfaceId);
228     instance->IncRefCount();
229     info.SetReturnValue(AceType::RawPtr(instance));
230 }
231 
DestructorCallback(JSBaseNode * node)232 void JSBaseNode::DestructorCallback(JSBaseNode* node)
233 {
234     if (node != nullptr) {
235         node->DecRefCount();
236     }
237 }
238 
FinishUpdateFunc(const JSCallbackInfo & info)239 void JSBaseNode::FinishUpdateFunc(const JSCallbackInfo& info)
240 {
241     NG::ViewStackProcessor::GetInstance()->FlushRerenderTask();
242 }
243 
PostTouchEvent(const JSCallbackInfo & info)244 void JSBaseNode::PostTouchEvent(const JSCallbackInfo& info)
245 {
246     if (!viewNode_ || info.Length() < 1 || !info[0]->IsObject()) {
247         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostTouchEvent params invalid");
248         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
249         return;
250     }
251     TouchEvent touchEvent;
252     if (!InitTouchEvent(info, touchEvent, true)) {
253         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostTouchEvent params invalid");
254         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
255         return;
256     }
257     auto pipelineContext = NG::PipelineContext::GetCurrentContext();
258     if (!pipelineContext) {
259         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostTouchEvent pipelineContext is invalid");
260         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
261         return;
262     }
263     auto postEventManager = pipelineContext->GetPostEventManager();
264     if (!postEventManager) {
265         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostTouchEvent postEventManager is invalid");
266         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
267         return;
268     }
269     auto result = postEventManager->PostEvent(viewNode_, touchEvent);
270     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(result)));
271 }
272 
PostInputEvent(const JSCallbackInfo & info)273 void JSBaseNode::PostInputEvent(const JSCallbackInfo& info)
274 {
275     if (!realNode_ || info.Length() < 1 || !info[0]->IsObject()) {
276         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostInputEvent params invalid");
277         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
278         return;
279     }
280     auto pipelineContext = NG::PipelineContext::GetCurrentContext();
281     if (!pipelineContext) {
282         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostInputEvent pipelineContext is invalid");
283         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
284         return;
285     }
286     auto postEventManager = pipelineContext->GetPostEventManager();
287     if (!postEventManager) {
288         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostInputEvent postEventManager is invalid");
289         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
290         return;
291     }
292     auto obj = JSRef<JSObject>::Cast(info[0]);
293     if (obj->IsUndefined() || obj.IsEmpty()) {
294         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
295         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostInputEvent params is invalid");
296         return;
297     }
298     bool result = false;
299     auto touchesJsVal = obj->GetProperty("touches");
300     if (touchesJsVal->IsArray()) {
301         TouchEvent touchEvent;
302         if (!InitTouchEvent(info, touchEvent, false)) {
303             info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
304             return;
305         }
306         result = postEventManager->PostTouchEvent(realNode_, std::move(touchEvent));
307         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(result)));
308         return;
309     }
310     auto scrollStep = obj->GetProperty("scrollStep");
311     if (scrollStep->IsNumber()) {
312         AxisEvent axisEvent;
313         if (!InitAxisEvent(info, axisEvent)) {
314             info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
315             return;
316         }
317         result = postEventManager->PostAxisEvent(realNode_, std::move(axisEvent));
318         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(result)));
319         return;
320     }
321     MouseEvent mouseEvent;
322     if (!InitMouseEvent(info, mouseEvent)) {
323         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
324         return;
325     }
326     result = postEventManager->PostMouseEvent(realNode_, std::move(mouseEvent));
327     info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(result)));
328 }
329 
GetTouches(const JSCallbackInfo & info,TouchEvent & touchEvent)330 bool JSBaseNode::GetTouches(const JSCallbackInfo& info, TouchEvent& touchEvent)
331 {
332     if (info.Length() < 1 || !info[0]->IsObject()) {
333         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "TouchEvent params invalid");
334         return false;
335     }
336     auto obj = JSRef<JSObject>::Cast(info[0]);
337     if (obj->IsUndefined() || obj.IsEmpty()) {
338         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "TouchEvent params invalid");
339         return false;
340     }
341     auto touchesJsVal = obj->GetProperty("touches");
342     if (touchesJsVal->IsArray()) {
343         JSRef<JSArray> touchesArray = JSRef<JSArray>::Cast(touchesJsVal);
344         for (auto index = 0; index < static_cast<int32_t>(touchesArray->Length()); index++) {
345             JSRef<JSVal> item = touchesArray->GetValueAt(index);
346             if (!item->IsObject()) { continue; }
347             JSRef<JSObject> itemObj = JSRef<JSObject>::Cast(item);
348             TouchPoint point;
349             point.id = itemObj->GetPropertyValue<int32_t>("id", 0);
350             point.x = itemObj->GetPropertyValue<float>("x", 0.0f);
351             point.y = itemObj->GetPropertyValue<float>("y", 0.0f);
352             point.screenX = itemObj->GetPropertyValue<float>("screenX", 0.0f);
353             point.screenY = itemObj->GetPropertyValue<float>("screenY", 0.0f);
354             point.globalDisplayX = itemObj->GetPropertyValue<double>("globalDisplayX", 0.0);
355             point.globalDisplayY = itemObj->GetPropertyValue<double>("globalDisplayY", 0.0);
356             point.originalId = itemObj->GetPropertyValue<int32_t>("id", 0);
357             touchEvent.pointers.emplace_back(point);
358         }
359     }
360     auto changedTouchesJsVal = obj->GetProperty("changedTouches");
361     if (changedTouchesJsVal->IsArray()) {
362         JSRef<JSArray> changedTouchesArray = JSRef<JSArray>::Cast(changedTouchesJsVal);
363         if (static_cast<int32_t>(changedTouchesArray->Length()) <= 0) {
364             TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostTouchEvent event changedTouchesArray is invalid");
365             info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
366             return false;
367         }
368         JSRef<JSVal> item = changedTouchesArray->GetValueAt(0);
369         if (!item->IsObject()) {
370             TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostTouchEvent event changedTouchesArray item is not an object");
371             info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
372             return false;
373         }
374         JSRef<JSObject> itemObj = JSRef<JSObject>::Cast(item);
375         touchEvent.id = itemObj->GetPropertyValue<int32_t>("id", 0);
376         touchEvent.x = itemObj->GetPropertyValue<float>("x", 0.0f);
377         touchEvent.y = itemObj->GetPropertyValue<float>("y", 0.0f);
378         touchEvent.screenX = itemObj->GetPropertyValue<float>("screenX", 0.0f);
379         touchEvent.screenY = itemObj->GetPropertyValue<float>("screenY", 0.0f);
380         touchEvent.globalDisplayX = itemObj->GetPropertyValue<double>("globalDisplayX", 0.0);
381         touchEvent.globalDisplayY = itemObj->GetPropertyValue<double>("globalDisplayY", 0.0);
382         touchEvent.originalId = itemObj->GetPropertyValue<int32_t>("id", 0);
383     }
384     return true;
385 }
386 
387 // only postInputEvent call this function
GetChangedTouches(const JSCallbackInfo & info,TouchEvent & touchEvent)388 bool JSBaseNode::GetChangedTouches(const JSCallbackInfo& info, TouchEvent& touchEvent)
389 {
390     if (info.Length() < 1 || !info[0]->IsObject()) {
391         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "TouchEvent params invalid");
392         return false;
393     }
394     auto obj = JSRef<JSObject>::Cast(info[0]);
395     auto changedTouchesJsVal = obj->GetProperty("changedTouches");
396     if (!changedTouchesJsVal->IsArray() || changedTouchesJsVal->IsEmpty()) {
397         return false;
398     }
399     JSRef<JSArray> changedTouchesArray = JSRef<JSArray>::Cast(changedTouchesJsVal);
400     if (static_cast<int32_t>(changedTouchesArray->Length()) <= 0) {
401         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostInputEvent event changedTouchesArray is invalid");
402         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
403         return false;
404     }
405     JSRef<JSVal> item = changedTouchesArray->GetValueAt(0);
406     if (!item->IsObject()) {
407         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "PostInputEvent event changedTouchesArray item is not an object");
408         info.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(false)));
409         return false;
410     }
411     JSRef<JSObject> itemObj = JSRef<JSObject>::Cast(item);
412     touchEvent.id = itemObj->GetPropertyValue<int32_t>("id", 0);
413     touchEvent.x = itemObj->GetPropertyValue<float>("windowX", 0.0f);
414     touchEvent.y = itemObj->GetPropertyValue<float>("windowY", 0.0f);
415     touchEvent.screenX = itemObj->GetPropertyValue<float>("displayX", 0.0f);
416     touchEvent.screenY = itemObj->GetPropertyValue<float>("displayY", 0.0f);
417     touchEvent.originalId = itemObj->GetPropertyValue<int32_t>("id", 0);
418     touchEvent.width = itemObj->GetPropertyValue<float>("width", 0);
419     touchEvent.height = itemObj->GetPropertyValue<float>("height", 0);
420     touchEvent.globalDisplayX = itemObj->GetPropertyValue<double>("globalDisplayX", 0.0);
421     touchEvent.globalDisplayY = itemObj->GetPropertyValue<double>("globalDisplayY", 0.0);
422     auto pressedTimeJsVal = itemObj->GetProperty("pressedTime");
423     if (pressedTimeJsVal->IsNumber()) {
424         std::chrono::nanoseconds nanoseconds(static_cast<int64_t>(pressedTimeJsVal->ToNumber<double>()));
425         TimeStamp time(nanoseconds);
426         touchEvent.pressedTime = time;
427     }
428     auto handJsVal = itemObj->GetProperty("hand");
429     if (handJsVal->IsNumber()) {
430         touchEvent.operatingHand = handJsVal->ToNumber<int32_t>();
431     }
432     return true;
433 }
434 
GetInputTouches(const JSCallbackInfo & info,TouchEvent & touchEvent)435 bool JSBaseNode::GetInputTouches(const JSCallbackInfo& info, TouchEvent& touchEvent)
436 {
437     if (info.Length() < 1 || !info[0]->IsObject()) {
438         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "TouchEvent params invalid");
439         return false;
440     }
441     auto obj = JSRef<JSObject>::Cast(info[0]);
442     auto touchesJsVal = obj->GetProperty("touches");
443     if (!touchesJsVal->IsArray() || touchesJsVal->IsEmpty()) {
444         return false;
445     }
446     JSRef<JSArray> touchesArray = JSRef<JSArray>::Cast(touchesJsVal);
447     for (auto index = 0; index < static_cast<int32_t>(touchesArray->Length()); index++) {
448         JSRef<JSVal> item = touchesArray->GetValueAt(index);
449         if (!item->IsObject()) {
450             continue;
451         }
452         JSRef<JSObject> itemObj = JSRef<JSObject>::Cast(item);
453         TouchPoint point;
454         point.id = itemObj->GetPropertyValue<int32_t>("id", 0);
455         point.x = itemObj->GetPropertyValue<float>("windowX", 0.0f);
456         point.y = itemObj->GetPropertyValue<float>("windowY", 0.0f);
457         point.screenX = itemObj->GetPropertyValue<float>("displayX", 0.0f);
458         point.screenY = itemObj->GetPropertyValue<float>("displayY", 0.0f);
459         point.originalId = itemObj->GetPropertyValue<int32_t>("id", 0);
460         point.force = itemObj->GetPropertyValue<float>("pressure", 0);
461         point.width = itemObj->GetPropertyValue<float>("width", 0);
462         point.height = itemObj->GetPropertyValue<float>("height", 0);
463         point.operatingHand = itemObj->GetPropertyValue<int32_t>("hand", 0);
464         point.globalDisplayX = itemObj->GetPropertyValue<double>("globalDisplayX", 0.0);
465         point.globalDisplayY = itemObj->GetPropertyValue<double>("globalDisplayY", 0.0);
466         auto pressedTimeJsVal = itemObj->GetProperty("pressedTime");
467         if (pressedTimeJsVal->IsNumber()) {
468             std::chrono::nanoseconds nanoseconds(static_cast<int64_t>(pressedTimeJsVal->ToNumber<double>()));
469             TimeStamp time(nanoseconds);
470             point.downTime = time;
471         }
472         touchEvent.pointers.emplace_back(point);
473     }
474     return true;
475 }
476 
InitTouchEvent(const JSCallbackInfo & info,TouchEvent & touchEvent,bool isPostTouchEvent)477 bool JSBaseNode::InitTouchEvent(const JSCallbackInfo& info, TouchEvent& touchEvent, bool isPostTouchEvent)
478 {
479     if (info.Length() < 1 || !info[0]->IsObject()) {
480         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "TouchEvent params invalid");
481         return false;
482     }
483     auto obj = JSRef<JSObject>::Cast(info[0]);
484     if (obj->IsUndefined() || obj.IsEmpty()) {
485         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "TouchEvent params invalid");
486         return false;
487     }
488     auto typeJsVal = obj->GetProperty("type");
489     if (typeJsVal->IsNumber()) {
490         touchEvent.type = static_cast<TouchType>(typeJsVal->ToNumber<int32_t>());
491     }
492     auto sourceJsVal = obj->GetProperty("source");
493     if (sourceJsVal->IsNumber()) {
494         touchEvent.sourceType = static_cast<SourceType>((sourceJsVal->ToNumber<int32_t>()));
495     }
496     auto sourceToolJsVal = obj->GetProperty("sourceTool");
497     if (sourceToolJsVal->IsNumber()) {
498         touchEvent.sourceTool = static_cast<SourceTool>((sourceToolJsVal->ToNumber<int32_t>()));
499     }
500     auto pressureJsVal = obj->GetProperty("pressure");
501     if (pressureJsVal->IsNumber()) {
502         touchEvent.force = pressureJsVal->ToNumber<float>();
503     }
504     auto timestampJsVal = obj->GetProperty("timestamp");
505     if (timestampJsVal->IsNumber()) {
506         std::chrono::nanoseconds nanoseconds(static_cast<int64_t>(timestampJsVal->ToNumber<double>()));
507         TimeStamp time(nanoseconds);
508         touchEvent.time = time;
509     }
510     auto deviceIdJsVal = obj->GetProperty("deviceId");
511     if (deviceIdJsVal->IsNumber()) {
512         touchEvent.deviceId = deviceIdJsVal->ToNumber<int32_t>();
513     }
514     auto targetDisplayIdJsVal = obj->GetProperty("targetDisplayId");
515     if (targetDisplayIdJsVal->IsNumber()) {
516         touchEvent.targetDisplayId = targetDisplayIdJsVal->ToNumber<int32_t>();
517     }
518     ParamTouchEvent(info, touchEvent);
519     BaseEventInfo* baseEventInfo = obj->Unwrap<BaseEventInfo>();
520     if (baseEventInfo) {
521         touchEvent.SetPressedKeyCodes(baseEventInfo->GetPressedKeyCodes());
522     }
523     if (isPostTouchEvent) {
524         return GetTouches(info, touchEvent);
525     }
526     // postInputEvent: x = windowX, y = windowY, screenX = displayX, sreenY = displayY
527     if (!GetInputTouches(info, touchEvent)) {
528         return false;
529     }
530     return GetChangedTouches(info, touchEvent);
531 }
532 
ParamTouchEvent(const JSCallbackInfo & info,TouchEvent & touchEvent)533 bool JSBaseNode::ParamTouchEvent(const JSCallbackInfo& info, TouchEvent& touchEvent)
534 {
535     if (info.Length() < 1 || !info[0]->IsObject()) {
536         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "TouchEvent params invalid");
537         return false;
538     }
539     auto obj = JSRef<JSObject>::Cast(info[0]);
540     if (obj->IsUndefined() || obj.IsEmpty()) {
541         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "TouchEvent params invalid");
542         return false;
543     }
544     auto titleXJsVal = obj->GetProperty("tiltX");
545     if (titleXJsVal->IsNumber()) {
546         touchEvent.tiltX = titleXJsVal->ToNumber<float>();
547     }
548     auto titleYJsVal = obj->GetProperty("tiltY");
549     if (titleYJsVal->IsNumber()) {
550         touchEvent.tiltY = titleYJsVal->ToNumber<float>();
551     }
552     auto rollAngleJsVal = obj->GetProperty("rollAngle");
553     if (rollAngleJsVal->IsNumber()) {
554         touchEvent.rollAngle = rollAngleJsVal->ToNumber<float>();
555     }
556     return true;
557 }
558 
InitMouseEvent(const JSCallbackInfo & info,MouseEvent & mouseEvent)559 bool JSBaseNode::InitMouseEvent(const JSCallbackInfo& info, MouseEvent& mouseEvent)
560 {
561     if (info.Length() < 1 || !info[0]->IsObject()) {
562         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "MouseEvent params invalid");
563         return false;
564     }
565     auto obj = JSRef<JSObject>::Cast(info[0]);
566     if (obj->IsUndefined() || obj.IsEmpty()) {
567         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "MouseEvent params invalid");
568         return false;
569     }
570     auto sourceJsVal = obj->GetProperty("source");
571     if (sourceJsVal->IsNumber()) {
572         mouseEvent.sourceType = static_cast<SourceType>((sourceJsVal->ToNumber<int32_t>()));
573     }
574     auto sourceToolJsVal = obj->GetProperty("sourceTool");
575     if (sourceToolJsVal->IsNumber()) {
576         mouseEvent.sourceTool = static_cast<SourceTool>((sourceToolJsVal->ToNumber<int32_t>()));
577     }
578     auto timestampJsVal = obj->GetProperty("timestamp");
579     if (timestampJsVal->IsNumber()) {
580         std::chrono::nanoseconds nanoseconds(static_cast<int64_t>(timestampJsVal->ToNumber<double>()));
581         TimeStamp time(nanoseconds);
582         mouseEvent.time = time;
583     }
584     auto deviceIdJsVal = obj->GetProperty("deviceId");
585     if (deviceIdJsVal->IsNumber()) {
586         mouseEvent.deviceId = deviceIdJsVal->ToNumber<int32_t>();
587     }
588     auto targetDisplayIdJsVal = obj->GetProperty("targetDisplayId");
589     if (targetDisplayIdJsVal->IsNumber()) {
590         mouseEvent.targetDisplayId = targetDisplayIdJsVal->ToNumber<int32_t>();
591     }
592     auto xJsVal = obj->GetProperty("windowX");
593     if (xJsVal->IsNumber()) {
594         mouseEvent.x = xJsVal->ToNumber<float>();
595     }
596     auto yJsVal = obj->GetProperty("windowY");
597     if (yJsVal->IsNumber()) {
598         mouseEvent.y = yJsVal->ToNumber<float>();
599     }
600     auto globalDisplayXJsVal = obj->GetProperty("globalDisplayX");
601     if (globalDisplayXJsVal->IsNumber()) {
602         mouseEvent.globalDisplayX = globalDisplayXJsVal->ToNumber<double>();
603     }
604     auto globalDisplayYJsVal = obj->GetProperty("globalDisplayY");
605     if (globalDisplayYJsVal->IsNumber()) {
606         mouseEvent.globalDisplayY = globalDisplayYJsVal->ToNumber<double>();
607     }
608     auto buttonJsVal = obj->GetProperty("button");
609     if (buttonJsVal->IsNumber()) {
610         mouseEvent.button = static_cast<MouseButton>(buttonJsVal->ToNumber<int32_t>());
611     }
612     auto actionJsVal = obj->GetProperty("action");
613     if (actionJsVal->IsNumber()) {
614         mouseEvent.action = static_cast<MouseAction>(actionJsVal->ToNumber<int32_t>());
615     }
616     if (!ParamMouseEvent(info, mouseEvent)) {
617         return false;
618     }
619     return true;
620 }
621 
ParamMouseEvent(const JSCallbackInfo & info,MouseEvent & mouseEvent)622 bool JSBaseNode::ParamMouseEvent(const JSCallbackInfo& info, MouseEvent& mouseEvent)
623 {
624     if (info.Length() < 1 || !info[0]->IsObject()) {
625         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "MouseEevent params invalid");
626         return false;
627     }
628     auto obj = JSRef<JSObject>::Cast(info[0]);
629     if (obj->IsUndefined() || obj.IsEmpty()) {
630         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "MouseEvent params invalid");
631         return false;
632     }
633     auto screenXJsVal = obj->GetProperty("displayX");
634     if (screenXJsVal->IsNumber()) {
635         mouseEvent.screenX = screenXJsVal->ToNumber<float>();
636     }
637     auto screenYJsVal = obj->GetProperty("displayY");
638     if (screenYJsVal->IsNumber()) {
639         mouseEvent.screenY = screenYJsVal->ToNumber<float>();
640     }
641     auto rawDeltaXJsVal = obj->GetProperty("rawDeltaX");
642     if (rawDeltaXJsVal->IsNumber()) {
643         mouseEvent.rawDeltaX = rawDeltaXJsVal->ToNumber<float>();
644     }
645     auto rawDeltaYJsVal = obj->GetProperty("rawDeltaY");
646     if (rawDeltaYJsVal->IsNumber()) {
647         mouseEvent.rawDeltaY = rawDeltaYJsVal->ToNumber<float>();
648     }
649     BaseEventInfo* baseEventInfo = obj->Unwrap<BaseEventInfo>();
650     if (baseEventInfo) {
651         mouseEvent.pressedKeyCodes_ = baseEventInfo->GetPressedKeyCodes();
652     }
653     auto pressedButtonsJsVal = obj->GetProperty("pressedButtons");
654     if (pressedButtonsJsVal->IsArray()) {
655         JSRef<JSArray> pressedButtonsArray = JSRef<JSArray>::Cast(pressedButtonsJsVal);
656         for (auto index = 0; index < static_cast<int32_t>(pressedButtonsArray->Length()); index++) {
657             JSRef<JSVal> item = pressedButtonsArray->GetValueAt(index);
658             if (!item->IsNumber()) {
659                 continue;
660             }
661             auto pressedButton = item->ToNumber<int32_t>();
662             mouseEvent.pressedButtonsArray.push_back(static_cast<MouseButton>(pressedButton));
663         }
664     }
665     return true;
666 }
667 
InitAxisEvent(const JSCallbackInfo & info,AxisEvent & axisEvent)668 bool JSBaseNode::InitAxisEvent(const JSCallbackInfo& info, AxisEvent& axisEvent)
669 {
670     if (info.Length() < 1 || !info[0]->IsObject()) {
671         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "AxisEvent params invalid");
672         return false;
673     }
674     auto obj = JSRef<JSObject>::Cast(info[0]);
675     if (obj->IsUndefined() || obj.IsEmpty()) {
676         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "AxisEvent params invalid");
677         return false;
678     }
679     auto sourceJsVal = obj->GetProperty("source");
680     if (sourceJsVal->IsNumber()) {
681         axisEvent.sourceType = static_cast<SourceType>((sourceJsVal->ToNumber<int32_t>()));
682     }
683     auto sourceToolJsVal = obj->GetProperty("sourceTool");
684     if (sourceToolJsVal->IsNumber()) {
685         axisEvent.sourceTool = static_cast<SourceTool>((sourceToolJsVal->ToNumber<int32_t>()));
686     }
687     auto timestampJsVal = obj->GetProperty("timestamp");
688     if (timestampJsVal->IsNumber()) {
689         std::chrono::nanoseconds nanoseconds(static_cast<int64_t>(timestampJsVal->ToNumber<double>()));
690         TimeStamp time(nanoseconds);
691         axisEvent.time = time;
692     }
693     auto deviceIdJsVal = obj->GetProperty("deviceId");
694     if (deviceIdJsVal->IsNumber()) {
695         axisEvent.deviceId = deviceIdJsVal->ToNumber<int32_t>();
696     }
697     auto targetDisplayIdJsVal = obj->GetProperty("targetDisplayId");
698     if (targetDisplayIdJsVal->IsNumber()) {
699         axisEvent.targetDisplayId = targetDisplayIdJsVal->ToNumber<int32_t>();
700     }
701     auto actionJsVal = obj->GetProperty("action");
702     if (actionJsVal->IsNumber()) {
703         axisEvent.action = static_cast<AxisAction>(actionJsVal->ToNumber<int32_t>());
704     }
705     auto xJsVal = obj->GetProperty("windowX");
706     if (xJsVal->IsNumber()) {
707         axisEvent.x = xJsVal->ToNumber<float>();
708     }
709     auto yJsVal = obj->GetProperty("windowY");
710     if (yJsVal->IsNumber()) {
711         axisEvent.y = yJsVal->ToNumber<float>();
712     }
713     auto screenXJsVal = obj->GetProperty("displayX");
714     if (screenXJsVal->IsNumber()) {
715         axisEvent.screenX = screenXJsVal->ToNumber<float>();
716     }
717     auto screenYJsVal = obj->GetProperty("displayY");
718     if (screenYJsVal->IsNumber()) {
719         axisEvent.screenY = screenYJsVal->ToNumber<float>();
720     }
721     auto globalDisplayXJsVal = obj->GetProperty("globalDisplayX");
722     if (globalDisplayXJsVal->IsNumber()) {
723         axisEvent.globalDisplayX = globalDisplayXJsVal->ToNumber<double>();
724     }
725     auto globalDisplayYJsVal = obj->GetProperty("globalDisplayY");
726     if (globalDisplayYJsVal->IsNumber()) {
727         axisEvent.globalDisplayY = globalDisplayYJsVal->ToNumber<double>();
728     }
729 
730     AxisInfo* axisInfo = obj->Unwrap<AxisInfo>();
731     auto pinchAxisScale = obj->GetProperty("pinchAxisScale");
732     if (pinchAxisScale->IsNumber()) {
733         axisEvent.pinchAxisScale = pinchAxisScale->ToNumber<float>();
734     } else if (axisInfo) {
735         axisEvent.pinchAxisScale = axisInfo->GetPinchAxisScale();
736     }
737     auto rotateAxisAngle = obj->GetProperty("rotateAxisAngle");
738     if (rotateAxisAngle->IsNumber()) {
739         axisEvent.rotateAxisAngle = rotateAxisAngle->ToNumber<float>();
740     } else if (axisInfo) {
741         axisEvent.rotateAxisAngle = axisInfo->GetRotateAxisAngle();
742     }
743     if (!ParamAxisEvent(info, axisEvent)) {
744         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "AxisEvent params invalid");
745         return false;
746     }
747     return true;
748 }
749 
ParamAxisEvent(const JSCallbackInfo & info,AxisEvent & axisEvent)750 bool JSBaseNode::ParamAxisEvent(const JSCallbackInfo& info, AxisEvent& axisEvent)
751 {
752     if (info.Length() < 1 || !info[0]->IsObject()) {
753         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "AxisEvent params invalid");
754         return false;
755     }
756     auto obj = JSRef<JSObject>::Cast(info[0]);
757     if (obj->IsUndefined() || obj.IsEmpty()) {
758         TAG_LOGW(AceLogTag::ACE_INPUTKEYFLOW, "AxisEvent params invalid");
759         return false;
760     }
761     auto scrollStepJsVal = obj->GetProperty("scrollStep");
762     if (scrollStepJsVal->IsNumber()) {
763         axisEvent.scrollStep = scrollStepJsVal->ToNumber<int32_t>();
764     }
765     auto horizontalAxisJsVal = obj->GetProperty("axisHorizontal");
766     if (horizontalAxisJsVal->IsNumber()) {
767         axisEvent.horizontalAxis = horizontalAxisJsVal->ToNumber<float>();
768     }
769     auto verticalAxisJsVal = obj->GetProperty("axisVertical");
770     if (verticalAxisJsVal->IsNumber()) {
771         axisEvent.verticalAxis = verticalAxisJsVal->ToNumber<float>();
772     }
773     BaseEventInfo* baseEventInfo = obj->Unwrap<BaseEventInfo>();
774     if (baseEventInfo) {
775         axisEvent.pressedCodes = baseEventInfo->GetPressedKeyCodes();
776     }
777     return true;
778 }
779 
UpdateStart(const JSCallbackInfo & info)780 void JSBaseNode::UpdateStart(const JSCallbackInfo& info)
781 {
782     scopedViewStackProcessor_ = std::make_unique<NG::ScopedViewStackProcessor>();
783 }
784 
UpdateEnd(const JSCallbackInfo & info)785 void JSBaseNode::UpdateEnd(const JSCallbackInfo& info)
786 {
787     scopedViewStackProcessor_ = nullptr;
788     CHECK_NULL_VOID(viewNode_);
789     if (size_.IsValid()) {
790         viewNode_->SetParentLayoutConstraint(size_.ConvertToSizeT());
791     }
792 }
793 
OnReuseWithBindThis(const JSCallbackInfo & info)794 void JSBaseNode::OnReuseWithBindThis(const JSCallbackInfo& info)
795 {
796     CHECK_NULL_VOID(realNode_);
797     std::queue<RefPtr<NG::UINode>> elements;
798     elements.push(realNode_);
799     void* data = static_cast<void*>(info.GetJsiRuntimeCallInfo());
800     while (!elements.empty()) {
801         auto currentNode = elements.front();
802         elements.pop();
803         if (!currentNode) {
804             continue;
805         }
806         if (AceType::InstanceOf<NG::CustomNodeBase>(currentNode)) {
807             auto customNode = AceType::DynamicCast<NG::CustomNodeBase>(currentNode);
808             customNode->FireOnReuseFunc(data);
809         } else {
810             for (const auto& child : currentNode->GetChildren()) {
811                 elements.push(child);
812             }
813         }
814     }
815 }
816 
OnRecycleWithBindThis(const JSCallbackInfo & info)817 void JSBaseNode::OnRecycleWithBindThis(const JSCallbackInfo& info)
818 {
819     CHECK_NULL_VOID(realNode_);
820     std::queue<RefPtr<NG::UINode>> elements;
821     elements.push(realNode_);
822     while (!elements.empty()) {
823         auto currentNode = elements.front();
824         elements.pop();
825         if (!currentNode) {
826             continue;
827         }
828         if (AceType::InstanceOf<NG::CustomNodeBase>(currentNode)) {
829             auto customNode = AceType::DynamicCast<NG::CustomNodeBase>(currentNode);
830             customNode->FireOnRecycleFunc();
831         } else {
832             for (const auto& child : currentNode->GetChildren()) {
833                 elements.push(child);
834             }
835         }
836     }
837 }
838 
JSBind(BindingTarget globalObj)839 void JSBaseNode::JSBind(BindingTarget globalObj)
840 {
841     JSClass<JSBaseNode>::Declare("__JSBaseNode__");
842 
843     JSClass<JSBaseNode>::CustomMethod("create", &JSBaseNode::Create);
844     JSClass<JSBaseNode>::CustomMethod("finishUpdateFunc", &JSBaseNode::FinishUpdateFunc);
845     JSClass<JSBaseNode>::CustomMethod("postTouchEvent", &JSBaseNode::PostTouchEvent);
846     JSClass<JSBaseNode>::CustomMethod("disposeNode", &JSBaseNode::Dispose);
847     JSClass<JSBaseNode>::CustomMethod("updateStart", &JSBaseNode::UpdateStart);
848     JSClass<JSBaseNode>::CustomMethod("updateEnd", &JSBaseNode::UpdateEnd);
849     JSClass<JSBaseNode>::CustomMethod("onReuseWithBindObject", &JSBaseNode::OnReuseWithBindThis);
850     JSClass<JSBaseNode>::CustomMethod("onRecycleWithBindObject", &JSBaseNode::OnRecycleWithBindThis);
851     JSClass<JSBaseNode>::CustomMethod("postInputEvent", &JSBaseNode::PostInputEvent);
852 
853     JSClass<JSBaseNode>::Bind(globalObj, JSBaseNode::ConstructorCallback, JSBaseNode::DestructorCallback);
854 }
855 } // namespace OHOS::Ace::Framework
856