1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "frameworks/bridge/declarative_frontend/engine/functions/js_gesture_judge_function.h"
17
18 #include "base/memory/ace_type.h"
19 #include "base/utils/utils.h"
20 #include "bridge/declarative_frontend/engine/functions/js_should_built_in_recognizer_parallel_with_function.h"
21 #include "core/components/common/layout/constants.h"
22 #include "core/components_ng/gestures/base_gesture_event.h"
23 #include "frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_utils.h"
24
25 namespace OHOS::Ace::Framework {
26 constexpr int32_t PARAM_COUNT_THREE = 3;
27 constexpr int32_t PARAM_COUNT_FOUR = 4;
28
Execute(const RefPtr<NG::GestureInfo> & gestureInfo,const std::shared_ptr<BaseGestureEvent> & info)29 GestureJudgeResult JsGestureJudgeFunction::Execute(
30 const RefPtr<NG::GestureInfo>& gestureInfo, const std::shared_ptr<BaseGestureEvent>& info)
31 {
32 JSRef<JSObject> gestureInfoObj = JSRef<JSObject>::New();
33 CHECK_NULL_RETURN(gestureInfo, GestureJudgeResult::CONTINUE);
34 CHECK_NULL_RETURN(info, GestureJudgeResult::CONTINUE);
35 if (gestureInfo->GetTag().has_value()) {
36 gestureInfoObj->SetProperty<std::string>("tag", gestureInfo->GetTag().value());
37 }
38 gestureInfoObj->SetProperty<int32_t>("type", static_cast<int32_t>(gestureInfo->GetType()));
39 gestureInfoObj->SetProperty<bool>("isSystemGesture", gestureInfo->IsSystemGesture());
40 gestureInfoObj->SetProperty<int32_t>("targetDisplayId", info->GetTargetDisplayId());
41 auto obj = CreateGestureEventObject(info, gestureInfo->GetType());
42 int32_t paramCount = 2;
43 JSRef<JSVal> params[paramCount];
44 params[0] = gestureInfoObj;
45 params[1] = obj;
46 auto jsValue = JsFunction::ExecuteJS(paramCount, params);
47 auto returnValue = GestureJudgeResult::CONTINUE;
48 if (jsValue->IsNumber()) {
49 returnValue = static_cast<GestureJudgeResult>(jsValue->ToNumber<int32_t>());
50 }
51 return returnValue;
52 }
53
Execute(const std::shared_ptr<BaseGestureEvent> & info,const RefPtr<NG::NGGestureRecognizer> & current,const std::list<RefPtr<NG::NGGestureRecognizer>> & others)54 GestureJudgeResult JsGestureJudgeFunction::Execute(const std::shared_ptr<BaseGestureEvent>& info,
55 const RefPtr<NG::NGGestureRecognizer>& current, const std::list<RefPtr<NG::NGGestureRecognizer>>& others)
56 {
57 CHECK_NULL_RETURN(info, GestureJudgeResult::CONTINUE);
58 auto gestureInfo = current->GetGestureInfo();
59 CHECK_NULL_RETURN(gestureInfo, GestureJudgeResult::CONTINUE);
60 auto obj = CreateGestureEventObject(info, gestureInfo->GetRecognizerType());
61 JSRef<JSVal> params[PARAM_COUNT_FOUR];
62 params[0] = obj;
63 auto currentObj = JsShouldBuiltInRecognizerParallelWithFunction::CreateRecognizerObject(current);
64 params[1] = currentObj;
65 JSRef<JSArray> othersArr = JSRef<JSArray>::New();
66 uint32_t othersIdx = 0;
67 for (const auto& item : others) {
68 auto othersObj = JsShouldBuiltInRecognizerParallelWithFunction::CreateRecognizerObject(item);
69 othersArr->SetValueAt(othersIdx++, othersObj);
70 }
71
72 auto touchRecognizerMap = CreateTouchRecognizerMap(info, current);
73 JSRef<JSArray> touchRecognizers = JSRef<JSArray>::New();
74 uint32_t touchRecognizersIdx = 0;
75 for (auto& [item, fingerIds] : touchRecognizerMap) {
76 JSRef<JSObject> recognizerObj = JSClass<JSTouchRecognizer>::NewInstance();
77 auto jsRecognizer = Referenced::Claim(recognizerObj->Unwrap<JSTouchRecognizer>());
78 if (jsRecognizer) {
79 jsRecognizer->SetTouchData(item, fingerIds);
80 }
81 touchRecognizers->SetValueAt(touchRecognizersIdx++, recognizerObj);
82 }
83 params[2] = othersArr;
84 params[PARAM_COUNT_THREE] = touchRecognizers;
85 auto jsValue = JsFunction::ExecuteJS(PARAM_COUNT_FOUR, params);
86 auto returnValue = GestureJudgeResult::CONTINUE;
87 if (jsValue->IsNumber()) {
88 returnValue = static_cast<GestureJudgeResult>(jsValue->ToNumber<int32_t>());
89 }
90 return returnValue;
91 }
92
CreateTouchRecognizerMap(const std::shared_ptr<BaseGestureEvent> & info,const RefPtr<NG::NGGestureRecognizer> & current)93 TouchRecognizerMap JsGestureJudgeFunction::CreateTouchRecognizerMap(
94 const std::shared_ptr<BaseGestureEvent>& info, const RefPtr<NG::NGGestureRecognizer>& current)
95 {
96 TouchRecognizerMap touchRecognizerMap;
97 auto frameNode = current->GetAttachedNode().Upgrade();
98 CHECK_NULL_RETURN(frameNode, touchRecognizerMap);
99 auto pipeline = frameNode->GetContext();
100 CHECK_NULL_RETURN(pipeline, touchRecognizerMap);
101 auto eventManager = pipeline->GetEventManager();
102 CHECK_NULL_RETURN(eventManager, touchRecognizerMap);
103 auto& touchTestResult = eventManager->touchTestResults_;
104 const auto& fingerList = info->GetFingerList();
105 for (const auto& finger : fingerList) {
106 auto& touchTargetList = touchTestResult[finger.fingerId_];
107 CollectTouchEventTarget(touchRecognizerMap, touchTargetList, AceType::RawPtr(frameNode), finger.fingerId_);
108 }
109 return touchRecognizerMap;
110 }
111
CollectTouchEventTarget(TouchRecognizerMap & dict,std::list<RefPtr<TouchEventTarget>> & targets,NG::FrameNode * frameNode,int32_t fingerId)112 void JsGestureJudgeFunction::CollectTouchEventTarget(
113 TouchRecognizerMap& dict, std::list<RefPtr<TouchEventTarget>>& targets, NG::FrameNode* frameNode, int32_t fingerId)
114 {
115 for (auto& target : targets) {
116 if (AceType::DynamicCast<NG::NGGestureRecognizer>(target)) {
117 continue;
118 }
119 auto weakTarget = WeakPtr<TouchEventTarget>(target);
120 if (dict.find(weakTarget) != dict.end() && dict[weakTarget].count(fingerId) > 0) {
121 continue;
122 }
123 auto targetNode = target->GetAttachedNode().Upgrade();
124 if (targetNode && targetNode == frameNode) {
125 dict[weakTarget].insert(fingerId);
126 return;
127 }
128 while (targetNode) {
129 if (targetNode == frameNode) {
130 dict[weakTarget].insert(fingerId);
131 break;
132 }
133 targetNode = targetNode->GetParentFrameNode();
134 }
135 }
136 }
137
CreateFingerInfo(const FingerInfo & fingerInfo)138 JSRef<JSObject> JsGestureJudgeFunction::CreateFingerInfo(const FingerInfo& fingerInfo)
139 {
140 JSRef<JSObject> fingerInfoObj = JSRef<JSObject>::New();
141 const OHOS::Ace::Offset& globalLocation = fingerInfo.globalLocation_;
142 const OHOS::Ace::Offset& localLocation = fingerInfo.localLocation_;
143 const OHOS::Ace::Offset& screenLocation = fingerInfo.screenLocation_;
144 const OHOS::Ace::Offset& globalDisplayLocation = fingerInfo.globalDisplayLocation_;
145 fingerInfoObj->SetProperty<int32_t>("id", fingerInfo.fingerId_);
146 fingerInfoObj->SetProperty<int32_t>("hand", fingerInfo.operatingHand_);
147 fingerInfoObj->SetProperty<double>("globalX", PipelineBase::Px2VpWithCurrentDensity(globalLocation.GetX()));
148 fingerInfoObj->SetProperty<double>("globalY", PipelineBase::Px2VpWithCurrentDensity(globalLocation.GetY()));
149 fingerInfoObj->SetProperty<double>("localX", PipelineBase::Px2VpWithCurrentDensity(localLocation.GetX()));
150 fingerInfoObj->SetProperty<double>("localY", PipelineBase::Px2VpWithCurrentDensity(localLocation.GetY()));
151 fingerInfoObj->SetProperty<double>("displayX", PipelineBase::Px2VpWithCurrentDensity(screenLocation.GetX()));
152 fingerInfoObj->SetProperty<double>("displayY", PipelineBase::Px2VpWithCurrentDensity(screenLocation.GetY()));
153 fingerInfoObj->SetProperty<double>(
154 "globalDisplayX", PipelineBase::Px2VpWithCurrentDensity(globalDisplayLocation.GetX()));
155 fingerInfoObj->SetProperty<double>(
156 "globalDisplayY", PipelineBase::Px2VpWithCurrentDensity(globalDisplayLocation.GetY()));
157 return fingerInfoObj;
158 }
159
CreateEventTargetObject(const std::shared_ptr<BaseGestureEvent> & info)160 JSRef<JSObject> JsGestureJudgeFunction::CreateEventTargetObject(const std::shared_ptr<BaseGestureEvent>& info)
161 {
162 JSRef<JSObjTemplate> objectTemplate = JSRef<JSObjTemplate>::New();
163 JSRef<JSObject> target = objectTemplate->NewInstance();
164 JSRef<JSObject> area = objectTemplate->NewInstance();
165 JSRef<JSObject> offset = objectTemplate->NewInstance();
166 JSRef<JSObject> globalOffset = objectTemplate->NewInstance();
167 const auto& localOffset = info->GetTarget().area.GetOffset();
168 const auto& origin = info->GetTarget().origin;
169 offset->SetProperty<double>("x", localOffset.GetX().ConvertToVp());
170 offset->SetProperty<double>("y", localOffset.GetY().ConvertToVp());
171 globalOffset->SetProperty<double>("x", (origin.GetX().ConvertToVp() + localOffset.GetX().ConvertToVp()));
172 globalOffset->SetProperty<double>("y", (origin.GetY().ConvertToVp() + localOffset.GetY().ConvertToVp()));
173 area->SetPropertyObject("position", offset);
174 area->SetPropertyObject("globalPosition", globalOffset);
175 area->SetProperty<double>("width", info->GetTarget().area.GetWidth().ConvertToVp());
176 area->SetProperty<double>("height", info->GetTarget().area.GetHeight().ConvertToVp());
177 target->SetPropertyObject("area", area);
178 if (!info->GetTarget().id.empty()) {
179 target->SetProperty<const char*>("id", info->GetTarget().id.c_str());
180 } else {
181 target->SetPropertyObject("id", JsiValue::Undefined());
182 }
183 return target;
184 }
185
ParsePanGestureEvent(JSRef<JSObject> & obj,const std::shared_ptr<BaseGestureEvent> & info)186 void JsGestureJudgeFunction::ParsePanGestureEvent(JSRef<JSObject>& obj, const std::shared_ptr<BaseGestureEvent>& info)
187 {
188 auto panGestureEvent = TypeInfoHelper::DynamicCast<PanGestureEvent>(info.get());
189 if (panGestureEvent) {
190 obj->SetProperty<double>(
191 "offsetX", PipelineBase::Px2VpWithCurrentDensity(panGestureEvent->GetOffsetX()));
192 obj->SetProperty<double>(
193 "offsetY", PipelineBase::Px2VpWithCurrentDensity(panGestureEvent->GetOffsetY()));
194 obj->SetProperty<double>(
195 "velocityX", PipelineBase::Px2VpWithCurrentDensity(panGestureEvent->GetVelocity().GetVelocityX()));
196 obj->SetProperty<double>(
197 "velocityY", PipelineBase::Px2VpWithCurrentDensity(panGestureEvent->GetVelocity().GetVelocityY()));
198 obj->SetProperty<double>("velocity",
199 PipelineBase::Px2VpWithCurrentDensity(panGestureEvent->GetVelocity().GetVelocityValue()));
200 }
201 }
202
SetUniqueAttributes(JSRef<JSObject> & obj,GestureTypeName typeName,const std::shared_ptr<BaseGestureEvent> & info)203 void JsGestureJudgeFunction::SetUniqueAttributes(
204 JSRef<JSObject>& obj, GestureTypeName typeName, const std::shared_ptr<BaseGestureEvent>& info)
205 {
206 switch (typeName) {
207 case OHOS::Ace::GestureTypeName::LONG_PRESS_GESTURE: {
208 auto longPressGestureEvent = TypeInfoHelper::DynamicCast<LongPressGestureEvent>(info.get());
209 if (longPressGestureEvent) {
210 obj->SetProperty<bool>("repeat", longPressGestureEvent->GetRepeat());
211 }
212 break;
213 }
214 case OHOS::Ace::GestureTypeName::PAN_GESTURE: {
215 ParsePanGestureEvent(obj, info);
216 break;
217 }
218 case OHOS::Ace::GestureTypeName::PINCH_GESTURE: {
219 auto pinchGestureEvent = TypeInfoHelper::DynamicCast<PinchGestureEvent>(info.get());
220 if (pinchGestureEvent) {
221 obj->SetProperty<double>("scale", pinchGestureEvent->GetScale());
222 obj->SetProperty<double>(
223 "pinchCenterX", PipelineBase::Px2VpWithCurrentDensity(pinchGestureEvent->GetPinchCenter().GetX()));
224 obj->SetProperty<double>(
225 "pinchCenterY", PipelineBase::Px2VpWithCurrentDensity(pinchGestureEvent->GetPinchCenter().GetY()));
226 }
227 break;
228 }
229 case OHOS::Ace::GestureTypeName::ROTATION_GESTURE: {
230 auto rotationGestureEvent = TypeInfoHelper::DynamicCast<RotationGestureEvent>(info.get());
231 if (rotationGestureEvent) {
232 obj->SetProperty<double>("angle", rotationGestureEvent->GetAngle());
233 }
234 break;
235 }
236 case OHOS::Ace::GestureTypeName::SWIPE_GESTURE: {
237 auto swipeGestureEvent = TypeInfoHelper::DynamicCast<SwipeGestureEvent>(info.get());
238 if (swipeGestureEvent) {
239 obj->SetProperty<double>("angle", swipeGestureEvent->GetAngle());
240 obj->SetProperty<double>("speed", swipeGestureEvent->GetSpeed());
241 }
242 break;
243 }
244 case OHOS::Ace::GestureTypeName::TAP_GESTURE: {
245 auto tapGestureEvent = TypeInfoHelper::DynamicCast<TapGestureEvent>(info.get());
246 if (tapGestureEvent && !tapGestureEvent->GetFingerList().empty()) {
247 obj->SetPropertyObject("tapLocation", GetTapLocation(tapGestureEvent->GetFingerList().back()));
248 }
249 break;
250 }
251 default:
252 break;
253 }
254 }
255
CreateGestureEventObject(const std::shared_ptr<BaseGestureEvent> & info,GestureTypeName typeName)256 JSRef<JSObject> JsGestureJudgeFunction::CreateGestureEventObject(
257 const std::shared_ptr<BaseGestureEvent>& info, GestureTypeName typeName)
258 {
259 JSRef<JSObjTemplate> objTemp = JSRef<JSObjTemplate>::New();
260 objTemp->SetInternalFieldCount(1);
261 JSRef<JSObject> obj = objTemp->NewInstance();
262 SetUniqueAttributes(obj, typeName, info);
263 obj->SetProperty<double>("timestamp", info->GetTimeStamp().time_since_epoch().count());
264 obj->SetProperty<double>("source", static_cast<int32_t>(info->GetSourceDevice()));
265 obj->SetProperty<double>("pressure", info->GetForce());
266 obj->SetProperty<double>("tiltX", info->GetTiltX().value_or(0.0f));
267 obj->SetProperty<double>("tiltY", info->GetTiltY().value_or(0.0f));
268 obj->SetProperty<double>("rollAngle", info->GetRollAngle().value_or(0.0f));
269 obj->SetProperty<double>("sourceTool", static_cast<int32_t>(info->GetSourceTool()));
270 obj->SetProperty<double>("deviceId", static_cast<int32_t>(info->GetDeviceId()));
271 obj->SetProperty<int32_t>("targetDisplayId", info->GetTargetDisplayId());
272 obj->SetProperty<float>("axisVertical", info->GetVerticalAxis());
273 obj->SetProperty<float>("axisHorizontal", info->GetHorizontalAxis());
274 obj->SetPropertyObject(
275 "getModifierKeyState", JSRef<JSFunc>::New<FunctionCallback>(NG::ArkTSUtils::JsGetModifierKeyState));
276
277 JSRef<JSArray> fingerArr = JSRef<JSArray>::New();
278 const std::list<FingerInfo>& fingerList = info->GetFingerList();
279 std::list<FingerInfo> notTouchFingerList;
280 int32_t maxFingerId = -1;
281 for (const FingerInfo& fingerInfo : fingerList) {
282 JSRef<JSObject> element = CreateFingerInfo(fingerInfo);
283 if (fingerInfo.sourceType_ == SourceType::TOUCH && fingerInfo.sourceTool_ == SourceTool::FINGER) {
284 fingerArr->SetValueAt(fingerInfo.fingerId_, element);
285 if (fingerInfo.fingerId_ > maxFingerId) {
286 maxFingerId = fingerInfo.fingerId_;
287 }
288 } else {
289 notTouchFingerList.emplace_back(fingerInfo);
290 }
291 }
292 auto idx = maxFingerId + 1;
293 for (const FingerInfo& fingerInfo : notTouchFingerList) {
294 JSRef<JSObject> element = CreateFingerInfo(fingerInfo);
295 fingerArr->SetValueAt(idx++, element);
296 }
297 obj->SetPropertyObject("fingerList", fingerArr);
298 auto target = CreateEventTargetObject(info);
299 obj->SetPropertyObject("target", target);
300 CreateFingerInfosObject(info, obj);
301 obj->Wrap<BaseGestureEvent>(info.get());
302 return obj;
303 }
304
CreateFingerInfosObject(const std::shared_ptr<BaseGestureEvent> & info,JSRef<JSObject> & obj)305 JSRef<JSObject> JsGestureJudgeFunction::CreateFingerInfosObject(
306 const std::shared_ptr<BaseGestureEvent>& info, JSRef<JSObject>& obj)
307 {
308 JSRef<JSArray> fingerArr = JSRef<JSArray>::New();
309 const std::list<FingerInfo>& fingerList = info->GetFingerList();
310 std::list<FingerInfo> notTouchFingerList;
311 std::vector<JSRef<JSObject>> validFingers;
312 for (const FingerInfo& fingerInfo : fingerList) {
313 JSRef<JSObject> element = CreateFingerInfo(fingerInfo);
314 if (fingerInfo.sourceType_ == SourceType::TOUCH && fingerInfo.sourceTool_ == SourceTool::FINGER) {
315 validFingers.emplace_back(element);
316 } else {
317 notTouchFingerList.emplace_back(fingerInfo);
318 }
319 }
320 for (size_t i = 0; i < validFingers.size(); ++i) {
321 fingerArr->SetValueAt(i, validFingers[i]);
322 }
323 auto idx = validFingers.size();
324 for (const FingerInfo& fingerInfo : notTouchFingerList) {
325 JSRef<JSObject> element = CreateFingerInfo(fingerInfo);
326 fingerArr->SetValueAt(idx++, element);
327 }
328 obj->SetPropertyObject("fingerInfos", fingerArr);
329 return obj;
330 }
331 } // namespace OHOS::Ace::Framework
332