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/utils.h"
24 #include "core/components_ng/manager/select_content_overlay/select_content_overlay_manager.h"
25 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
26 #include "core/components_ng/pattern/text_field/text_field_paint_property.h"
27 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
28 #include "core/event/ace_events.h"
29 #include "core/event/touch_event.h"
30 
31 #ifndef ACE_UNITTEST
32 #ifdef ENABLE_STANDARD_INPUT
33 #include "input_method_controller.h"
34 #endif
35 #endif
36 
37 namespace OHOS::Ace::NG {
38 namespace {
39 // uncertainty range when comparing selectedTextBox to contentRect
40 constexpr float BOX_EPSILON = 0.5f;
41 constexpr uint32_t REQUEST_SELECT_ALL = 1 << 1;
42 } // namespace
43 
PreProcessOverlay(const OverlayRequest & request)44 bool TextFieldSelectOverlay::PreProcessOverlay(const OverlayRequest& request)
45 {
46     auto pattern = GetPattern<TextFieldPattern>();
47     CHECK_NULL_RETURN(pattern, false);
48     auto host = pattern->GetHost();
49     CHECK_NULL_RETURN(host, false);
50     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
51     CHECK_NULL_RETURN(layoutProperty, false);
52     bool isHideRightClickMenu = layoutProperty->GetSelectionMenuHiddenValue(false) && IsUsingMouse();
53     bool isFontSizeZero = layoutProperty->HasFontSize() && NearZero(layoutProperty->GetFontSize()->Value());
54     if (isHideRightClickMenu || isFontSizeZero) {
55         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD,
56             "The selection menu is not displayed cause Font size is zero or selectionMenuHidden is true");
57         return false;
58     }
59     UpdatePattern(request);
60     CHECK_NULL_RETURN(!pattern->IsTransparent(), false);
61     pattern->ShowSelect();
62     SetEnableHandleLevel(true);
63     return true;
64 }
65 
UpdatePattern(const OverlayRequest & request)66 void TextFieldSelectOverlay::UpdatePattern(const OverlayRequest& request)
67 {
68     auto pattern = GetPattern<TextFieldPattern>();
69     CHECK_NULL_VOID(pattern);
70     bool isRequestSelectAll = (static_cast<uint32_t>(request.requestCode) & REQUEST_SELECT_ALL) == REQUEST_SELECT_ALL;
71     auto selectController = pattern->GetTextSelectController();
72     if ((static_cast<uint32_t>(request.requestCode) & REQUEST_SELECT_ALL) != REQUEST_SELECT_ALL) {
73         selectController->CalculateHandleOffset();
74     }
75     if (pattern->IsSelected() && selectController->IsHandleSamePosition()) {
76         SetIsSingleHandle(true);
77         selectController->UpdateCaretIndex(selectController->GetFirstHandleIndex());
78         selectController->UpdateCaretOffset();
79         selectController->MoveCaretToContentRect(selectController->GetCaretIndex());
80     } else if (!IsSingleHandle() && !isRequestSelectAll) {
81         auto rects = pattern->GetTextBoxes();
82         if (!rects.empty() && NearEqual(rects.size(), 1) && NearZero(rects[0].Width())) {
83             SetIsSingleHandle(true);
84             selectController->UpdateCaretIndex(selectController->GetFirstHandleIndex());
85             selectController->UpdateCaretOffset();
86         }
87     }
88     if (IsSingleHandle()) {
89         pattern->StartTwinkling();
90     }
91 }
92 
OnAfterSelectOverlayShow(bool isCreate)93 void TextFieldSelectOverlay::OnAfterSelectOverlayShow(bool isCreate)
94 {
95     CHECK_NULL_VOID(latestReqeust_);
96     auto manager = GetManager<SelectContentOverlayManager>();
97     CHECK_NULL_VOID(manager);
98     if (latestReqeust_->hideHandle) {
99         manager->HideHandle();
100     }
101     manager->MarkInfoChange(DIRTY_SELECT_TEXT);
102     latestReqeust_.reset();
103 }
104 
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)105 void TextFieldSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
106 {
107     BaseTextSelectOverlay::OnCloseOverlay(menuType, reason, info);
108     auto pattern = GetPattern<TextFieldPattern>();
109     CHECK_NULL_VOID(pattern);
110     CloseMagnifier();
111     if (CloseReason::CLOSE_REASON_BACK_PRESSED == reason) {
112         OnResetTextSelection();
113         if (info && info->isSingleHandle) {
114             pattern->OnBackPressed();
115         }
116     }
117 }
118 
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)119 void TextFieldSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
120 {
121     BaseTextSelectOverlay::OnHandleGlobalTouchEvent(sourceType, touchType);
122     SetLastSourceType(sourceType);
123 }
124 
HandleOnShowMenu()125 void TextFieldSelectOverlay::HandleOnShowMenu()
126 {
127     auto selectArea = GetSelectArea();
128     if (Negative(selectArea.Width()) || Negative(selectArea.Height())) {
129         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "The selected area is not visible.");
130         return;
131     }
132     if (SelectOverlayIsOn()) {
133         auto manager = GetManager<SelectContentOverlayManager>();
134         manager->ShowOptionMenu();
135         return;
136     }
137     auto pattern = GetPattern<TextFieldPattern>();
138     CHECK_NULL_VOID(pattern);
139     SetUsingMouse(lastSourceType_ == SourceType::MOUSE);
140     if (IsUsingMouse()) {
141         auto controller = pattern->GetTextSelectController();
142         SetMouseMenuOffset(controller->GetCaretRect().GetOffset() + pattern->GetParentGlobalOffset());
143     } else {
144         auto isSingleHandle = pattern->GetTextContentController()->IsEmpty() || !pattern->IsSelected();
145         SetIsSingleHandle(isSingleHandle);
146     }
147     ProcessOverlay({ .animation = true });
148 }
149 
GetFirstHandleInfo()150 std::optional<SelectHandleInfo> TextFieldSelectOverlay::GetFirstHandleInfo()
151 {
152     if (IsSingleHandle()) {
153         return std::nullopt;
154     }
155     auto handleRect = GetFirstHandleLocalPaintRect();
156     return GetHandleInfo(handleRect);
157 }
158 
GetSecondHandleInfo()159 std::optional<SelectHandleInfo> TextFieldSelectOverlay::GetSecondHandleInfo()
160 {
161     auto handleRect = GetSecondHandleLocalPaintRect();
162     return GetHandleInfo(handleRect);
163 }
164 
GetFirstHandleLocalPaintRect()165 RectF TextFieldSelectOverlay::GetFirstHandleLocalPaintRect()
166 {
167     auto pattern = GetPattern<TextFieldPattern>();
168     CHECK_NULL_RETURN(pattern, RectF());
169     auto controller = pattern->GetTextSelectController();
170     CHECK_NULL_RETURN(controller, RectF());
171     return controller->GetFirstHandleRect();
172 }
173 
GetSecondHandleLocalPaintRect()174 RectF TextFieldSelectOverlay::GetSecondHandleLocalPaintRect()
175 {
176     auto pattern = GetPattern<TextFieldPattern>();
177     CHECK_NULL_RETURN(pattern, RectF());
178     auto controller = pattern->GetTextSelectController();
179     CHECK_NULL_RETURN(controller, RectF());
180     if (IsSingleHandle()) {
181         return controller->GetCaretRect();
182     }
183     auto handleRect = controller->GetSecondHandleRect();
184     auto contentHeight = pattern->GetTextContentRect().Height();
185     auto handleHeight = std::min(handleRect.Height(), contentHeight);
186     handleRect.SetHeight(handleHeight);
187     return handleRect;
188 }
189 
GetHandleInfo(const RectF & handlePaintRect)190 std::optional<SelectHandleInfo> TextFieldSelectOverlay::GetHandleInfo(const RectF& handlePaintRect)
191 {
192     auto handleRect = handlePaintRect;
193     SelectHandleInfo handleInfo;
194     handleInfo.localPaintRect = handlePaintRect;
195     handleRect.SetOffset(handleRect.GetOffset() + GetPaintOffsetWithoutTransform());
196     handleInfo.paintRect = handleRect;
197     handleInfo.isShow = CheckHandleVisible(handleRect);
198 
199     SetTransformPaintInfo(handleInfo, handlePaintRect);
200     return handleInfo;
201 }
202 
CheckHandleVisible(const RectF & handlePaintRect)203 bool TextFieldSelectOverlay::CheckHandleVisible(const RectF& handlePaintRect)
204 {
205     auto pattern = GetPattern<TextFieldPattern>();
206     CHECK_NULL_RETURN(pattern, false);
207     // use global offset.
208     auto contentRect = pattern->GetContentRect();
209     auto visibleRect = GetVisibleContentRect();
210     // revert to original offset.
211     auto paintRect = handlePaintRect;
212     paintRect.SetOffset(OffsetF(paintRect.GetX() + paintRect.Width() / 2.0f, paintRect.GetY()));
213     if (!pattern->IsTextArea()) {
214         auto verticalEpsilon = std::max(0.0f, paintRect.Height() - contentRect.Height());
215         return GreatOrEqual(paintRect.Top() + verticalEpsilon, visibleRect.Top()) &&
216                LessOrEqual(paintRect.Bottom() - verticalEpsilon, visibleRect.Bottom()) &&
217                LessOrEqual(paintRect.Left() - paintRect.Width() - BOX_EPSILON, visibleRect.Right()) &&
218                GreatOrEqual(paintRect.Right(), visibleRect.Left());
219     }
220     PointF bottomPoint = { paintRect.Left(), paintRect.Bottom() - BOX_EPSILON };
221     PointF topPoint = { paintRect.Left(), paintRect.Top() + BOX_EPSILON };
222     visibleRect.SetLeft(visibleRect.GetX() - BOX_EPSILON);
223     visibleRect.SetWidth(visibleRect.Width() + 2.0f * BOX_EPSILON);
224     visibleRect.SetTop(visibleRect.GetY() - BOX_EPSILON);
225     visibleRect.SetHeight(visibleRect.Height() + 2.0f * BOX_EPSILON);
226     return visibleRect.IsInRegion(bottomPoint) && visibleRect.IsInRegion(topPoint);
227 }
228 
OnResetTextSelection()229 void TextFieldSelectOverlay::OnResetTextSelection()
230 {
231     auto pattern = GetPattern<TextFieldPattern>();
232     CHECK_NULL_VOID(pattern);
233     pattern->SetCaretPosition(pattern->GetTextSelectController()->GetEndIndex());
234 }
235 
AfterCloseOverlay()236 void TextFieldSelectOverlay::AfterCloseOverlay()
237 {
238     CloseMagnifier();
239 }
240 
CloseMagnifier()241 void TextFieldSelectOverlay::CloseMagnifier()
242 {
243     auto pattern = GetPattern<TextFieldPattern>();
244     CHECK_NULL_VOID(pattern);
245     if (pattern->GetMagnifierController()->GetShowMagnifier()) {
246         pattern->GetMagnifierController()->RemoveMagnifierFrameNode();
247     }
248 }
249 
OnUpdateMenuInfo(SelectMenuInfo & menuInfo,SelectOverlayDirtyFlag dirtyFlag)250 void TextFieldSelectOverlay::OnUpdateMenuInfo(SelectMenuInfo& menuInfo, SelectOverlayDirtyFlag dirtyFlag)
251 {
252     auto pattern = GetPattern<TextFieldPattern>();
253     CHECK_NULL_VOID(pattern);
254     auto host = pattern->GetHost();
255     CHECK_NULL_VOID(host);
256     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
257     CHECK_NULL_VOID(layoutProperty);
258     auto hasText = pattern->IsOperation();
259     if ((dirtyFlag & DIRTY_COPY_ALL_ITEM) == DIRTY_COPY_ALL_ITEM) {
260         menuInfo.showCopyAll = hasText && !pattern->IsSelectAll();
261         return;
262     }
263     bool isHideSelectionMenu = layoutProperty->GetSelectionMenuHiddenValue(false);
264 #if defined(ENABLE_STANDARD_INPUT)
265     auto inputMethod = MiscServices::InputMethodController::GetInstance();
266     auto isSupportCameraInput = inputMethod &&
267                                 inputMethod->IsInputTypeSupported(MiscServices::InputType::CAMERA_INPUT) &&
268                                 !pattern->IsInPasswordMode();
269 #else
270     auto isSupportCameraInput = false;
271 #endif
272     menuInfo.showCameraInput = !pattern->IsSelected() && isSupportCameraInput && !pattern->HasCustomKeyboard();
273     if (IsUsingMouse()) {
274         auto manager = SelectContentOverlayManager::GetOverlayManager();
275         CHECK_NULL_VOID(manager);
276         menuInfo.menuIsShow = !isHideSelectionMenu || manager->IsOpen();
277     } else {
278         menuInfo.menuIsShow = (hasText || IsShowPaste() || menuInfo.showCameraInput) &&
279             !isHideSelectionMenu && IsShowMenu();
280     }
281     menuInfo.menuDisable = isHideSelectionMenu;
282     menuInfo.showPaste = IsShowPaste();
283     menuInfo.menuType = IsUsingMouse() ? OptionMenuType::MOUSE_MENU : OptionMenuType::TOUCH_MENU;
284     menuInfo.showCopy = hasText && pattern->AllowCopy() && pattern->IsSelected();
285     menuInfo.showCut = menuInfo.showCopy;
286     menuInfo.showCopyAll = hasText && !pattern->IsSelectAll();
287     menuInfo.showAIWrite = pattern->IsShowAIWrite() && pattern->IsSelected();
288 }
289 
OnUpdateSelectOverlayInfo(SelectOverlayInfo & overlayInfo,int32_t requestCode)290 void TextFieldSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo& overlayInfo, int32_t requestCode)
291 {
292     overlayInfo.clipHandleDrawRect = IsClipHandleWithViewPort();
293     BaseTextSelectOverlay::OnUpdateSelectOverlayInfo(overlayInfo, requestCode);
294     auto textFieldPattern = GetPattern<TextFieldPattern>();
295     CHECK_NULL_VOID(textFieldPattern);
296     auto paintProperty = textFieldPattern->GetPaintProperty<TextFieldPaintProperty>();
297     CHECK_NULL_VOID(paintProperty);
298     overlayInfo.handlerColor = paintProperty->GetCursorColor();
299     OnUpdateOnCreateMenuCallback(overlayInfo);
300     auto layoutProperty =
301         DynamicCast<TextFieldLayoutProperty>(textFieldPattern->GetLayoutProperty<TextFieldLayoutProperty>());
302     CHECK_NULL_VOID(layoutProperty);
303     if (layoutProperty->HasMaxLines()) {
304         uint32_t maxLine = layoutProperty->GetMaxLinesValue(Infinity<uint32_t>());
305         if (1 == maxLine) {
306             overlayInfo.isSingleLine = true;
307         }
308     }
309 }
310 
GetSelectArea()311 RectF TextFieldSelectOverlay::GetSelectArea()
312 {
313     auto pattern = GetPattern<TextFieldPattern>();
314     CHECK_NULL_RETURN(pattern, {});
315     auto host = pattern->GetHost();
316     CHECK_NULL_RETURN(host, {});
317     auto selectRects = pattern->GetTextBoxes();
318     RectF res(pattern->GetCaretRect());
319     auto textPaintOffset = host->GetTransformRelativeOffset();
320     if (selectRects.empty()) {
321         res.SetOffset(res.GetOffset() + textPaintOffset);
322     } else {
323         auto contentRect = pattern->GetContentRect();
324         auto textRect = pattern->GetTextRect();
325         res = MergeSelectedBoxes(selectRects, contentRect, textRect, textPaintOffset);
326     }
327     auto globalContentRect = GetVisibleContentRect();
328     auto intersectRect = res.IntersectRectT(globalContentRect);
329     if (hasTransform_) {
330         intersectRect.SetOffset(intersectRect.GetOffset() - textPaintOffset);
331         GetGlobalRectWithTransform(intersectRect);
332     }
333     ApplySelectAreaWithKeyboard(intersectRect);
334     return intersectRect;
335 }
336 
GetSelectedText()337 std::string TextFieldSelectOverlay::GetSelectedText()
338 {
339     auto pattern = GetPattern<TextFieldPattern>();
340     CHECK_NULL_RETURN(pattern, "");
341     auto start = pattern->GetTextSelectController()->GetStartIndex();
342     auto end = pattern->GetTextSelectController()->GetEndIndex();
343     return pattern->GetTextContentController()->GetSelectedValue(start, end);
344 }
345 
OnMenuItemAction(OptionMenuActionId id,OptionMenuType type)346 void TextFieldSelectOverlay::OnMenuItemAction(OptionMenuActionId id, OptionMenuType type)
347 {
348     auto pattern = GetPattern<TextFieldPattern>();
349     CHECK_NULL_VOID(pattern);
350     TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "Handle overlay menu, men id %{public}d, menu type %{public}d", id, type);
351     switch (id) {
352         case OptionMenuActionId::COPY:
353             pattern->HandleOnCopy();
354             return;
355         case OptionMenuActionId::CUT:
356             pattern->HandleOnCut();
357             return;
358         case OptionMenuActionId::SELECT_ALL:
359             pattern->HandleOnSelectAll(type == OptionMenuType::MOUSE_MENU, false, true);
360             return;
361         case OptionMenuActionId::PASTE:
362             pattern->HandleOnPaste();
363             return;
364         case OptionMenuActionId::CAMERA_INPUT:
365             pattern->HandleOnCameraInput();
366             return;
367         case OptionMenuActionId::AI_WRITE:
368             pattern->HandleOnAIWrite();
369             return;
370         default:
371             return;
372     }
373 }
374 
GetTextAreaCaretPosition(const OffsetF & localOffset)375 int32_t TextFieldSelectOverlay::GetTextAreaCaretPosition(const OffsetF& localOffset)
376 {
377     auto pattern = GetPattern<TextFieldPattern>();
378     auto contentRect = pattern->GetContentRect();
379     auto paddingLeft = pattern->GetPaddingLeft();
380     auto textRect = pattern->GetTextRect();
381     auto lineHeight = pattern->PreferredLineHeight();
382     Offset offset;
383     if (LessNotEqual(localOffset.GetY(), contentRect.GetY())) {
384         offset = Offset(localOffset.GetX() - paddingLeft, localOffset.GetY() - textRect.GetY() - lineHeight);
385     } else if (GreatOrEqual(localOffset.GetY(), contentRect.GetY() + contentRect.Height())) {
386         offset = Offset(localOffset.GetX() - paddingLeft, localOffset.GetY() - textRect.GetY() + lineHeight);
387     } else {
388         offset = Offset(localOffset.GetX() - paddingLeft, localOffset.GetY() - textRect.GetY());
389     }
390     return pattern->ConvertTouchOffsetToCaretPosition(offset);
391 }
392 
GetTextInputCaretPosition(const OffsetF & localOffset,bool isFirst)393 int32_t TextFieldSelectOverlay::GetTextInputCaretPosition(const OffsetF& localOffset, bool isFirst)
394 {
395     auto pattern = GetPattern<TextFieldPattern>();
396     auto contentRect = pattern->GetContentRect();
397     auto selectController = pattern->GetTextSelectController();
398     auto wideText = pattern->GetWideText();
399     if (LessNotEqual(localOffset.GetX(), contentRect.GetX())) {
400         auto index = selectController->GetStartIndex();
401         if ((!isFirst && !IsHandleReverse()) || (isFirst && IsHandleReverse())) {
402             index = selectController->GetEndIndex();
403         }
404         auto len = pattern->GetGraphemeClusterLength(wideText, index, true);
405         return std::max(index - len, 0);
406     }
407     if (GreatOrEqual(localOffset.GetX(), contentRect.GetX() + contentRect.Width())) {
408         auto index = selectController->GetEndIndex();
409         if ((isFirst && !IsHandleReverse()) || (!isFirst && IsHandleReverse())) {
410             index = selectController->GetStartIndex();
411         }
412         auto len = pattern->GetGraphemeClusterLength(wideText, index);
413         return std::min(index + len, pattern->GetContentWideTextLength());
414     }
415     Offset offset(localOffset.GetX() - pattern->GetTextRect().GetX(), 0.0f);
416     return pattern->ConvertTouchOffsetToCaretPosition(offset);
417 }
418 
GetCaretPositionOnHandleMove(const OffsetF & localOffset,bool isFirst)419 int32_t TextFieldSelectOverlay::GetCaretPositionOnHandleMove(const OffsetF& localOffset, bool isFirst)
420 {
421     auto pattern = GetPattern<TextFieldPattern>();
422     CHECK_NULL_RETURN(pattern, 0);
423     if (pattern->IsTextArea()) {
424         return GetTextAreaCaretPosition(localOffset);
425     }
426     return GetTextInputCaretPosition(localOffset, isFirst);
427 }
428 
OnHandleMove(const RectF & handleRect,bool isFirst)429 void TextFieldSelectOverlay::OnHandleMove(const RectF& handleRect, bool isFirst)
430 {
431     auto pattern = GetPattern<TextFieldPattern>();
432     CHECK_NULL_VOID(pattern);
433     CHECK_NULL_VOID(pattern->IsOperation());
434     auto localOffset = handleRect.GetOffset();
435     localOffset.SetY(localOffset.GetY() + handleRect.Height() / 2.0f);
436     if (IsOverlayMode()) {
437         localOffset = localOffset - GetPaintOffsetWithoutTransform();
438     }
439     auto selectController = pattern->GetTextSelectController();
440     CHECK_NULL_VOID(selectController);
441     int32_t startIndex = selectController->GetFirstHandleIndex();
442     int32_t endIndex = selectController->GetSecondHandleIndex();
443     if (pattern->GetMagnifierController() && SelectOverlayIsOn()) {
444         auto magnifierLocalOffsetY = localOffset.GetY();
445         auto magnifierLocalOffset = OffsetF(localOffset.GetX(), magnifierLocalOffsetY);
446         if (IsOverlayMode()) {
447             GetLocalPointWithTransform(magnifierLocalOffset);
448         }
449         pattern->GetMagnifierController()->SetLocalOffset(magnifierLocalOffset);
450     }
451     if (IsSingleHandle()) {
452         int32_t preIndex = selectController->GetCaretIndex();
453         selectController->UpdateCaretInfoByOffset(Offset(localOffset.GetX(), localOffset.GetY()));
454         pattern->ShowCaretAndStopTwinkling();
455         pattern->StartVibratorByIndexChange(selectController->GetCaretIndex(), preIndex);
456     } else {
457         auto position = GetCaretPositionOnHandleMove(localOffset, isFirst);
458         if (isFirst) {
459             pattern->StartVibratorByIndexChange(position, startIndex);
460             selectController->MoveFirstHandleToContentRect(position, false);
461             UpdateSecondHandleOffset();
462         } else {
463             pattern->StartVibratorByIndexChange(position, endIndex);
464             selectController->MoveSecondHandleToContentRect(position, false);
465             UpdateFirstHandleOffset();
466         }
467     }
468     pattern->PlayScrollBarAppearAnimation();
469     auto tmpHost = pattern->GetHost();
470     CHECK_NULL_VOID(tmpHost);
471     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
472 }
473 
OnHandleMoveDone(const RectF & rect,bool isFirst)474 void TextFieldSelectOverlay::OnHandleMoveDone(const RectF& rect, bool isFirst)
475 {
476     BaseTextSelectOverlay::OnHandleMoveDone(rect, isFirst);
477     auto pattern = GetPattern<TextFieldPattern>();
478     CHECK_NULL_VOID(pattern);
479     auto host = pattern->GetHost();
480     CHECK_NULL_VOID(host);
481     auto layoutProperty = host->GetLayoutProperty<TextFieldLayoutProperty>();
482     CHECK_NULL_VOID(layoutProperty);
483     auto overlayManager = GetManager<SelectContentOverlayManager>();
484     CHECK_NULL_VOID(overlayManager);
485     if (!layoutProperty->GetSelectionMenuHiddenValue(false)) {
486         overlayManager->MarkInfoChange(DIRTY_COPY_ALL_ITEM);
487     }
488     if (pattern->GetMagnifierController()) {
489         pattern->GetMagnifierController()->RemoveMagnifierFrameNode();
490     }
491     auto selectController = pattern->GetTextSelectController();
492     if (!IsSingleHandle()) {
493         if (selectController->GetFirstHandleIndex() == selectController->GetSecondHandleIndex()) {
494             CloseOverlay(true, CloseReason::CLOSE_REASON_NORMAL);
495             pattern->StartTwinkling();
496             selectController->MoveCaretToContentRect(pattern->GetCaretIndex());
497         } else {
498             overlayManager->MarkInfoChange(DIRTY_DOUBLE_HANDLE | DIRTY_SELECT_AREA | DIRTY_SELECT_TEXT);
499         }
500     } else {
501         pattern->StopTwinkling();
502         overlayManager->MarkInfoChange(DIRTY_SECOND_HANDLE);
503     }
504     overlayManager->ShowOptionMenu();
505     overlayManager->SetHandleCircleIsShow(isFirst, true);
506     if (IsSingleHandle()) {
507         overlayManager->SetIsHandleLineShow(true);
508     }
509     pattern->ScheduleDisappearDelayTask();
510     pattern->UpdateCaretInfoToController();
511     auto tmpHost = pattern->GetHost();
512     CHECK_NULL_VOID(tmpHost);
513     tmpHost->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
514 }
515 
ProcessSelectAllOverlay(const OverlayRequest & request)516 void TextFieldSelectOverlay::ProcessSelectAllOverlay(const OverlayRequest& request)
517 {
518     OverlayRequest newRequest = request;
519     newRequest.requestCode = static_cast<uint32_t>(newRequest.requestCode) | REQUEST_SELECT_ALL;
520     ProcessOverlay(newRequest);
521 }
522 
OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)523 void TextFieldSelectOverlay::OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)
524 {
525     if (IsAncestorNodeGeometryChange(flag) || IsAncestorNodeTransformChange(flag)) {
526         UpdateAllHandlesOffset();
527     }
528     BaseTextSelectOverlay::OnAncestorNodeChanged(flag);
529 }
530 
OnHandleLevelModeChanged(HandleLevelMode mode)531 void TextFieldSelectOverlay::OnHandleLevelModeChanged(HandleLevelMode mode)
532 {
533     if (handleLevelMode_ != mode && mode == HandleLevelMode::OVERLAY) {
534         auto pattern = GetPattern<TextFieldPattern>();
535         if (pattern) {
536             pattern->UpdateParentGlobalOffset();
537             pattern->GetTextSelectController()->CalculateHandleOffset();
538         }
539     }
540     BaseTextSelectOverlay::OnHandleLevelModeChanged(mode);
541 }
542 
OnOverlayClick(const GestureEvent & event,bool isFirst)543 void TextFieldSelectOverlay::OnOverlayClick(const GestureEvent& event, bool isFirst)
544 {
545     auto pattern = GetPattern<TextFieldPattern>();
546     CHECK_NULL_VOID(pattern);
547     auto recognizer = pattern->GetMultipleClickRecognizer();
548     CHECK_NULL_VOID(recognizer);
549     if (recognizer->IsRunning() && recognizer->IsValidClick(event)) {
550         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield overlayClick multiple click recognizer is running.");
551         auto overlayEvent = event;
552         overlayEvent.SetLocalLocation(recognizer->GetBeginLocalLocation());
553         overlayEvent.SetGlobalLocation(recognizer->GetBeginGlobalLocation());
554         pattern->HandleClickEvent(overlayEvent);
555     } else if (!IsSingleHandle()) {
556         if (pattern->HandleBetweenSelectedPosition(event)) {
557             TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield HandleBetweenSelectedPosition");
558             return;
559         }
560         auto selectController = pattern->GetTextSelectController();
561         auto index = isFirst ? selectController->GetFirstHandleIndex() : selectController->GetSecondHandleIndex();
562         pattern->HandleSetSelection(index, index, false);
563         pattern->StartTwinkling();
564     } else {
565         TAG_LOGI(AceLogTag::ACE_TEXT_FIELD, "textfield overlayClick");
566     }
567 }
568 
OnHandleIsHidden()569 void TextFieldSelectOverlay::OnHandleIsHidden()
570 {
571     auto pattern = GetPattern<TextFieldPattern>();
572     CHECK_NULL_VOID(pattern);
573     pattern->StartTwinkling();
574 }
575 
OnHandleMoveStart(const GestureEvent & event,bool isFirst)576 void TextFieldSelectOverlay::OnHandleMoveStart(const GestureEvent& event, bool isFirst)
577 {
578     BaseTextSelectOverlay::OnHandleMoveStart(event, isFirst);
579     auto manager = GetManager<SelectContentOverlayManager>();
580     CHECK_NULL_VOID(manager);
581     auto pattern = GetPattern<TextFieldPattern>();
582     CHECK_NULL_VOID(pattern);
583     manager->SetHandleCircleIsShow(isFirst, false);
584     if (IsSingleHandle()) {
585         manager->SetIsHandleLineShow(false);
586         if (!pattern->IsOperation()) {
587             pattern->StartTwinkling();
588         }
589     }
590 }
591 
GetHandleColor()592 std::optional<Color> TextFieldSelectOverlay::GetHandleColor()
593 {
594     auto textFieldPattern = GetPattern<TextFieldPattern>();
595     CHECK_NULL_RETURN(textFieldPattern, std::nullopt);
596     auto paintProperty = textFieldPattern->GetPaintProperty<TextFieldPaintProperty>();
597     CHECK_NULL_RETURN(paintProperty, std::nullopt);
598     return paintProperty->GetCursorColor();
599 }
600 } // namespace OHOS::Ace::NG
601