1 /*
2 * Copyright (c) 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
16 #include "core/components_ng/pattern/text/text_select_overlay.h"
17
18 #include <algorithm>
19 #include <optional>
20
21 #include "base/utils/utils.h"
22 #include "core/components/text_overlay/text_overlay_theme.h"
23 #include "core/components_ng/manager/select_content_overlay/select_content_overlay_manager.h"
24 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
25 #include "core/components_ng/pattern/text/text_pattern.h"
26
27 namespace OHOS::Ace::NG {
28 namespace {
29 constexpr float BOX_EPSILON = 0.5f;
30 }
31
PreProcessOverlay(const OverlayRequest & request)32 bool TextSelectOverlay::PreProcessOverlay(const OverlayRequest& request)
33 {
34 auto pipeline = PipelineContext::GetCurrentContextSafely();
35 CHECK_NULL_RETURN(pipeline, false);
36 auto textPattern = GetPattern<TextPattern>();
37 CHECK_NULL_RETURN(textPattern, false);
38 SetUsingMouse(textPattern->IsUsingMouse());
39 SetEnableHandleLevel(true);
40 textPattern->CalculateHandleOffsetAndShowOverlay();
41 selectTextUseTopHandle = true;
42 return true;
43 }
44
GetFirstHandleInfo()45 std::optional<SelectHandleInfo> TextSelectOverlay::GetFirstHandleInfo()
46 {
47 auto textPattern = GetPattern<TextPattern>();
48 CHECK_NULL_RETURN(textPattern, std::nullopt);
49 SelectHandleInfo handleInfo;
50 handleInfo.paintRect = textPattern->GetTextSelector().firstHandle;
51 handleInfo.isShow = CheckAndAdjustHandle(handleInfo.paintRect);
52
53 auto localPaintRect = textPattern->GetTextSelector().firstHandle;
54 localPaintRect.SetOffset(localPaintRect.GetOffset() - GetPaintOffsetWithoutTransform());
55 handleInfo.localPaintRect = localPaintRect;
56 SetTransformPaintInfo(handleInfo, localPaintRect);
57 return handleInfo;
58 }
59
GetSecondHandleInfo()60 std::optional<SelectHandleInfo> TextSelectOverlay::GetSecondHandleInfo()
61 {
62 auto textPattern = GetPattern<TextPattern>();
63 CHECK_NULL_RETURN(textPattern, std::nullopt);
64 SelectHandleInfo handleInfo;
65 handleInfo.paintRect = textPattern->GetTextSelector().secondHandle;
66 handleInfo.isShow = CheckAndAdjustHandle(handleInfo.paintRect);
67
68 auto localPaintRect = textPattern->GetTextSelector().secondHandle;
69 localPaintRect.SetOffset(localPaintRect.GetOffset() - GetPaintOffsetWithoutTransform());
70 handleInfo.localPaintRect = localPaintRect;
71 SetTransformPaintInfo(handleInfo, localPaintRect);
72 return handleInfo;
73 }
74
GetFirstHandleLocalPaintRect()75 RectF TextSelectOverlay::GetFirstHandleLocalPaintRect()
76 {
77 auto textPattern = GetPattern<TextPattern>();
78 CHECK_NULL_RETURN(textPattern, RectF());
79 auto localPaintRect = textPattern->GetTextSelector().firstHandle;
80 localPaintRect.SetOffset(localPaintRect.GetOffset() - GetPaintOffsetWithoutTransform());
81 return localPaintRect;
82 }
83
GetSecondHandleLocalPaintRect()84 RectF TextSelectOverlay::GetSecondHandleLocalPaintRect()
85 {
86 auto textPattern = GetPattern<TextPattern>();
87 CHECK_NULL_RETURN(textPattern, RectF());
88 auto localPaintRect = textPattern->GetTextSelector().secondHandle;
89 localPaintRect.SetOffset(localPaintRect.GetOffset() - GetPaintOffsetWithoutTransform());
90 return localPaintRect;
91 }
92
CheckAndAdjustHandle(RectF & paintRect)93 bool TextSelectOverlay::CheckAndAdjustHandle(RectF& paintRect)
94 {
95 auto textPattern = GetPattern<TextPattern>();
96 CHECK_NULL_RETURN(textPattern, false);
97 auto host = textPattern->GetHost();
98 CHECK_NULL_RETURN(host, false);
99 auto renderContext = host->GetRenderContext();
100 CHECK_NULL_RETURN(renderContext, false);
101 auto clip = false;
102 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
103 clip = true;
104 }
105 if (!renderContext->GetClipEdge().value_or(clip)) {
106 if (handleLevelMode_ == HandleLevelMode::EMBED) {
107 return true;
108 }
109 auto contentRect = textPattern->GetTextContentRect();
110 auto localPaintRect = paintRect;
111 localPaintRect.SetOffset(localPaintRect.GetOffset() - GetPaintOffsetWithoutTransform());
112 localPaintRect.SetOffset(OffsetF(localPaintRect.GetX() + localPaintRect.Width() / 2.0f, localPaintRect.GetY()));
113 auto visibleContentRect = contentRect.CombineRectT(localPaintRect);
114 visibleContentRect.SetOffset(visibleContentRect.GetOffset() + textPattern->GetTextPaintOffset());
115 visibleContentRect = GetVisibleRect(host, visibleContentRect);
116 return CheckAndAdjustHandleWithContent(visibleContentRect, paintRect);
117 }
118 auto contentRect = textPattern->GetTextContentRect();
119 RectF visibleContentRect(contentRect.GetOffset() + textPattern->GetTextPaintOffset(), contentRect.GetSize());
120 if (handleLevelMode_ == HandleLevelMode::OVERLAY) {
121 visibleContentRect = GetVisibleRect(host, visibleContentRect);
122 }
123 return CheckAndAdjustHandleWithContent(visibleContentRect, paintRect);
124 }
125
CheckAndAdjustHandleWithContent(const RectF & visibleContentRect,RectF & paintRect)126 bool TextSelectOverlay::CheckAndAdjustHandleWithContent(const RectF& visibleContentRect, RectF& paintRect)
127 {
128 auto paintLeft = paintRect.GetX() + paintRect.Width() / 2.0f;
129 PointF bottomPoint = { paintLeft, paintRect.Bottom() - BOX_EPSILON };
130 PointF topPoint = { paintLeft, paintRect.Top() + BOX_EPSILON };
131 bool bottomInRegion = visibleContentRect.IsInRegion(bottomPoint);
132 bool topInRegion = visibleContentRect.IsInRegion(topPoint);
133 if (IsClipHandleWithViewPort()) {
134 return bottomInRegion || topInRegion;
135 }
136 if (!bottomInRegion && topInRegion) {
137 paintRect.SetHeight(visibleContentRect.Bottom() - paintRect.Top());
138 } else if (bottomInRegion && !topInRegion) {
139 paintRect.SetHeight(paintRect.Bottom() - visibleContentRect.Top());
140 paintRect.SetTop(visibleContentRect.Top());
141 }
142 return bottomInRegion || topInRegion;
143 }
144
CheckHandleVisible(const RectF & paintRect)145 bool TextSelectOverlay::CheckHandleVisible(const RectF& paintRect)
146 {
147 auto textPattern = GetPattern<TextPattern>();
148 CHECK_NULL_RETURN(textPattern, false);
149 auto host = textPattern->GetHost();
150 CHECK_NULL_RETURN(host, false);
151 auto renderContext = host->GetRenderContext();
152 CHECK_NULL_RETURN(renderContext, false);
153 auto clip = false;
154 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
155 clip = true;
156 }
157 if (!renderContext->GetClipEdge().value_or(clip)) {
158 return true;
159 }
160 auto contentRect = textPattern->GetTextContentRect();
161 RectF visibleContentRect(contentRect.GetOffset() + textPattern->GetTextPaintOffset(), contentRect.GetSize());
162 visibleContentRect = GetVisibleRect(host, visibleContentRect);
163 PointF bottomPoint = { paintRect.Left(), paintRect.Bottom() - BOX_EPSILON };
164 PointF topPoint = { paintRect.Left(), paintRect.Top() + BOX_EPSILON };
165 return visibleContentRect.IsInRegion(bottomPoint) && visibleContentRect.IsInRegion(topPoint);
166 }
167
OnResetTextSelection()168 void TextSelectOverlay::OnResetTextSelection()
169 {
170 auto textPattern = GetPattern<TextPattern>();
171 CHECK_NULL_VOID(textPattern);
172 textPattern->ResetSelection();
173 }
174
OnHandleMove(const RectF & handleRect,bool isFirst)175 void TextSelectOverlay::OnHandleMove(const RectF& handleRect, bool isFirst)
176 {
177 auto textPattern = GetPattern<TextPattern>();
178 CHECK_NULL_VOID(textPattern);
179 auto host = textPattern->GetHost();
180 CHECK_NULL_VOID(host);
181 auto renderContext = host->GetRenderContext();
182 CHECK_NULL_VOID(renderContext);
183 auto contentRect = textPattern->GetTextContentRect();
184 auto contentOffset = contentRect.GetOffset();
185 auto localHandleOffset = handleRect.GetOffset();
186 if (IsOverlayMode()) {
187 contentOffset = contentOffset + GetPaintOffsetWithoutTransform();
188 localHandleOffset -= GetPaintOffsetWithoutTransform();
189 }
190 localHandleOffset.SetY(localHandleOffset.GetY() + handleRect.Height() / 2.0f);
191 textPattern->GetMagnifierController()->SetLocalOffset(localHandleOffset);
192 auto handleOffset = handleRect.GetOffset();
193 handleOffset.SetY(handleOffset.GetY() + handleRect.Height() / 2.0f);
194 auto clip = false;
195 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
196 clip = true;
197 }
198 if (renderContext->GetClipEdge().value_or(clip)) {
199 handleOffset.SetX(
200 std::clamp(handleOffset.GetX(), contentOffset.GetX(), contentOffset.GetX() + contentRect.Width()));
201 handleOffset.SetY(
202 std::clamp(handleOffset.GetY(), contentOffset.GetY(), contentOffset.GetY() + contentRect.Height()));
203 }
204 auto textPaintOffset = contentOffset - OffsetF(0.0f, std::min(textPattern->GetBaselineOffset(), 0.0f));
205 handleOffset -= textPaintOffset;
206 // the handle position is calculated based on the middle of the handle height.
207 UpdateSelectorOnHandleMove(handleOffset, isFirst);
208 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
209 auto overlayManager = GetManager<SelectContentOverlayManager>();
210 CHECK_NULL_VOID(overlayManager);
211 overlayManager->MarkInfoChange(DIRTY_SELECT_TEXT);
212 }
213
UpdateSelectorOnHandleMove(const OffsetF & handleOffset,bool isFirstHandle)214 void TextSelectOverlay::UpdateSelectorOnHandleMove(const OffsetF& handleOffset, bool isFirstHandle)
215 {
216 auto textPattern = GetPattern<TextPattern>();
217 CHECK_NULL_VOID(textPattern);
218 auto currentHandleIndex = textPattern->GetHandleIndex(Offset(handleOffset.GetX(), handleOffset.GetY()));
219 if (isFirstHandle) {
220 textPattern->StartVibratorByIndexChange(currentHandleIndex, textPattern->GetTextSelector().baseOffset);
221 textPattern->HandleSelectionChange(currentHandleIndex, textPattern->GetTextSelector().destinationOffset);
222 } else {
223 textPattern->StartVibratorByIndexChange(currentHandleIndex, textPattern->GetTextSelector().destinationOffset);
224 textPattern->HandleSelectionChange(textPattern->GetTextSelector().baseOffset, currentHandleIndex);
225 }
226 }
227
OnHandleMoveDone(const RectF & rect,bool isFirst)228 void TextSelectOverlay::OnHandleMoveDone(const RectF& rect, bool isFirst)
229 {
230 BaseTextSelectOverlay::OnHandleMoveDone(rect, isFirst);
231 auto textPattern = GetPattern<TextPattern>();
232 CHECK_NULL_VOID(textPattern);
233 if (textPattern->GetMagnifierController()) {
234 textPattern->GetMagnifierController()->RemoveMagnifierFrameNode();
235 }
236 textPattern->SetTextResponseType(TextResponseType::LONG_PRESS);
237 auto textSelector = textPattern->GetTextSelector();
238 textPattern->UpdateSelectionSpanType(textSelector.GetTextStart(), textSelector.GetTextEnd());
239 textPattern->CalculateHandleOffsetAndShowOverlay();
240 auto overlayManager = GetManager<SelectContentOverlayManager>();
241 CHECK_NULL_VOID(overlayManager);
242 overlayManager->ShowOptionMenu();
243 overlayManager->MarkInfoChange((isFirst ? DIRTY_FIRST_HANDLE : DIRTY_SECOND_HANDLE) | DIRTY_SELECT_AREA |
244 DIRTY_SELECT_TEXT | DIRTY_COPY_ALL_ITEM);
245 if (textPattern->CheckSelectedTypeChange()) {
246 CloseOverlay(false, CloseReason::CLOSE_REASON_NORMAL);
247 ProcessOverlay({ .animation = true });
248 }
249 overlayManager->SetHandleCircleIsShow(isFirst, true);
250 auto host = textPattern->GetHost();
251 CHECK_NULL_VOID(host);
252 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
253 }
254
GetSelectedText()255 std::string TextSelectOverlay::GetSelectedText()
256 {
257 auto textPattern = GetPattern<TextPattern>();
258 CHECK_NULL_RETURN(textPattern, "");
259 auto start = textPattern->GetTextSelector().GetTextStart();
260 auto end = textPattern->GetTextSelector().GetTextEnd();
261 return textPattern->GetSelectedText(start, end);
262 }
263
GetSelectArea()264 RectF TextSelectOverlay::GetSelectArea()
265 {
266 auto pattern = GetPattern<TextPattern>();
267 RectF res;
268 CHECK_NULL_RETURN(pattern, res);
269 auto selectRects = pattern->GetTextBoxes();
270 auto textPaintOffset = GetPaintOffsetWithoutTransform();
271 if (selectRects.empty()) {
272 res.SetOffset(res.GetOffset() + textPaintOffset);
273 GetSelectAreaFromHandle(res);
274 ApplySelectAreaWithKeyboard(res);
275 return res;
276 }
277 auto contentRect = pattern->GetTextContentRect();
278 auto textRect = pattern->GetTextRect();
279 res = MergeSelectedBoxes(selectRects, contentRect, textRect, textPaintOffset);
280 RectF visibleContentRect(contentRect.GetOffset() + textPaintOffset, contentRect.GetSize());
281 visibleContentRect = GetVisibleRect(pattern->GetHost(), visibleContentRect);
282 auto intersectRect = res.IntersectRectT(visibleContentRect);
283 intersectRect.SetWidth(std::max(intersectRect.Width(), 0.0f));
284 intersectRect.SetHeight(std::max(intersectRect.Height(), 0.0f));
285 if (hasTransform_) {
286 intersectRect.SetOffset(intersectRect.GetOffset() - textPaintOffset);
287 GetGlobalRectWithTransform(intersectRect);
288 }
289 ApplySelectAreaWithKeyboard(intersectRect);
290 return intersectRect;
291 }
292
GetSelectAreaFromHandle(RectF & rect)293 void TextSelectOverlay::GetSelectAreaFromHandle(RectF& rect)
294 {
295 auto firstHandle = GetFirstHandleInfo();
296 if (firstHandle) {
297 auto firstRect = firstHandle->paintRect;
298 if (hasTransform_) {
299 firstRect.SetOffset(firstRect.GetOffset() - GetPaintOffsetWithoutTransform());
300 GetGlobalRectWithTransform(firstRect);
301 }
302 rect = firstRect;
303 return;
304 }
305 auto secondHandle = GetSecondHandleInfo();
306 if (secondHandle) {
307 auto secondRect = secondHandle->paintRect;
308 if (hasTransform_) {
309 secondRect.SetOffset(secondRect.GetOffset() - GetPaintOffsetWithoutTransform());
310 GetGlobalRectWithTransform(secondRect);
311 }
312 rect = secondRect;
313 }
314 }
315
OnUpdateMenuInfo(SelectMenuInfo & menuInfo,SelectOverlayDirtyFlag dirtyFlag)316 void TextSelectOverlay::OnUpdateMenuInfo(SelectMenuInfo& menuInfo, SelectOverlayDirtyFlag dirtyFlag)
317 {
318 auto textPattern = GetPattern<TextPattern>();
319 CHECK_NULL_VOID(textPattern);
320 menuInfo.showCopyAll = !textPattern->IsSelectAll();
321 menuInfo.showCopy = !textPattern->GetTextSelector().SelectNothing();
322 if (dirtyFlag == DIRTY_COPY_ALL_ITEM) {
323 return;
324 }
325 menuInfo.menuIsShow = IsShowMenu();
326 menuInfo.showCut = false;
327 menuInfo.showPaste = false;
328 }
329
OnUpdateSelectOverlayInfo(SelectOverlayInfo & overlayInfo,int32_t requestCode)330 void TextSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo& overlayInfo, int32_t requestCode)
331 {
332 overlayInfo.clipHandleDrawRect = IsClipHandleWithViewPort();
333 BaseTextSelectOverlay::OnUpdateSelectOverlayInfo(overlayInfo, requestCode);
334 auto textPattern = GetPattern<TextPattern>();
335 CHECK_NULL_VOID(textPattern);
336 textPattern->CopySelectionMenuParams(overlayInfo);
337 auto layoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
338 CHECK_NULL_VOID(layoutProperty);
339 overlayInfo.handlerColor = layoutProperty->GetCursorColor();
340 OnUpdateOnCreateMenuCallback(overlayInfo);
341 auto scrollableParent = FindScrollableParent();
342 if (scrollableParent) {
343 auto weakParent = WeakClaim(AceType::RawPtr(scrollableParent));
344 overlayInfo.onHandlePanMove = [weak = WeakClaim(this), weakParent](const GestureEvent& event, bool isFirst) {
345 auto overlay = weak.Upgrade();
346 CHECK_NULL_VOID(overlay);
347 overlay->TriggerScrollableParentToScroll(weakParent.Upgrade(), event.GetGlobalLocation(), false);
348 };
349 overlayInfo.onHandlePanEnd = [weak = WeakClaim(this), weakParent](const GestureEvent& event, bool isFirst) {
350 auto overlay = weak.Upgrade();
351 CHECK_NULL_VOID(overlay);
352 overlay->TriggerScrollableParentToScroll(weakParent.Upgrade(), event.GetGlobalLocation(), true);
353 };
354 overlayInfo.getDeltaHandleOffset = [weak = WeakClaim(this)]() {
355 auto overlay = weak.Upgrade();
356 CHECK_NULL_RETURN(overlay, OffsetF());
357 auto hostPaintOffset = overlay->GetHotPaintOffset();
358 auto deltaOffset = overlay->hostPaintOffset_ - hostPaintOffset;
359 overlay->hostPaintOffset_ = hostPaintOffset;
360 return deltaOffset;
361 };
362 }
363 }
364
OnMenuItemAction(OptionMenuActionId id,OptionMenuType type)365 void TextSelectOverlay::OnMenuItemAction(OptionMenuActionId id, OptionMenuType type)
366 {
367 auto textPattern = GetPattern<TextPattern>();
368 CHECK_NULL_VOID(textPattern);
369 switch (id) {
370 case OptionMenuActionId::COPY:
371 textPattern->HandleOnCopy();
372 break;
373 case OptionMenuActionId::SELECT_ALL:
374 textPattern->HandleOnSelectAll();
375 break;
376 default:
377 TAG_LOGI(AceLogTag::ACE_TEXT, "Unsupported menu option id %{public}d", id);
378 break;
379 }
380 }
381
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)382 void TextSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
383 {
384 BaseTextSelectOverlay::OnCloseOverlay(menuType, reason, info);
385 auto textPattern = GetPattern<TextPattern>();
386 CHECK_NULL_VOID(textPattern);
387 if (reason == CloseReason::CLOSE_REASON_HOLD_BY_OTHER || reason == CloseReason::CLOSE_REASON_TOOL_BAR ||
388 reason == CloseReason::CLOSE_REASON_BACK_PRESSED) {
389 textPattern->ResetSelection();
390 }
391 if (textPattern->GetMagnifierController()) {
392 textPattern->GetMagnifierController()->RemoveMagnifierFrameNode();
393 }
394 }
395
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)396 void TextSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
397 {
398 auto textPattern = GetPattern<TextPattern>();
399 CHECK_NULL_VOID(textPattern);
400 if (IsMouseClickDown(sourceType, touchType) && touchInside) {
401 textPattern->ResetSelection();
402 }
403 BaseTextSelectOverlay::OnHandleGlobalTouchEvent(sourceType, touchType);
404 }
405
OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)406 void TextSelectOverlay::OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)
407 {
408 auto isDragging = GetIsHandleDragging();
409 if (IsAncestorNodeGeometryChange(flag)) {
410 auto textPattern = GetPattern<TextPattern>();
411 CHECK_NULL_VOID(textPattern);
412 textPattern->UpdateParentGlobalOffset();
413 textPattern->CalculateHandleOffsetAndShowOverlay();
414 if (isDragging && isDraggingFirstHandle_) {
415 UpdateViewPort();
416 UpdateSecondHandleOffset();
417 return;
418 }
419 if (isDragging && !isDraggingFirstHandle_) {
420 UpdateViewPort();
421 UpdateFirstHandleOffset();
422 return;
423 }
424 UpdateAllHandlesOffset();
425 }
426 if (!isDragging) {
427 BaseTextSelectOverlay::OnAncestorNodeChanged(flag);
428 }
429 }
430
OnHandleLevelModeChanged(HandleLevelMode mode)431 void TextSelectOverlay::OnHandleLevelModeChanged(HandleLevelMode mode)
432 {
433 if (handleLevelMode_ != mode && mode == HandleLevelMode::OVERLAY) {
434 auto textPattern = GetPattern<TextPattern>();
435 CHECK_NULL_VOID(textPattern);
436 textPattern->UpdateParentGlobalOffset();
437 textPattern->CalculateHandleOffsetAndShowOverlay();
438 UpdateAllHandlesOffset();
439 }
440 BaseTextSelectOverlay::OnHandleLevelModeChanged(mode);
441 }
442
OnHandleMoveStart(const GestureEvent & event,bool isFirst)443 void TextSelectOverlay::OnHandleMoveStart(const GestureEvent& event, bool isFirst)
444 {
445 BaseTextSelectOverlay::OnHandleMoveStart(event, isFirst);
446 auto textPattern = GetPattern<TextPattern>();
447 CHECK_NULL_VOID(textPattern);
448 textPattern->ChangeHandleHeight(event, isFirst, IsOverlayMode());
449 auto manager = GetManager<SelectContentOverlayManager>();
450 CHECK_NULL_VOID(manager);
451 manager->MarkInfoChange(isFirst ? DIRTY_FIRST_HANDLE : DIRTY_SECOND_HANDLE);
452 manager->SetHandleCircleIsShow(isFirst, false);
453 isDraggingFirstHandle_ = isFirst;
454 hostPaintOffset_ = GetHotPaintOffset();
455 }
456
OnOverlayClick(const GestureEvent & event,bool isFirst)457 void TextSelectOverlay::OnOverlayClick(const GestureEvent& event, bool isFirst)
458 {
459 if (!IsSingleHandle()) {
460 ToggleMenu();
461 }
462 }
463
UpdateClipHandleViewPort(RectF & rect)464 void TextSelectOverlay::UpdateClipHandleViewPort(RectF& rect)
465 {
466 auto host = GetOwner();
467 CHECK_NULL_VOID(host);
468 auto renderContext = host->GetRenderContext();
469 CHECK_NULL_VOID(renderContext);
470 if (renderContext->GetClipEdge().value_or(false)) {
471 return;
472 }
473 auto clipNode = host->GetAncestorNodeOfFrame(true);
474 while (clipNode) {
475 renderContext = clipNode->GetRenderContext();
476 CHECK_NULL_VOID(renderContext);
477 if (renderContext->GetClipEdge().value_or(false)) {
478 break;
479 }
480 clipNode = clipNode->GetAncestorNodeOfFrame(true);
481 }
482 CHECK_NULL_VOID(clipNode);
483 RectF visibleRect;
484 RectF frameRect;
485 clipNode->GetVisibleRect(visibleRect, frameRect);
486 rect.SetHeight(visibleRect.Bottom() - rect.Top());
487 }
488
TriggerScrollableParentToScroll(const RefPtr<ScrollablePattern> scrollablePattern,const Offset & globalOffset,bool isStopAutoScroll)489 void TextSelectOverlay::TriggerScrollableParentToScroll(
490 const RefPtr<ScrollablePattern> scrollablePattern, const Offset& globalOffset, bool isStopAutoScroll)
491 {
492 CHECK_NULL_VOID(scrollablePattern);
493 auto scrollAxis = scrollablePattern->GetAxis();
494 if (!scrollablePattern->IsScrollable() || (scrollAxis != Axis::VERTICAL && scrollAxis != Axis::HORIZONTAL)) {
495 return;
496 }
497 auto scrollableHost = scrollablePattern->GetHost();
498 CHECK_NULL_VOID(scrollableHost);
499 auto scrollableFrameRect = scrollableHost->GetPaintRectWithTransform();
500 auto host = GetOwner();
501 CHECK_NULL_VOID(host);
502 auto hostRect = host->GetPaintRectWithTransform();
503 auto hostSize = hostRect.Height();
504 auto scrollableParentSize = scrollableFrameRect.Height();
505 if (scrollAxis == Axis::HORIZONTAL) {
506 hostSize = hostRect.Width();
507 scrollableParentSize = scrollableFrameRect.Width();
508 }
509 if (LessOrEqual(hostSize, scrollableParentSize)) {
510 return;
511 }
512 RefPtr<NotifyDragEvent> notifyDragEvent = AceType::MakeRefPtr<NotifyDragEvent>();
513 notifyDragEvent->SetX(globalOffset.GetX());
514 notifyDragEvent->SetY(globalOffset.GetY());
515 scrollablePattern->HandleOnDragStatusCallback(
516 isStopAutoScroll ? DragEventType::DROP : DragEventType::MOVE, notifyDragEvent);
517 }
518
FindScrollableParent()519 const RefPtr<ScrollablePattern> TextSelectOverlay::FindScrollableParent()
520 {
521 auto host = GetOwner();
522 CHECK_NULL_RETURN(host, nullptr);
523 auto parent = host->GetAncestorNodeOfFrame(true);
524 while (parent) {
525 auto scrollablePattern = parent->GetPattern<ScrollablePattern>();
526 if (scrollablePattern) {
527 return scrollablePattern;
528 }
529 parent = parent->GetAncestorNodeOfFrame(true);
530 }
531 return nullptr;
532 }
533
GetHotPaintOffset()534 OffsetF TextSelectOverlay::GetHotPaintOffset()
535 {
536 auto host = GetOwner();
537 CHECK_NULL_RETURN(host, hostPaintOffset_);
538 auto renderContext = host->GetRenderContext();
539 CHECK_NULL_RETURN(renderContext, hostPaintOffset_);
540 return renderContext->GetPaintRectWithTransform().GetOffset();
541 }
542
GetHandleColor()543 std::optional<Color> TextSelectOverlay::GetHandleColor()
544 {
545 auto textPattern = GetPattern<TextPattern>();
546 CHECK_NULL_RETURN(textPattern, std::nullopt);
547 auto layoutProperty = textPattern->GetLayoutProperty<TextLayoutProperty>();
548 CHECK_NULL_RETURN(layoutProperty, std::nullopt);
549 return layoutProperty->GetCursorColor();
550 }
551 } // namespace OHOS::Ace::NG
552