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