• 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_field/text_field_select_overlay.h"
17 
18 #include <algorithm>
19 #include <cstdint>
20 
21 #include "base/geometry/ng/rect_t.h"
22 #include "base/memory/ace_type.h"
23 #include "base/utils/utf_helper.h"
24 #include "base/utils/utils.h"
25 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
26 
27 #ifndef ACE_UNITTEST
28 #ifdef ENABLE_STANDARD_INPUT
29 #include "input_method_controller.h"
30 #endif
31 #endif
32 
33 namespace OHOS::Ace::NG {
34 namespace {
35 // uncertainty range when comparing selectedTextBox to contentRect
36 constexpr float BOX_EPSILON = 0.5f;
37 constexpr uint32_t REQUEST_SELECT_ALL = 1 << 1;
38 } // namespace
39 
PreProcessOverlay(const OverlayRequest & request)40 bool TextFieldSelectOverlay::PreProcessOverlay(const OverlayRequest& request)
41 {
42     auto pattern = GetPattern<TextFieldPattern>();
43     CHECK_NULL_RETURN(pattern, false);
44     auto host = pattern->GetHost();
45     CHECK_NULL_RETURN(host, false);
46     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
47     CHECK_NULL_RETURN(layoutProperty, false);
48     bool isHideRightClickMenu = layoutProperty->GetSelectionMenuHiddenValue(false) && IsUsingMouse();
49     bool isFontSizeZero = layoutProperty->HasFontSize() && NearZero(layoutProperty->GetFontSize()->Value());
50     if (isHideRightClickMenu || (isFontSizeZero && !SelectOverlayIsOn())) {
51         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
52             "The selection menu is not displayed cause Font size is zero or selectionMenuHidden is true");
53         return false;
54     }
55     UpdatePattern(request);
56     CHECK_NULL_RETURN(!pattern->IsTransparent(), false);
57     pattern->ShowSelect();
58     SetEnableHandleLevel(true);
59     SetEnableSubWindowMenu(true);
60     CheckEnableContainerModal();
61     return true;
62 }
63 
UpdatePattern(const OverlayRequest & request)64 void TextFieldSelectOverlay::UpdatePattern(const OverlayRequest& request)
65 {
66     if (IsSingleHandle()) {
67         return;
68     }
69     auto pattern = GetPattern<TextFieldPattern>();
70     CHECK_NULL_VOID(pattern);
71     bool isRequestSelectAll = (static_cast<uint32_t>(request.requestCode) & REQUEST_SELECT_ALL) == REQUEST_SELECT_ALL;
72     auto selectController = pattern->GetTextSelectController();
73     if (pattern->IsSelected() && selectController->IsHandleSamePosition()) {
74         SetIsSingleHandle(true);
75         selectController->UpdateCaretIndex(selectController->GetFirstHandleIndex());
76         selectController->UpdateCaretOffset();
77         selectController->MoveCaretToContentRect(selectController->GetCaretIndex());
78     } else if (!IsSingleHandle() && !isRequestSelectAll) {
79         auto rects = pattern->GetTextBoxes();
80         if (!rects.empty() && NearEqual(rects.size(), 1) && NearZero(rects[0].Width())) {
81             SetIsSingleHandle(true);
82             selectController->UpdateCaretIndex(selectController->GetFirstHandleIndex());
83             selectController->UpdateCaretOffset();
84         }
85     }
86 }
87 
OnAfterSelectOverlayShow(bool isCreate)88 void TextFieldSelectOverlay::OnAfterSelectOverlayShow(bool isCreate)
89 {
90     CHECK_NULL_VOID(latestReqeust_);
91     auto manager = GetManager<SelectContentOverlayManager>();
92     CHECK_NULL_VOID(manager);
93     auto pattern = GetPattern<TextFieldPattern>();
94     CHECK_NULL_VOID(pattern);
95     if (latestReqeust_->hideHandle) {
96         manager->HideHandle();
97     }
98     auto selectOverlayInfo = manager->GetSelectOverlayInfo();
99     CHECK_NULL_VOID(selectOverlayInfo);
100     if (!selectOverlayInfo->isUsingMouse) {
101         if (manager->IsHiddenHandle()) {
102             pattern->StartTwinkling();
103         } else {
104             pattern->StopTwinkling();
105         }
106     }
107     manager->MarkInfoChange(DIRTY_SELECT_TEXT | DIRTY_SELECT_AREA);
108     latestReqeust_.reset();
109 }
110 
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)111 void TextFieldSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
112 {
113     BaseTextSelectOverlay::OnCloseOverlay(menuType, reason, info);
114     auto pattern = GetPattern<TextFieldPattern>();
115     CHECK_NULL_VOID(pattern);
116     CloseMagnifier();
117     if (CloseReason::CLOSE_REASON_BACK_PRESSED == reason) {
118         OnResetTextSelection();
119         if (info && info->isSingleHandle) {
120             TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "SingleHandle OnCloseOverlay");
121             pattern->OnBackPressed();
122         }
123     } else if (CloseReason::CLOSE_REASON_HOLD_BY_OTHER == reason) {
124         OnResetTextSelection();
125     }
126     pattern->StopContentScroll();
127     RemoveAvoidKeyboardCallback();
128     if (pattern->GetFloatingCursorVisible()) {
129         pattern->ResetFloatingCursorState();
130         auto host = pattern->GetHost();
131         CHECK_NULL_VOID(host);
132         host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
133     }
134 }
135 
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)136 void TextFieldSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
137 {
138     BaseTextSelectOverlay::OnHandleGlobalTouchEvent(sourceType, touchType);
139     SetLastSourceType(sourceType);
140 }
141 
HandleOnShowMenu()142 void TextFieldSelectOverlay::HandleOnShowMenu()
143 {
144     auto selectArea = GetSelectArea();
145     if (Negative(selectArea.Width()) || Negative(selectArea.Height())) {
146         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "The selected area is not visible.");
147         return;
148     }
149     if (SelectOverlayIsOn()) {
150         auto manager = GetManager<SelectContentOverlayManager>();
151         manager->ShowOptionMenu();
152         return;
153     }
154     auto pattern = GetPattern<TextFieldPattern>();
155     CHECK_NULL_VOID(pattern);
156     SetUsingMouse(lastSourceType_ == SourceType::MOUSE);
157     if (IsUsingMouse()) {
158         auto controller = pattern->GetTextSelectController();
159         SetMouseMenuOffset(controller->GetCaretRect().GetOffset() + pattern->GetParentGlobalOffset());
160     } else {
161         auto isSingleHandle = pattern->GetTextContentController()->IsEmpty() || !pattern->IsSelected();
162         SetIsSingleHandle(isSingleHandle);
163     }
164     ProcessOverlay({ .animation = true });
165 }
166 
GetFirstHandleInfo()167 std::optional<SelectHandleInfo> TextFieldSelectOverlay::GetFirstHandleInfo()
168 {
169     if (IsSingleHandle()) {
170         return std::nullopt;
171     }
172     auto handleRect = GetHandleLocalPaintRect(DragHandleIndex::FIRST);
173     return GetHandleInfo(handleRect);
174 }
175 
GetSecondHandleInfo()176 std::optional<SelectHandleInfo> TextFieldSelectOverlay::GetSecondHandleInfo()
177 {
178     auto handleRect = GetHandleLocalPaintRect(DragHandleIndex::SECOND);
179     return GetHandleInfo(handleRect);
180 }
181 
GetHandleLocalPaintRect(DragHandleIndex dragHandleIndex)182 RectF TextFieldSelectOverlay::GetHandleLocalPaintRect(DragHandleIndex dragHandleIndex)
183 {
184     auto pattern = GetPattern<TextFieldPattern>();
185     CHECK_NULL_RETURN(pattern, RectF());
186     auto controller = pattern->GetTextSelectController();
187     CHECK_NULL_RETURN(controller, RectF());
188     controller->AdjustAllHandlesWithBoundary();
189     if (dragHandleIndex == DragHandleIndex::FIRST) {
190         return controller->GetFirstHandleRect();
191     } else if (dragHandleIndex == DragHandleIndex::SECOND) {
192         if (IsSingleHandle()) {
193             return controller->GetCaretInfo().originalRect;
194         }
195         return controller->GetSecondHandleRect();
196     } else { // DragHandleIndex::NONE
197         return RectF();
198     }
199 }
200 
GetHandleInfo(const RectF & handlePaintRect)201 std::optional<SelectHandleInfo> TextFieldSelectOverlay::GetHandleInfo(const RectF& handlePaintRect)
202 {
203     auto handleRect = handlePaintRect;
204     SelectHandleInfo handleInfo;
205     handleInfo.localPaintRect = handlePaintRect;
206     handleRect.SetOffset(handleRect.GetOffset() + GetPaintOffsetWithoutTransform());
207     handleInfo.paintRect = handleRect;
208     handleInfo.isShow = CheckHandleVisible(handleRect);
209 
210     SetTransformPaintInfo(handleInfo, handlePaintRect);
211     return handleInfo;
212 }
213 
CheckHandleVisible(const RectF & handlePaintRect)214 bool TextFieldSelectOverlay::CheckHandleVisible(const RectF& handlePaintRect)
215 {
216     auto pattern = GetPattern<TextFieldPattern>();
217     CHECK_NULL_RETURN(pattern, false);
218     // use global offset.
219     auto contentRect = pattern->GetContentRect();
220     auto visibleRect = GetVisibleContentRect();
221     // revert to original offset.
222     auto paintRect = handlePaintRect;
223     paintRect.SetOffset(OffsetF(paintRect.GetX() + paintRect.Width() / 2.0f, paintRect.GetY()));
224     if (!pattern->IsTextArea()) {
225         auto verticalEpsilon = std::max(0.0f, paintRect.Height() - contentRect.Height());
226         return GreatOrEqual(paintRect.Top() + verticalEpsilon, visibleRect.Top()) &&
227                LessOrEqual(paintRect.Bottom() - verticalEpsilon, visibleRect.Bottom()) &&
228                LessOrEqual(paintRect.Left() - paintRect.Width() - BOX_EPSILON, visibleRect.Right()) &&
229                GreatOrEqual(paintRect.Right(), visibleRect.Left());
230     }
231     PointF bottomPoint = { paintRect.Left(), paintRect.Bottom() - BOX_EPSILON };
232     PointF topPoint = { paintRect.Left(), paintRect.Top() + BOX_EPSILON };
233     visibleRect.SetLeft(visibleRect.GetX() - BOX_EPSILON);
234     visibleRect.SetWidth(visibleRect.Width() + 2.0f * BOX_EPSILON);
235     visibleRect.SetTop(visibleRect.GetY() - BOX_EPSILON);
236     visibleRect.SetHeight(visibleRect.Height() + 2.0f * BOX_EPSILON);
237     return visibleRect.IsInRegion(bottomPoint) && visibleRect.IsInRegion(topPoint);
238 }
239 
OnResetTextSelection()240 void TextFieldSelectOverlay::OnResetTextSelection()
241 {
242     auto pattern = GetPattern<TextFieldPattern>();
243     CHECK_NULL_VOID(pattern);
244     pattern->SetCaretPosition(pattern->GetTextSelectController()->GetEndIndex());
245 }
246 
AfterCloseOverlay()247 void TextFieldSelectOverlay::AfterCloseOverlay()
248 {
249     CloseMagnifier();
250 }
251 
CloseMagnifier()252 void TextFieldSelectOverlay::CloseMagnifier()
253 {
254     auto pattern = GetPattern<TextFieldPattern>();
255     CHECK_NULL_VOID(pattern);
256     if (pattern->GetMagnifierController()->GetShowMagnifier()) {
257         pattern->GetMagnifierController()->RemoveMagnifierFrameNode();
258     }
259 }
260 
OnUpdateMenuInfo(SelectMenuInfo & menuInfo,SelectOverlayDirtyFlag dirtyFlag)261 void TextFieldSelectOverlay::OnUpdateMenuInfo(SelectMenuInfo& menuInfo, SelectOverlayDirtyFlag dirtyFlag)
262 {
263     auto pattern = GetPattern<TextFieldPattern>();
264     CHECK_NULL_VOID(pattern);
265     auto host = pattern->GetHost();
266     CHECK_NULL_VOID(host);
267     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
268     CHECK_NULL_VOID(layoutProperty);
269     auto hasText = pattern->HasText();
270     if ((dirtyFlag & DIRTY_COPY_ALL_ITEM) == DIRTY_COPY_ALL_ITEM) {
271         menuInfo.showCopyAll = hasText && !pattern->IsSelectAll();
272         return;
273     }
274     bool isHideSelectionMenu = layoutProperty->GetSelectionMenuHiddenValue(false);
275 #if defined(ENABLE_STANDARD_INPUT)
276     auto inputMethod = MiscServices::InputMethodController::GetInstance();
277     auto isSupportCameraInput = inputMethod &&
278                                 inputMethod->IsInputTypeSupported(MiscServices::InputType::CAMERA_INPUT) &&
279                                 !pattern->IsInPasswordMode();
280 #else
281     auto isSupportCameraInput = false;
282 #endif
283     menuInfo.showCameraInput = !pattern->IsSelected() && isSupportCameraInput && !pattern->HasCustomKeyboard();
284     if (IsUsingMouse()) {
285         auto manager = SelectContentOverlayManager::GetOverlayManager();
286         CHECK_NULL_VOID(manager);
287         menuInfo.menuIsShow = !isHideSelectionMenu || manager->IsOpen();
288     } else {
289         menuInfo.menuIsShow = (hasText || IsShowPaste() || menuInfo.showCameraInput) &&
290             !isHideSelectionMenu && IsShowMenu();
291     }
292     menuInfo.menuDisable = isHideSelectionMenu;
293     menuInfo.showPaste = IsShowPaste();
294     menuInfo.menuType = IsUsingMouse() ? OptionMenuType::MOUSE_MENU : OptionMenuType::TOUCH_MENU;
295     menuInfo.showCopy = hasText && pattern->AllowCopy() && pattern->IsSelected();
296     menuInfo.showCut = menuInfo.showCopy;
297     menuInfo.showCopyAll = hasText && !pattern->IsSelectAll();
298     menuInfo.showTranslate = menuInfo.showCopy && pattern->IsShowTranslate() && IsNeedMenuTranslate();
299     menuInfo.showSearch = menuInfo.showCopy && pattern->IsShowSearch() && IsNeedMenuSearch();
300     menuInfo.showShare = menuInfo.showCopy && IsSupportMenuShare() && IsNeedMenuShare();
301     menuInfo.showAIWrite = pattern->IsShowAIWrite() && pattern->IsSelected();
302 }
303 
OnUpdateSelectOverlayInfo(SelectOverlayInfo & overlayInfo,int32_t requestCode)304 void TextFieldSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo& overlayInfo, int32_t requestCode)
305 {
306     overlayInfo.clipHandleDrawRect = IsClipHandleWithViewPort();
307     BaseTextSelectOverlay::OnUpdateSelectOverlayInfo(overlayInfo, requestCode);
308     auto textFieldPattern = GetPattern<TextFieldPattern>();
309     CHECK_NULL_VOID(textFieldPattern);
310     auto paintProperty = textFieldPattern->GetPaintProperty<TextFieldPaintProperty>();
311     CHECK_NULL_VOID(paintProperty);
312     overlayInfo.handlerColor = paintProperty->GetCursorColor();
313     OnUpdateOnCreateMenuCallback(overlayInfo);
314     auto layoutProperty =
315         DynamicCast<TextFieldLayoutProperty>(textFieldPattern->GetLayoutProperty<TextFieldLayoutProperty>());
316     CHECK_NULL_VOID(layoutProperty);
317     if (layoutProperty->HasMaxLines()) {
318         uint32_t maxLine = layoutProperty->GetMaxLinesValue(Infinity<uint32_t>());
319         overlayInfo.isSingleLine = (maxLine == 1);
320     }
321     if (!textFieldPattern->IsTextArea()) {
322         overlayInfo.checkHandleReverse = [](const RectF& first, const RectF& second) {
323             return GreatNotEqual(first.Left(), second.Left());
324         };
325     }
326 }
327 
GetSelectAreaFromRects(SelectRectsType pos)328 RectF TextFieldSelectOverlay::GetSelectAreaFromRects(SelectRectsType pos)
329 {
330     auto pattern = GetPattern<TextFieldPattern>();
331     CHECK_NULL_RETURN(pattern, {});
332     auto host = pattern->GetHost();
333     CHECK_NULL_RETURN(host, {});
334     auto selectRects = pattern->GetTextBoxes();
335     RectF res(pattern->GetCaretRect());
336     auto textPaintOffset = host->GetTransformRelativeOffset();
337     if (selectRects.empty()) {
338         res.SetOffset(res.GetOffset() + textPaintOffset);
339     } else {
340         auto contentRect = pattern->GetContentRect();
341         auto textRect = pattern->GetTextRect();
342         if (pos == SelectRectsType::LEFT_TOP_POINT) {
343             selectRects.erase(std::next(selectRects.begin()), selectRects.end());
344             selectRects.front().SetSize({0, 0});
345         } else if (pos == SelectRectsType::RIGHT_BOTTOM_POINT) {
346             selectRects.erase(selectRects.begin(), std::prev(selectRects.end()));
347             selectRects.front().SetRect({selectRects.front().Right(), selectRects.front().Bottom()}, {0, 0});
348         }
349         res = MergeSelectedBoxes(selectRects, contentRect, textRect, textPaintOffset);
350         if (NearZero(res.Width())) {
351             pattern->AdjustSelectedBlankLineWidth(res);
352         }
353     }
354     auto globalContentRect = GetVisibleContentRect(true);
355     auto intersectRect = res.IntersectRectT(globalContentRect);
356     if (hasTransform_) {
357         intersectRect.SetOffset(intersectRect.GetOffset() - textPaintOffset);
358         GetGlobalRectWithTransform(intersectRect);
359     }
360     ApplySelectAreaWithKeyboard(intersectRect);
361     return intersectRect;
362 }
363 
GetSelectedText()364 std::string TextFieldSelectOverlay::GetSelectedText()
365 {
366     auto pattern = GetPattern<TextFieldPattern>();
367     CHECK_NULL_RETURN(pattern, "");
368     auto textSelectController = pattern->GetTextSelectController();
369     CHECK_NULL_RETURN(textSelectController, "");
370     auto start = textSelectController->GetStartIndex();
371     auto end = textSelectController->GetEndIndex();
372     return UtfUtils::Str16DebugToStr8(pattern->GetTextContentController()->GetSelectedValue(start, end));
373 }
374 
OnMenuItemAction(OptionMenuActionId id,OptionMenuType type)375 void TextFieldSelectOverlay::OnMenuItemAction(OptionMenuActionId id, OptionMenuType type)
376 {
377     auto pattern = GetPattern<TextFieldPattern>();
378     CHECK_NULL_VOID(pattern);
379     TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Handle overlay menu, men id %{public}d, menu type %{public}d", id, type);
380     switch (id) {
381         case OptionMenuActionId::COPY:
382             pattern->HandleOnCopy();
383             return;
384         case OptionMenuActionId::CUT:
385             pattern->HandleOnCut();
386             return;
387         case OptionMenuActionId::SELECT_ALL:
388             pattern->HandleOnSelectAll(type == OptionMenuType::MOUSE_MENU, false, true);
389             return;
390         case OptionMenuActionId::PASTE:
391             pattern->HandleOnPaste();
392             return;
393         case OptionMenuActionId::TRANSLATE:
394             HandleOnTranslate();
395             return;
396         case OptionMenuActionId::SEARCH:
397             HandleOnSearch();
398             return;
399         case OptionMenuActionId::SHARE:
400             HandleOnShare();
401             return;
402         case OptionMenuActionId::CAMERA_INPUT:
403             pattern->HandleOnCameraInput();
404             return;
405         case OptionMenuActionId::AI_WRITE:
406             pattern->HandleOnAIWrite();
407             return;
408         default:
409             return;
410     }
411 }
412 
GetTextAreaCaretPosition(const OffsetF & localOffset)413 int32_t TextFieldSelectOverlay::GetTextAreaCaretPosition(const OffsetF& localOffset)
414 {
415     auto pattern = GetPattern<TextFieldPattern>();
416     auto contentRect = pattern->GetContentRect();
417     auto paddingLeft = pattern->GetPaddingLeft();
418     auto textRect = pattern->GetTextRect();
419     Offset offset;
420     if (LessNotEqual(localOffset.GetY(), contentRect.GetY())) {
421         offset = Offset(localOffset.GetX() - paddingLeft, contentRect.GetY() - textRect.GetY());
422     } else if (GreatOrEqual(localOffset.GetY(), contentRect.GetY() + contentRect.Height())) {
423         offset = Offset(localOffset.GetX() - paddingLeft, contentRect.GetY() + contentRect.Height() - textRect.GetY());
424     } else {
425         offset = Offset(localOffset.GetX() - paddingLeft, localOffset.GetY() - textRect.GetY());
426     }
427     return pattern->ConvertTouchOffsetToCaretPosition(offset);
428 }
429 
GetTextInputCaretPosition(const OffsetF & localOffset,bool isFirst)430 int32_t TextFieldSelectOverlay::GetTextInputCaretPosition(const OffsetF& localOffset, bool isFirst)
431 {
432     auto pattern = GetPattern<TextFieldPattern>();
433     auto contentRect = pattern->GetContentRect();
434     auto selectController = pattern->GetTextSelectController();
435     auto wideText = pattern->GetTextUtf16Value();
436     if (LessNotEqual(localOffset.GetX(), contentRect.GetX())) {
437         auto index = selectController->GetStartIndex();
438         if (!SelectOverlayIsOn()) {
439             return index;
440         }
441         if ((!isFirst && !IsHandleReverse()) || (isFirst && IsHandleReverse())) {
442             index = selectController->GetEndIndex();
443         }
444         return index;
445     }
446     if (GreatOrEqual(localOffset.GetX(), contentRect.GetX() + contentRect.Width())) {
447         auto index = selectController->GetEndIndex();
448         if (!SelectOverlayIsOn()) {
449             return index;
450         }
451         if ((isFirst && !IsHandleReverse()) || (!isFirst && IsHandleReverse())) {
452             index = selectController->GetStartIndex();
453         }
454         return index;
455     }
456     Offset offset(localOffset.GetX() - pattern->GetTextRect().GetX(), 0.0f);
457     return pattern->ConvertTouchOffsetToCaretPosition(offset);
458 }
459 
GetCaretPositionOnHandleMove(const OffsetF & localOffset,bool isFirst)460 int32_t TextFieldSelectOverlay::GetCaretPositionOnHandleMove(const OffsetF& localOffset, bool isFirst)
461 {
462     auto pattern = GetPattern<TextFieldPattern>();
463     CHECK_NULL_RETURN(pattern, 0);
464     if (pattern->IsTextArea()) {
465         return GetTextAreaCaretPosition(localOffset);
466     }
467     return GetTextInputCaretPosition(localOffset, isFirst);
468 }
469 
OnHandleMove(const RectF & handleRect,bool isFirst)470 void TextFieldSelectOverlay::OnHandleMove(const RectF& handleRect, bool isFirst)
471 {
472     auto pattern = GetPattern<TextFieldPattern>();
473     CHECK_NULL_VOID(pattern);
474     CHECK_NULL_VOID(pattern->HasText());
475     auto localOffset = handleRect.GetOffset();
476     localOffset.SetY(localOffset.GetY() + handleRect.Height() / 2.0f);
477     if (IsOverlayMode()) {
478         localOffset = localOffset - GetPaintOffsetWithoutTransform();
479     }
480     auto selectController = pattern->GetTextSelectController();
481     CHECK_NULL_VOID(selectController);
482     int32_t startIndex = selectController->GetFirstHandleIndex();
483     int32_t endIndex = selectController->GetSecondHandleIndex();
484     TriggerContentToScroll(localOffset, false);
485     if (IsSingleHandle()) {
486         auto isScrolling = pattern->GetContentScrollerIsScrolling();
487         auto contentRect = pattern->GetContentRect();
488         auto touchCaretX = std::clamp(localOffset.GetX(), contentRect.Left(), contentRect.Right());
489         // 1/4 line height.
490         auto yOffset = pattern->PreferredLineHeight() * 0.25f;
491         auto touchCaretY = std::clamp(localOffset.GetY(), contentRect.Top() + yOffset, contentRect.Bottom() - yOffset);
492         selectController->UpdateCaretInfoByOffset(!isScrolling ? Offset(touchCaretX, touchCaretY) :
493             Offset(localOffset.GetX(), localOffset.GetY()), !isScrolling, true);
494         pattern->ShowCaretAndStopTwinkling();
495     } else {
496         auto position = GetCaretPositionOnHandleMove(localOffset, isFirst);
497         pattern->StartVibratorByIndexChange(position, isFirst ? startIndex : endIndex);
498         if (isFirst) {
499             selectController->MoveFirstHandleToContentRect(position, false, false);
500             UpdateSecondHandleOffset();
501         } else {
502             selectController->MoveSecondHandleToContentRect(position, false, false);
503             UpdateFirstHandleOffset();
504         }
505     }
506     if (pattern->GetMagnifierController() && SelectOverlayIsOn()) {
507         if (IsSingleHandle()) {
508             pattern->SetMagnifierLocalOffsetToFloatingCaretPos();
509         } else {
510             auto magnifierLocalOffset = OffsetF(localOffset.GetX(), localOffset.GetY());
511             if (IsOverlayMode()) {
512                 GetLocalPointWithTransform(magnifierLocalOffset);
513             }
514             pattern->GetMagnifierController()->SetLocalOffset(magnifierLocalOffset);
515         }
516     }
517     pattern->PlayScrollBarAppearAnimation();
518     auto tmpHost = pattern->GetHost();
519     CHECK_NULL_VOID(tmpHost);
520     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
521 }
522 
OnHandleMoveDone(const RectF & rect,bool isFirst)523 void TextFieldSelectOverlay::OnHandleMoveDone(const RectF& rect, bool isFirst)
524 {
525     BaseTextSelectOverlay::OnHandleMoveDone(rect, isFirst);
526     auto pattern = GetPattern<TextFieldPattern>();
527     CHECK_NULL_VOID(pattern);
528     auto host = pattern->GetHost();
529     CHECK_NULL_VOID(host);
530     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
531     CHECK_NULL_VOID(layoutProperty);
532     auto overlayManager = GetManager<SelectContentOverlayManager>();
533     CHECK_NULL_VOID(overlayManager);
534     if (!layoutProperty->GetSelectionMenuHiddenValue(false)) {
535         overlayManager->MarkInfoChange(DIRTY_COPY_ALL_ITEM);
536     }
537     if (pattern->GetMagnifierController()) {
538         pattern->GetMagnifierController()->RemoveMagnifierFrameNode();
539     }
540     auto selectController = pattern->GetTextSelectController();
541     TriggerContentToScroll(OffsetF(), true);
542     overlayManager->ShowOptionMenu();
543     if (!IsSingleHandle()) {
544         if (selectController->GetFirstHandleIndex() == selectController->GetSecondHandleIndex()) {
545             CloseOverlay(true, CloseReason::CLOSE_REASON_NORMAL);
546             pattern->StartTwinkling();
547             selectController->MoveCaretToContentRect(pattern->GetCaretIndex());
548         } else {
549             if (isFirst) {
550                 selectController->MoveFirstHandleToContentRect(selectController->GetFirstHandleIndex(), false);
551             } else {
552                 selectController->MoveSecondHandleToContentRect(selectController->GetSecondHandleIndex(), false);
553             }
554             overlayManager->MarkInfoChange(DIRTY_DOUBLE_HANDLE | DIRTY_SELECT_AREA | DIRTY_SELECT_TEXT);
555         }
556     } else {
557         pattern->StopTwinkling();
558         // single handle use caret offset.
559         auto caretRect = selectController->GetCaretRect();
560         selectController->UpdateCaretInfoByOffset(
561             Offset(caretRect.Left(), caretRect.Top() + caretRect.Height() / 2.0f));
562         overlayManager->MarkInfoChange(DIRTY_SECOND_HANDLE);
563     }
564     overlayManager->SetHandleCircleIsShow(isFirst, true);
565     if (IsSingleHandle()) {
566         overlayManager->SetIsHandleLineShow(true);
567     }
568     pattern->ScheduleDisappearDelayTask();
569     pattern->UpdateCaretInfoToController();
570     pattern->FloatingCaretLand();
571     auto tmpHost = pattern->GetHost();
572     CHECK_NULL_VOID(tmpHost);
573     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
574 }
575 
ProcessSelectAllOverlay(const OverlayRequest & request)576 void TextFieldSelectOverlay::ProcessSelectAllOverlay(const OverlayRequest& request)
577 {
578     OverlayRequest newRequest = request;
579     newRequest.requestCode = static_cast<uint32_t>(newRequest.requestCode) | REQUEST_SELECT_ALL;
580     ProcessOverlay(newRequest);
581 }
582 
OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)583 void TextFieldSelectOverlay::OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)
584 {
585     if (IsAncestorNodeGeometryChange(flag) || IsAncestorNodeTransformChange(flag)) {
586         UpdateAllHandlesOffset();
587     }
588     BaseTextSelectOverlay::OnAncestorNodeChanged(flag);
589 }
590 
OnHandleLevelModeChanged(HandleLevelMode mode)591 void TextFieldSelectOverlay::OnHandleLevelModeChanged(HandleLevelMode mode)
592 {
593     if (handleLevelMode_ != mode && mode == HandleLevelMode::OVERLAY) {
594         auto pattern = GetPattern<TextFieldPattern>();
595         if (pattern) {
596             pattern->UpdateParentGlobalOffset();
597             pattern->GetTextSelectController()->CalculateHandleOffset();
598         }
599     }
600     BaseTextSelectOverlay::OnHandleLevelModeChanged(mode);
601 }
602 
OnOverlayClick(const GestureEvent & event,bool isFirst)603 void TextFieldSelectOverlay::OnOverlayClick(const GestureEvent& event, bool isFirst)
604 {
605     auto pattern = GetPattern<TextFieldPattern>();
606     CHECK_NULL_VOID(pattern);
607     auto recognizer = pattern->GetMultipleClickRecognizer();
608     CHECK_NULL_VOID(recognizer);
609     if (recognizer->IsValidClick(event)) {
610         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield overlayClick multiple click recognizer is running.");
611         auto overlayEvent = event;
612         overlayEvent.SetLocalLocation(recognizer->GetBeginLocalLocation());
613         overlayEvent.SetGlobalLocation(recognizer->GetBeginGlobalLocation());
614         pattern->HandleClickEvent(overlayEvent);
615     } else if (!IsSingleHandle()) {
616         if (pattern->HandleBetweenSelectedPosition(event)) {
617             TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield HandleBetweenSelectedPosition");
618             return;
619         }
620         auto selectController = pattern->GetTextSelectController();
621         auto index = isFirst ? selectController->GetFirstHandleIndex() : selectController->GetSecondHandleIndex();
622         pattern->HandleSetSelection(index, index, false);
623         pattern->StartTwinkling();
624     } else {
625         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield overlayClick");
626     }
627 }
628 
OnHandleIsHidden()629 void TextFieldSelectOverlay::OnHandleIsHidden()
630 {
631     auto pattern = GetPattern<TextFieldPattern>();
632     CHECK_NULL_VOID(pattern);
633     pattern->StartTwinkling();
634 }
635 
OnHandleMoveStart(const GestureEvent & event,bool isFirst)636 void TextFieldSelectOverlay::OnHandleMoveStart(const GestureEvent& event, bool isFirst)
637 {
638     BaseTextSelectOverlay::OnHandleMoveStart(event, isFirst);
639     auto manager = GetManager<SelectContentOverlayManager>();
640     CHECK_NULL_VOID(manager);
641     auto pattern = GetPattern<TextFieldPattern>();
642     CHECK_NULL_VOID(pattern);
643     manager->SetHandleCircleIsShow(isFirst, false);
644     if (IsSingleHandle()) {
645         manager->SetIsHandleLineShow(false);
646         if (!pattern->HasText()) {
647             pattern->StartTwinkling();
648         }
649     }
650     pattern->StopContentScroll();
651 }
652 
TriggerContentToScroll(const OffsetF & localOffset,bool isEnd)653 void TextFieldSelectOverlay::TriggerContentToScroll(const OffsetF& localOffset, bool isEnd)
654 {
655     auto pattern = GetPattern<TextFieldPattern>();
656     CHECK_NULL_VOID(pattern);
657     if (pattern->GetScrollEnabled()) {
658         if (isEnd) {
659             pattern->StopContentScroll();
660         } else {
661             pattern->UpdateContentScroller(Offset(localOffset.GetX(), localOffset.GetY()));
662         }
663     }
664 }
665 
GetHandleColor()666 std::optional<Color> TextFieldSelectOverlay::GetHandleColor()
667 {
668     auto textFieldPattern = GetPattern<TextFieldPattern>();
669     CHECK_NULL_RETURN(textFieldPattern, std::nullopt);
670     auto paintProperty = textFieldPattern->GetPaintProperty<TextFieldPaintProperty>();
671     CHECK_NULL_RETURN(paintProperty, std::nullopt);
672     return paintProperty->GetCursorColor();
673 }
674 
UpdateAllHandlesOffset()675 void TextFieldSelectOverlay::UpdateAllHandlesOffset()
676 {
677     if (dragHandleIndex_ == DragHandleIndex::NONE) {
678         BaseTextSelectOverlay::UpdateAllHandlesOffset();
679     } else if (dragHandleIndex_ == DragHandleIndex::FIRST) {
680         BaseTextSelectOverlay::UpdateSecondHandleOffset();
681     } else {
682         BaseTextSelectOverlay::UpdateFirstHandleOffset();
683     }
684 }
685 
UpdateFirstHandleOffset()686 void TextFieldSelectOverlay::UpdateFirstHandleOffset()
687 {
688     if (dragHandleIndex_ == DragHandleIndex::FIRST) {
689         return;
690     }
691     BaseTextSelectOverlay::UpdateFirstHandleOffset();
692 }
693 
UpdateSecondHandleOffset()694 void TextFieldSelectOverlay::UpdateSecondHandleOffset()
695 {
696     if (dragHandleIndex_ == DragHandleIndex::SECOND) {
697         return;
698     }
699     BaseTextSelectOverlay::UpdateSecondHandleOffset();
700 }
701 
AllowTranslate()702 bool TextFieldSelectOverlay::AllowTranslate()
703 {
704     auto pattern = GetPattern<TextFieldPattern>();
705     CHECK_NULL_RETURN(pattern, false);
706     return pattern->AllowCopy();
707 }
708 
AllowSearch()709 bool TextFieldSelectOverlay::AllowSearch()
710 {
711     auto pattern = GetPattern<TextFieldPattern>();
712     CHECK_NULL_RETURN(pattern, false);
713     return pattern->AllowCopy();
714 }
715 
AllowShare()716 bool TextFieldSelectOverlay::AllowShare()
717 {
718     auto pattern = GetPattern<TextFieldPattern>();
719     CHECK_NULL_RETURN(pattern, false);
720     return pattern->AllowCopy();
721 }
722 
IsStopBackPress() const723 bool TextFieldSelectOverlay::IsStopBackPress() const
724 {
725     auto pattern = GetPattern<TextFieldPattern>();
726     CHECK_NULL_RETURN(pattern, true);
727     return pattern->IsStopBackPress();
728 }
729 } // namespace OHOS::Ace::NG
730