1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components/gesture_listener/render_gesture_listener.h"
17 
18 #include "frameworks/bridge/common/dom/dom_document.h"
19 
20 namespace OHOS::Ace {
21 
22 namespace {
23 
24 constexpr int32_t DOUBLE_CLICK = 2;
25 constexpr int32_t DEFAULT_PINCH_FINGER = 2;
26 constexpr double DEFAULT_PINCH_DISTANCE = 1.0;
27 constexpr int32_t BUBBLE_MODE_VERSION = 6;
28 
29 }
30 #if !defined(PREVIEW)
SetDragCallBack(RefPtr<FreeDragRecognizer> & recognizer,RefPtr<GestureListenerComponent> component)31 void RenderGestureListener::SetDragCallBack(RefPtr<FreeDragRecognizer>& recognizer,
32     RefPtr<GestureListenerComponent> component)
33 {
34     auto& onDragStartId = component->GetOnFreeDragStartId();
35     auto& onDragUpdateId = component->GetOnFreeDragUpdateId();
36     auto& onDragEndId = component->GetOnFreeDragEndId();
37     auto& onDragCancelId = component->GetOnFreeDragCancelId();
38     GestureItemInfo dragInfo;
39     OnGestureFunc onDragStart = component->GetOnDragStartId();
40 
41     if (!(onDragStartId.IsEmpty() && onDragUpdateId.IsEmpty() && onDragEndId.IsEmpty() &&
42         onDragCancelId.IsEmpty())) {
43         recognizer = AceType::MakeRefPtr<FreeDragRecognizer>();
44         auto pipelineContext = context_.Upgrade();
45         if (!pipelineContext) {
46             LOGE("Context is null.");
47             return;
48         }
49         auto funcStart = AceAsyncEvent<void(const DragStartInfo&)>::Create(onDragStartId, context_);
50         auto funcDragStart = [pipelineContext, weak = AceType::WeakClaim<>(this), funcStart, onDragStart]
51             (const DragStartInfo& info)->void {
52             if (funcStart) {
53                 funcStart(info);
54             }
55             GestureItemInfo dragInfo;
56             if (onDragStart) {
57                 dragInfo = onDragStart();
58             }
59             if (dragInfo.pixelMap) {
60                 auto renderNode = weak.Upgrade();
61                 if (!renderNode->dragWindow_) {
62                     auto rect = pipelineContext->GetCurrentWindowRect();
63                     renderNode->dragWindow_ = DragWindow::CreateDragWindow("APP_DRAG_WINDOW",
64                         static_cast<int32_t>(info.GetGlobalLocation().GetX()) + rect.Left(),
65                         static_cast<int32_t>(info.GetGlobalLocation().GetY()) + rect.Top(),
66                         dragInfo.pixelMap->GetWidth(), dragInfo.pixelMap->GetHeight());
67                     renderNode->dragWindow_->SetOffset(rect.Left(), rect.Top());
68                     renderNode->dragWindow_->DrawPixelMap(dragInfo.pixelMap);
69                 }
70             }
71         };
72         auto funcUpdate = AceAsyncEvent<void(const DragUpdateInfo&)>::Create(onDragUpdateId, context_);
73         auto funcDragUpdate = [pipelineContext, weak = AceType::WeakClaim<>(this), funcUpdate, onDragStart]
74             (const DragUpdateInfo& info)->void {
75             if (funcUpdate) {
76                 funcUpdate(info);
77             }
78             GestureItemInfo dragInfo;
79             if (onDragStart) {
80                 dragInfo = onDragStart();
81             }
82             if (dragInfo.pixelMap) {
83                 auto renderNode = weak.Upgrade();
84                 if (!renderNode->dragWindow_) {
85                     auto rect = pipelineContext->GetCurrentWindowRect();
86                     renderNode->dragWindow_ = DragWindow::CreateDragWindow("APP_DRAG_WINDOW",
87                         static_cast<int32_t>(info.GetGlobalLocation().GetX()) + rect.Left(),
88                         static_cast<int32_t>(info.GetGlobalLocation().GetY()) + rect.Top(),
89                         dragInfo.pixelMap->GetWidth(), dragInfo.pixelMap->GetHeight());
90                     renderNode->dragWindow_->SetOffset(rect.Left(), rect.Top());
91                     renderNode->dragWindow_->DrawPixelMap(dragInfo.pixelMap);
92                 } else {
93                     int32_t x = static_cast<int32_t>(info.GetGlobalLocation().GetX());
94                     int32_t y = static_cast<int32_t>(info.GetGlobalLocation().GetY());
95                     int32_t offsetX = x + dragInfo.pixelMap->GetWidth() / 2
96                         - dragInfo.offsetX;
97                     int32_t offsetY = y + dragInfo.pixelMap->GetHeight()
98                         - dragInfo.offsetY;
99                     renderNode->dragWindow_->MoveTo(offsetX, offsetY);
100                 }
101             }
102         };
103         auto funcEnd = AceAsyncEvent<void(const DragEndInfo&)>::Create(onDragEndId, context_);
104         auto funcDragEnd = [pipelineContext, weak = AceType::WeakClaim<>(this), funcEnd, onDragStart]
105             (const DragEndInfo& info)->void {
106             if (funcEnd) {
107                 funcEnd(info);
108             }
109             auto renderNode = weak.Upgrade();
110             GestureItemInfo dragInfo;
111             if (onDragStart) {
112                 dragInfo = onDragStart();
113             }
114             if (dragInfo.pixelMap && renderNode->dragWindow_) {
115                 if (renderNode->dragWindow_) {
116                     renderNode->dragWindow_->Destroy();
117                     renderNode->dragWindow_ = nullptr;
118                 }
119             }
120         };
121         recognizer->SetOnDragStart(funcDragStart);
122         recognizer->SetOnDragUpdate(funcDragUpdate);
123         recognizer->SetOnDragEnd(funcDragEnd);
124         recognizer->SetOnDragCancel(AceAsyncEvent<void()>::Create(onDragCancelId, context_));
125     }
126 }
127 #endif
128 
129 #define SET_DRAG_CALLBACK(recognizer, type, component)                                                                 \
130     do {                                                                                                               \
131         auto& onDragStartId = component->GetOn##type##StartId();                                                       \
132         auto& onDragUpdateId = component->GetOn##type##UpdateId();                                                     \
133         auto& onDragEndId = component->GetOn##type##EndId();                                                           \
134         auto& onDragCancelId = component->GetOn##type##CancelId();                                                     \
135         if (!(onDragStartId.IsEmpty() && onDragUpdateId.IsEmpty() && onDragEndId.IsEmpty() &&                          \
136                 onDragCancelId.IsEmpty())) {                                                                           \
137             recognizer = AceType::MakeRefPtr<type##Recognizer>();                                                      \
138             recognizer->SetOnDragStart(AceAsyncEvent<void(const DragStartInfo&)>::Create(onDragStartId, context_));    \
139             recognizer->SetOnDragUpdate(AceAsyncEvent<void(const DragUpdateInfo&)>::Create(onDragUpdateId, context_)); \
140             recognizer->SetOnDragEnd(AceAsyncEvent<void(const DragEndInfo&)>::Create(onDragEndId, context_));          \
141             recognizer->SetOnDragCancel(AceAsyncEvent<void()>::Create(onDragCancelId, context_));                      \
142         }                                                                                                              \
143     } while (0)
144 
Create()145 RefPtr<RenderNode> RenderGestureListener::Create()
146 {
147     return AceType::MakeRefPtr<RenderGestureListener>();
148 }
149 
Update(const RefPtr<Component> & component)150 void RenderGestureListener::Update(const RefPtr<Component>& component)
151 {
152     RenderProxy::Update(component);
153     auto gestureComponent = AceType::DynamicCast<GestureListenerComponent>(component);
154     if (!gestureComponent) {
155         LOGE("gestureComponent is null");
156         return;
157     }
158     ACE_DCHECK(gestureComponent);
159     SetRemoteMessageCallback(gestureComponent);
160     SetOnClickCallback(gestureComponent);
161     SetOnDoubleClickCallback(gestureComponent);
162     SetOnLongPressCallback(gestureComponent);
163     SetOnPinchStartCallback(gestureComponent);
164     SetOnPinchUpdateCallback(gestureComponent);
165     SetOnPinchEndCallback(gestureComponent);
166     SetOnPinchCancelCallback(gestureComponent);
167     isVisible_ = gestureComponent->IsVisible();
168     responseRegion_ = gestureComponent->GetResponseRegion();
169     isResponseRegion_ = gestureComponent->IsResponseRegion();
170 #if !defined(PREVIEW)
171     SetDragCallBack(freeDragRecognizer_, gestureComponent);
172 #else
173     SET_DRAG_CALLBACK(freeDragRecognizer_, FreeDrag, gestureComponent);
174 #endif
175     if (!freeDragRecognizer_) {
176         // Horizontal and vertical gestures can only be enabled in the absence of free gesture.
177         SET_DRAG_CALLBACK(horizontalDragRecognizer_, HorizontalDrag, gestureComponent);
178         SET_DRAG_CALLBACK(verticalDragRecognizer_, VerticalDrag, gestureComponent);
179         return;
180     }
181 
182     freeDragRecognizer_->SetDragUpdateNotify([&](double x, double y, const DragUpdateInfo& updateInfo) {
183         auto context = context_.Upgrade();
184         if (!context) {
185             return;
186         }
187         TouchEvent point;
188         point.x = x;
189         point.y = y;
190         if (dragTarget_ == nullptr) {
191             RefPtr<RenderBox> renderBox = AceType::DynamicCast<RenderBox>(context->DragTestAll(point));
192             if (renderBox) {
193                 dragTarget_ = renderBox;
194                 dragTarget_->onDomDragEnter_(updateInfo);
195             }
196         } else {
197             if (dragTarget_->IsPointInBox(point)) {
198                 if (dragTarget_->onDomDragOver_) {
199                     dragTarget_->onDomDragOver_(updateInfo);
200                 }
201             } else {
202                 if (dragTarget_->onDomDragLeave_) {
203                     dragTarget_->onDomDragLeave_(updateInfo);
204                 }
205                 dragTarget_ = nullptr;
206             }
207         }
208     });
209 
210     freeDragRecognizer_->SetDragEndNotify([&](double x, double y, const DragEndInfo& endInfo) {
211         if (dragTarget_ != nullptr) {
212             if (dragTarget_->onDomDragDrop_) {
213                 dragTarget_->onDomDragDrop_(endInfo);
214             }
215             dragTarget_ = nullptr;
216         }
217     });
218 }
219 
GetVisible() const220 bool RenderGestureListener::GetVisible() const
221 {
222     return RenderNode::GetVisible() && isVisible_;
223 }
224 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)225 void RenderGestureListener::OnTouchTestHit(
226     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
227 {
228     if (clickRecognizer_) {
229         clickRecognizer_->SetCoordinateOffset(coordinateOffset);
230         result.emplace_back(clickRecognizer_);
231     }
232     if (doubleClickRecognizer_) {
233         doubleClickRecognizer_->SetCoordinateOffset(coordinateOffset);
234         result.emplace_back(doubleClickRecognizer_);
235     }
236     if (longPressRecognizer_) {
237         longPressRecognizer_->SetCoordinateOffset(coordinateOffset);
238         longPressRecognizer_->SetTouchRestrict(touchRestrict);
239         result.emplace_back(longPressRecognizer_);
240     }
241     if (pinchRecognizer_) {
242         pinchRecognizer_->SetCoordinateOffset(coordinateOffset);
243         result.emplace_back(pinchRecognizer_);
244     }
245     if (freeDragRecognizer_) {
246         freeDragRecognizer_->SetCoordinateOffset(coordinateOffset);
247         result.emplace_back(freeDragRecognizer_);
248         return;
249     }
250     // Horizontal and vertical gestures can only be enabled in the absence of free gesture.
251     if (verticalDragRecognizer_) {
252         verticalDragRecognizer_->SetCoordinateOffset(coordinateOffset);
253         result.emplace_back(verticalDragRecognizer_);
254     }
255     if (horizontalDragRecognizer_) {
256         horizontalDragRecognizer_->SetCoordinateOffset(coordinateOffset);
257         result.emplace_back(horizontalDragRecognizer_);
258     }
259 }
260 
SetOnClickCallback(const RefPtr<GestureListenerComponent> & component)261 void RenderGestureListener::SetOnClickCallback(const RefPtr<GestureListenerComponent>& component)
262 {
263     const auto& onClickId = component->GetOnClickId();
264     if (onClickId.IsEmpty()) {
265         return;
266     }
267     SetOnClickCallback(AceAsyncEvent<void(const ClickInfo&)>::Create(onClickId, context_));
268     if (!onClickId.GetCatchMode()) {
269         static const int32_t bubbleModeVersion = 6;
270         auto pipeline = context_.Upgrade();
271         if (pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
272             clickRecognizer_->SetUseCatchMode(false);
273             return;
274         }
275     }
276     clickRecognizer_->SetUseCatchMode(true);
277     clickRecognizer_->SetIsExternalGesture(true);
278 }
279 
SetRemoteMessageCallback(const RefPtr<GestureListenerComponent> & component)280 void RenderGestureListener::SetRemoteMessageCallback(const RefPtr<GestureListenerComponent>& component)
281 {
282     const auto& remoteMessageId = component->GetRemoteMessageId();
283     if (remoteMessageId.IsEmpty()) {
284         return;
285     }
286     SetRemoteMessageCallback(AceAsyncEvent<void(const ClickInfo&)>::Create(remoteMessageId, context_));
287     if (!remoteMessageId.GetCatchMode()) {
288         static const int32_t bubbleModeVersion = 6;
289         auto pipeline = context_.Upgrade();
290         if (pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
291             clickRecognizer_->SetUseCatchMode(false);
292             return;
293         }
294     }
295     clickRecognizer_->SetUseCatchMode(true);
296     clickRecognizer_->SetIsExternalGesture(true);
297 }
298 
SetOnDoubleClickCallback(const RefPtr<GestureListenerComponent> & component)299 void RenderGestureListener::SetOnDoubleClickCallback(const RefPtr<GestureListenerComponent>& component)
300 {
301     const auto& onDoubleClickId = component->GetOnDoubleClickId();
302     if (onDoubleClickId.IsEmpty()) {
303         return;
304     }
305     SetOnDoubleClickCallback(AceAsyncEvent<void(const ClickInfo&)>::Create(onDoubleClickId, context_));
306     if (!onDoubleClickId.GetCatchMode()) {
307         auto pipeline = context_.Upgrade();
308         if (pipeline && pipeline->GetMinPlatformVersion() >= BUBBLE_MODE_VERSION) {
309             doubleClickRecognizer_->SetUseCatchMode(false);
310             return;
311         }
312     }
313     doubleClickRecognizer_->SetUseCatchMode(true);
314     doubleClickRecognizer_->SetIsExternalGesture(true);
315 }
316 
SetOnLongPressCallback(const RefPtr<GestureListenerComponent> & component)317 void RenderGestureListener::SetOnLongPressCallback(const RefPtr<GestureListenerComponent>& component)
318 {
319     const auto& onLongPressId = component->GetOnLongPressId();
320     if (onLongPressId.IsEmpty()) {
321         return;
322     }
323     SetOnLongPressCallback(AceAsyncEvent<void(const LongPressInfo&)>::Create(onLongPressId, context_));
324     if (!onLongPressId.GetCatchMode()) {
325         auto pipeline = context_.Upgrade();
326         if (pipeline && pipeline->GetMinPlatformVersion() >= BUBBLE_MODE_VERSION) {
327             longPressRecognizer_->SetUseCatchMode(false);
328             return;
329         }
330     }
331     longPressRecognizer_->SetUseCatchMode(true);
332     longPressRecognizer_->SetIsExternalGesture(true);
333 }
334 
SetOnPinchStartCallback(const RefPtr<GestureListenerComponent> & component)335 void RenderGestureListener::SetOnPinchStartCallback(const RefPtr<GestureListenerComponent>& component)
336 {
337     const auto& onPinchStartId = component->GetOnPinchStartId();
338     if (onPinchStartId.IsEmpty()) {
339         return;
340     }
341     SetOnPinchStartCallback(AceAsyncEvent<void(const GestureEvent&)>::Create(onPinchStartId, context_));
342 }
343 
SetOnPinchUpdateCallback(const RefPtr<GestureListenerComponent> & component)344 void RenderGestureListener::SetOnPinchUpdateCallback(const RefPtr<GestureListenerComponent>& component)
345 {
346     const auto& onPinchUpdateId = component->GetOnPinchUpdateId();
347     if (onPinchUpdateId.IsEmpty()) {
348         return;
349     }
350     SetOnPinchUpdateCallback(AceAsyncEvent<void(const GestureEvent&)>::Create(onPinchUpdateId, context_));
351 }
352 
SetOnPinchEndCallback(const RefPtr<GestureListenerComponent> & component)353 void RenderGestureListener::SetOnPinchEndCallback(const RefPtr<GestureListenerComponent>& component)
354 {
355     const auto& onPinchEndId = component->GetOnPinchEndId();
356     if (onPinchEndId.IsEmpty()) {
357         return;
358     }
359     SetOnPinchEndCallback(AceAsyncEvent<void(const GestureEvent&)>::Create(onPinchEndId, context_));
360 }
361 
SetOnPinchCancelCallback(const RefPtr<GestureListenerComponent> & component)362 void RenderGestureListener::SetOnPinchCancelCallback(const RefPtr<GestureListenerComponent>& component)
363 {
364     const auto& onPinchCancelId = component->GetOnPinchCancelId();
365     if (onPinchCancelId.IsEmpty()) {
366         return;
367     }
368     SetOnPinchCancelCallback(AceAsyncEvent<void()>::Create(onPinchCancelId, context_));
369 }
370 
SetRemoteMessageCallback(const ClickCallback & callback)371 void RenderGestureListener::SetRemoteMessageCallback(const ClickCallback& callback)
372 {
373     if (callback) {
374         if (!clickRecognizer_) {
375             clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
376         }
377         clickRecognizer_->SetRemoteMessage(callback);
378     } else {
379         LOGE("fail to set remote message callback due to callback is nullptr");
380     }
381 }
382 
SetOnClickCallback(const ClickCallback & callback)383 void RenderGestureListener::SetOnClickCallback(const ClickCallback& callback)
384 {
385     if (callback) {
386         if (!clickRecognizer_) {
387             clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
388         }
389         clickRecognizer_->SetOnClick(callback);
390     } else {
391         LOGE("fail to set click callback due to callback is nullptr");
392     }
393 }
394 
SetOnDoubleClickCallback(const ClickCallback & callback)395 void RenderGestureListener::SetOnDoubleClickCallback(const ClickCallback& callback)
396 {
397     if (callback) {
398         if (!doubleClickRecognizer_) {
399             doubleClickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>(GetContext(), 1, DOUBLE_CLICK);
400         }
401         doubleClickRecognizer_->SetOnClick(callback);
402     } else {
403         LOGE("fail to set double click callback due to callback is nullptr");
404     }
405 }
406 
SetOnLongPressCallback(const OnLongPress & callback)407 void RenderGestureListener::SetOnLongPressCallback(const OnLongPress& callback)
408 {
409     if (callback) {
410         if (!longPressRecognizer_) {
411             longPressRecognizer_ = AceType::MakeRefPtr<LongPressRecognizer>(context_);
412         }
413         longPressRecognizer_->SetOnLongPress(callback);
414     } else {
415         LOGE("fail to set long press callback due to callback is nullptr");
416     }
417 }
418 
SetOnPinchStartCallback(const GestureEventFunc & onPinchStart)419 void RenderGestureListener::SetOnPinchStartCallback(const GestureEventFunc& onPinchStart)
420 {
421     if (onPinchStart) {
422         if (!pinchRecognizer_) {
423             pinchRecognizer_ = AceType::MakeRefPtr<PinchRecognizer>(DEFAULT_PINCH_FINGER, DEFAULT_PINCH_DISTANCE);
424         }
425         pinchRecognizer_->SetOnActionStart(onPinchStart);
426     } else {
427         LOGE("fail to set pinch start callback due to callback is nullptr");
428     }
429 }
430 
SetOnPinchUpdateCallback(const GestureEventFunc & onPinchUpdate)431 void RenderGestureListener::SetOnPinchUpdateCallback(const GestureEventFunc& onPinchUpdate)
432 {
433     if (onPinchUpdate) {
434         if (!pinchRecognizer_) {
435             pinchRecognizer_ = AceType::MakeRefPtr<PinchRecognizer>(DEFAULT_PINCH_FINGER, DEFAULT_PINCH_DISTANCE);
436         }
437         pinchRecognizer_->SetOnActionUpdate(onPinchUpdate);
438     } else {
439         LOGE("fail to set pinch update callback due to callback is nullptr");
440     }
441 }
442 
SetOnPinchEndCallback(const GestureEventFunc & onPinchEnd)443 void RenderGestureListener::SetOnPinchEndCallback(const GestureEventFunc& onPinchEnd)
444 {
445     if (onPinchEnd) {
446         if (!pinchRecognizer_) {
447             pinchRecognizer_ = AceType::MakeRefPtr<PinchRecognizer>(DEFAULT_PINCH_FINGER, DEFAULT_PINCH_DISTANCE);
448         }
449         pinchRecognizer_->SetOnActionEnd(onPinchEnd);
450     } else {
451         LOGE("fail to set pinch end callback due to callback is nullptr");
452     }
453 }
454 
SetOnPinchCancelCallback(const GestureEventNoParameter & onPinchCancel)455 void RenderGestureListener::SetOnPinchCancelCallback(const GestureEventNoParameter& onPinchCancel)
456 {
457     if (onPinchCancel) {
458         if (!pinchRecognizer_) {
459             pinchRecognizer_ = AceType::MakeRefPtr<PinchRecognizer>(DEFAULT_PINCH_FINGER, DEFAULT_PINCH_DISTANCE);
460         }
461         pinchRecognizer_->SetOnActionCancel(onPinchCancel);
462     } else {
463         LOGE("fail to set pinch cancel callback due to callback is nullptr");
464     }
465 }
466 
UpdateTouchRect()467 void RenderGestureListener::UpdateTouchRect()
468 {
469     const auto& children = GetChildren();
470     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
471         auto& child = *iter;
472         for (auto& rect : child->GetTouchRectList()) {
473             // unified coordinate system
474             Rect newRect = rect;
475             newRect.SetOffset(rect.GetOffset() + GetPaintRect().GetOffset());
476             touchRectList_.emplace_back(newRect);
477         }
478     }
479 }
480 
481 } // namespace OHOS::Ace
482