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, ¶m);
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