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