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