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