• 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/base_text_select_overlay.h"
17 
18 #include "base/utils/system_properties.h"
19 #include "core/common/ace_engine.h"
20 #include "core/common/ai/text_translation_adapter.h"
21 #include "core/common/share/text_share_adapter.h"
22 #include "core/components/select/select_theme.h"
23 #include "core/components/text_overlay/text_overlay_theme.h"
24 #include "core/components_ng/pattern/scrollable/nestable_scroll_container.h"
25 #include "core/components_ng/pattern/scrollable/scrollable_paint_property.h"
26 #include "core/components_ng/pattern/text_drag/text_drag_base.h"
27 #include "core/components_ng/pattern/text_field/text_field_manager.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr int32_t NO_NEED_RESTART_SINGLE_HANDLE = 100;
32 constexpr FrameNodeChangeInfoFlag AVOID_KEYBOARD_END_FALG = 1 << 8;
33 const char *SYSTEM_CAPABILITY_OF_SHARE = "SystemCapability.Collaboration.SystemShare";
34 } // namespace
ProcessOverlay(const OverlayRequest & request)35 void BaseTextSelectOverlay::ProcessOverlay(const OverlayRequest& request)
36 {
37     if (!IsEnableSelectionMenu()) {
38         TAG_LOGI(AceLogTag::ACE_TEXT, "The selectoverlay is not displayed cause enableSelectionMenu is false");
39         return;
40     }
41     UpdateTransformFlag();
42     if (!PreProcessOverlay(request) || AnimationUtils::IsImplicitAnimationOpen()) {
43         return;
44     }
45     isSuperFoldDisplayDevice_ = SystemProperties::IsSuperFoldDisplayDevice();
46     auto checkClipboard = [weak = WeakClaim(this), request](bool hasData) {
47         TAG_LOGI(AceLogTag::ACE_TEXT, "HasData callback from clipboard, data available ? %{public}d", hasData);
48         auto overlay = weak.Upgrade();
49         CHECK_NULL_VOID(overlay);
50         overlay->ShowSelectOverlay(request, hasData);
51     };
52     auto textBase = hostTextBase_.Upgrade();
53     CHECK_NULL_VOID(textBase);
54     auto clipboard = textBase->GetClipboard();
55     if (clipboard) {
56         auto mimeTypes = GetPasteMimeTypes();
57         if (!mimeTypes.empty()) {
58             clipboard->HasDataType(checkClipboard, mimeTypes);
59             return;
60         }
61         clipboard->HasData(checkClipboard);
62     } else {
63         checkClipboard(false);
64     }
65 }
66 
ShowSelectOverlay(const OverlayRequest & request,bool hasClipboardData)67 void BaseTextSelectOverlay::ShowSelectOverlay(const OverlayRequest& request, bool hasClipboardData)
68 {
69     SetShowPaste(hasClipboardData);
70     SetMenuIsShow(request.menuIsShow);
71     SetIsShowHandleLine(!request.hideHandleLine);
72     latestReqeust_ = request;
73     if (!SelectOverlayIsOn() && enableHandleLevel_) {
74         auto firstLocalRect = GetHandleLocalPaintRect(DragHandleIndex::FIRST);
75         auto secondLocalRect = GetHandleLocalPaintRect(DragHandleIndex::SECOND);
76         CalcHandleLevelMode(firstLocalRect, secondLocalRect);
77     }
78     if (enableHandleLevel_) {
79         auto host = GetOwner();
80         CHECK_NULL_VOID(host);
81         host->RegisterNodeChangeListener();
82         RegisterScrollingListener(nullptr);
83         CheckAndUpdateHostGlobalPaintRect();
84     }
85     auto manager = SelectContentOverlayManager::GetOverlayManager(Claim(this));
86     CHECK_NULL_VOID(manager);
87     manager->Show(request.animation, request.requestCode);
88 }
89 
ProcessOverlayOnAreaChanged(const OverlayRequest & request)90 void BaseTextSelectOverlay::ProcessOverlayOnAreaChanged(const OverlayRequest& request)
91 {
92     auto overlayRequest = request;
93     overlayRequest.requestCode = NO_NEED_RESTART_SINGLE_HANDLE;
94     ProcessOverlay(overlayRequest);
95 }
96 
CheckRestartHiddenHandleTask(int32_t requestCode)97 bool BaseTextSelectOverlay::CheckRestartHiddenHandleTask(int32_t requestCode)
98 {
99     return requestCode != NO_NEED_RESTART_SINGLE_HANDLE;
100 }
101 
IsShowMouseMenu()102 bool BaseTextSelectOverlay::IsShowMouseMenu()
103 {
104     auto overlayManager = GetManager<SelectContentOverlayManager>();
105     CHECK_NULL_RETURN(overlayManager, false);
106     return overlayManager->GetShowMenuType() == OptionMenuType::MOUSE_MENU;
107 }
108 
IsCurrentMenuVisibile()109 bool BaseTextSelectOverlay::IsCurrentMenuVisibile()
110 {
111     auto overlayManager = GetManager<SelectContentOverlayManager>();
112     CHECK_NULL_RETURN(overlayManager, false);
113     return overlayManager->IsMenuShow();
114 }
115 
IsHandleReverse()116 bool BaseTextSelectOverlay::IsHandleReverse()
117 {
118     auto overlayManager = GetManager<SelectContentOverlayManager>();
119     CHECK_NULL_RETURN(overlayManager, false);
120     return overlayManager->IsHandleReverse();
121 }
122 
SelectOverlayIsOn()123 bool BaseTextSelectOverlay::SelectOverlayIsOn()
124 {
125     auto manager = GetManager<SelectContentOverlayManager>();
126     CHECK_NULL_RETURN(manager, false);
127     return manager->IsOpen();
128 }
129 
SelectOverlayIsCreating()130 bool BaseTextSelectOverlay::SelectOverlayIsCreating()
131 {
132     auto manager = GetManager<SelectContentOverlayManager>();
133     CHECK_NULL_RETURN(manager, false);
134     return manager->IsCreating();
135 }
136 
CloseOverlay(bool animation,CloseReason reason)137 void BaseTextSelectOverlay::CloseOverlay(bool animation, CloseReason reason)
138 {
139     auto overlayManager = GetManager<SelectContentOverlayManager>();
140     CHECK_NULL_VOID(overlayManager);
141     overlayManager->Close(GetOwnerId(), false, reason);
142     AfterCloseOverlay();
143 }
144 
ToggleMenu()145 void BaseTextSelectOverlay::ToggleMenu()
146 {
147     auto manager = GetManager<SelectContentOverlayManager>();
148     CHECK_NULL_VOID(manager);
149     manager->ToggleOptionMenu();
150     UpdateOriginalMenuIsShow();
151 }
152 
ShowMenu()153 void BaseTextSelectOverlay::ShowMenu()
154 {
155     auto manager = GetManager<SelectContentOverlayManager>();
156     CHECK_NULL_VOID(manager);
157     manager->ShowOptionMenu();
158     UpdateOriginalMenuIsShow();
159 }
160 
HideMenu(bool noAnimation)161 void BaseTextSelectOverlay::HideMenu(bool noAnimation)
162 {
163     auto manager = GetManager<SelectContentOverlayManager>();
164     CHECK_NULL_VOID(manager);
165     manager->HideOptionMenu(noAnimation);
166     UpdateOriginalMenuIsShow();
167 }
168 
DisableMenu()169 void BaseTextSelectOverlay::DisableMenu()
170 {
171     auto manager = GetManager<SelectContentOverlayManager>();
172     CHECK_NULL_VOID(manager);
173     manager->DisableMenu();
174 }
175 
EnableMenu()176 void BaseTextSelectOverlay::EnableMenu()
177 {
178     auto manager = GetManager<SelectContentOverlayManager>();
179     CHECK_NULL_VOID(manager);
180     manager->EnableMenu();
181 }
182 
UpdateAllHandlesOffset()183 void BaseTextSelectOverlay::UpdateAllHandlesOffset()
184 {
185     auto manager = GetManager<SelectContentOverlayManager>();
186     CHECK_NULL_VOID(manager);
187     manager->MarkInfoChange(DIRTY_DOUBLE_HANDLE | DIRTY_SELECT_AREA);
188 }
189 
UpdateFirstHandleOffset()190 void BaseTextSelectOverlay::UpdateFirstHandleOffset()
191 {
192     auto manager = GetManager<SelectContentOverlayManager>();
193     CHECK_NULL_VOID(manager);
194     manager->MarkInfoChange(DIRTY_FIRST_HANDLE);
195 }
196 
UpdateSecondHandleOffset()197 void BaseTextSelectOverlay::UpdateSecondHandleOffset()
198 {
199     auto manager = GetManager<SelectContentOverlayManager>();
200     CHECK_NULL_VOID(manager);
201     manager->MarkInfoChange(DIRTY_SECOND_HANDLE);
202 }
203 
UpdateViewPort()204 void BaseTextSelectOverlay::UpdateViewPort()
205 {
206     auto manager = GetManager<SelectContentOverlayManager>();
207     CHECK_NULL_VOID(manager);
208     manager->MarkInfoChange(DIRTY_VIEWPORT);
209 }
210 
GetOwner()211 RefPtr<FrameNode> BaseTextSelectOverlay::GetOwner()
212 {
213     auto pattern = GetPattern<Pattern>();
214     CHECK_NULL_RETURN(pattern, nullptr);
215     return pattern->GetHost();
216 }
217 
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)218 void BaseTextSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
219 {
220     if (IsMouseClickDown(sourceType, touchType)) {
221         CloseOverlay(false, CloseReason::CLOSE_REASON_CLICK_OUTSIDE);
222     } else if (IsTouchUp(sourceType, touchType)) {
223         HideMenu(true);
224     }
225 }
226 
CheckTouchInHostNode(const PointF & touchPoint)227 bool BaseTextSelectOverlay::CheckTouchInHostNode(const PointF& touchPoint)
228 {
229     auto host = GetOwner();
230     CHECK_NULL_RETURN(host, false);
231     auto geo = host->GetGeometryNode();
232     CHECK_NULL_RETURN(geo, false);
233     auto rect = RectF(OffsetF(0.0f, 0.0f), geo->GetFrameSize());
234     return rect.IsInRegion(touchPoint);
235 }
236 
OnUpdateSelectOverlayInfo(SelectOverlayInfo & overlayInfo,int32_t requestCode)237 void BaseTextSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo& overlayInfo, int32_t requestCode)
238 {
239     overlayInfo.isSingleHandle = isSingleHandle_;
240     overlayInfo.isHandleLineShow = isShowHandleLine_;
241     overlayInfo.recreateOverlay = isUsingMouse_;
242     overlayInfo.rightClickOffset = mouseMenuOffset_;
243     overlayInfo.isUsingMouse = isUsingMouse_;
244     overlayInfo.isNewAvoid = true;
245     overlayInfo.hitTestMode = HitTestMode::HTMDEFAULT;
246     if (hasTransform_) {
247         overlayInfo.callerNodeInfo = {
248             .paintFrameRect = GetPaintRectWithTransform(),
249             .paintOffset = GetPaintRectOffsetWithTransform()
250         };
251     }
252     overlayInfo.ancestorViewPort = GetAncestorNodeViewPort();
253     overlayInfo.enableHandleLevel = enableHandleLevel_;
254     overlayInfo.handleLevelMode = handleLevelMode_;
255     if (enableHandleLevel_) {
256         overlayInfo.scale = GetHostScale();
257     }
258     overlayInfo.afterOnClick = [weak = WeakClaim(this)](const GestureEvent&, bool isFirst) {
259         auto overlay = weak.Upgrade();
260         CHECK_NULL_VOID(overlay);
261         overlay->UpdateOriginalMenuIsShow();
262     };
263     overlayInfo.enableSubWindowMenu = enableSubWindowMenu_;
264 }
265 
GetVisibleRect(const RefPtr<FrameNode> & node,const RectF & visibleRect)266 RectF BaseTextSelectOverlay::GetVisibleRect(const RefPtr<FrameNode>& node, const RectF& visibleRect)
267 {
268     CHECK_NULL_RETURN(node, visibleRect);
269     auto parentNode = node->GetAncestorNodeOfFrame(true);
270     CHECK_NULL_RETURN(parentNode, visibleRect);
271     if (parentNode->GetTag() == V2::PAGE_ETS_TAG) {
272         return visibleRect;
273     }
274     auto intersectRect = visibleRect;
275     auto scrollablePattern = AceType::DynamicCast<NestableScrollContainer>(parentNode->GetPattern());
276     auto geometryNode = parentNode->GetGeometryNode();
277     if (scrollablePattern && geometryNode) {
278         RectF parentViewPort;
279         if (!GetFrameNodeContentRect(parentNode, parentViewPort)) {
280             return RectF(0, 0, 0, 0);
281         }
282         parentViewPort += parentNode->GetTransformRelativeOffset();
283         if (parentViewPort.IsIntersectWith(visibleRect)) {
284             intersectRect = parentViewPort.IntersectRectT(visibleRect);
285         } else {
286             return RectF(0, 0, 0, 0);
287         }
288     }
289     return GetVisibleRect(parentNode, intersectRect);
290 }
291 
RemoveSelectionHoldCallback()292 void BaseTextSelectOverlay::RemoveSelectionHoldCallback()
293 {
294     auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
295     CHECK_NULL_VOID(overlayManager);
296     overlayManager->RemoveHoldSelectionCallback(GetOwnerId());
297 }
298 
SetSelectionHoldCallback()299 void BaseTextSelectOverlay::SetSelectionHoldCallback()
300 {
301     auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
302     CHECK_NULL_VOID(overlayManager);
303     HoldSelectionInfo selectionInfo;
304     selectionInfo.resetSelectionCallback = [weak = WeakClaim(this)]() {
305         auto overlay = weak.Upgrade();
306         CHECK_NULL_VOID(overlay);
307         overlay->OnResetTextSelection();
308     };
309     selectionInfo.checkTouchInArea = [weak = WeakClaim(this), manager = WeakClaim(AceType::RawPtr(overlayManager))](
310                                          const PointF& point, bool passThrough) {
311         auto baseOverlay = weak.Upgrade();
312         CHECK_NULL_RETURN(baseOverlay, false);
313         auto overlayManager = manager.Upgrade();
314         CHECK_NULL_RETURN(overlayManager, false);
315         auto host = baseOverlay->GetOwner();
316         CHECK_NULL_RETURN(host, false);
317         auto localPoint = point;
318         overlayManager->ConvertPointRelativeToNode(host, localPoint, passThrough);
319         return baseOverlay->CheckTouchInHostNode(localPoint);
320     };
321     selectionInfo.eventFilter = [weak = WeakClaim(this)](SourceType sourceType, TouchType touchType) {
322         auto overlay = weak.Upgrade();
323         CHECK_NULL_RETURN(overlay, false);
324         return overlay->IsAcceptResetSelectionEvent(sourceType, touchType);
325     };
326     overlayManager->SetHoldSelectionCallback(GetOwnerId(), selectionInfo);
327 }
328 
GetVisibleContentRect(bool isGlobal)329 RectF BaseTextSelectOverlay::GetVisibleContentRect(bool isGlobal)
330 {
331     RectF visibleContentRect;
332     auto pattern = GetPattern<Pattern>();
333     CHECK_NULL_RETURN(pattern, visibleContentRect);
334     auto host = pattern->GetHost();
335     CHECK_NULL_RETURN(host, visibleContentRect);
336     auto context = host->GetContext();
337     CHECK_NULL_RETURN(context, visibleContentRect);
338     auto geometryNode = host->GetGeometryNode();
339     CHECK_NULL_RETURN(geometryNode, visibleContentRect);
340     auto paintOffset = host->GetTransformRelativeOffset();
341     visibleContentRect = RectF(geometryNode->GetContentOffset() + paintOffset, geometryNode->GetContentSize());
342     if (enableHandleLevel_ && handleLevelMode_ == HandleLevelMode::EMBED && !isGlobal) {
343         return visibleContentRect;
344     }
345     return GetVisibleRect(pattern->GetHost(), visibleContentRect);
346 }
347 
MergeSelectedBoxes(const std::vector<RectF> & boxes,const RectF & contentRect,const RectF & textRect,const OffsetF & paintOffset)348 RectF BaseTextSelectOverlay::MergeSelectedBoxes(
349     const std::vector<RectF>& boxes, const RectF& contentRect, const RectF& textRect, const OffsetF& paintOffset)
350 {
351     if (boxes.empty()) {
352         return RectF();
353     }
354     auto frontRect = boxes.front();
355     auto backRect = boxes.back();
356     float selectAreaRight = frontRect.Right();
357     float selectAreaLeft = frontRect.Left();
358     if (boxes.size() != 1) {
359         std::unordered_map<float, RectF> selectLineRect;
360         for (const auto& box : boxes) {
361             auto combineLineRect = box;
362             auto top = box.Top();
363             if (selectLineRect.find(top) == selectLineRect.end()) {
364                 selectLineRect.insert({ top, combineLineRect });
365             } else {
366                 combineLineRect = combineLineRect.CombineRectT(selectLineRect[top]);
367                 selectLineRect.insert({ top, combineLineRect });
368             }
369             selectAreaRight = std::max(selectAreaRight, combineLineRect.Right());
370             selectAreaLeft = std::min(selectAreaLeft, combineLineRect.Left());
371         }
372     }
373     return { selectAreaLeft + textRect.GetX() + paintOffset.GetX(),
374         frontRect.GetY() + textRect.GetY() + paintOffset.GetY(), selectAreaRight - selectAreaLeft,
375         backRect.Bottom() - frontRect.Top() };
376 }
377 
SetTransformPaintInfo(SelectHandleInfo & handleInfo,const RectF & localHandleRect)378 void BaseTextSelectOverlay::SetTransformPaintInfo(SelectHandleInfo& handleInfo, const RectF& localHandleRect)
379 {
380     CHECK_NULL_VOID(hasTransform_);
381     SelectHandlePaintInfo paintInfo;
382     auto left = localHandleRect.Left() + localHandleRect.Width() / 2.0f;
383     std::vector<OffsetF> points = { OffsetF(left, localHandleRect.Top()), OffsetF(left, localHandleRect.Bottom()) };
384     GetGlobalPointsWithTransform(points);
385     paintInfo.startPoint = points[0];
386     paintInfo.endPoint = points[1];
387     paintInfo.width = localHandleRect.Width();
388     handleInfo.paintInfo = paintInfo;
389     handleInfo.paintInfoConverter = [weak = WeakClaim(this)](const SelectHandlePaintInfo& paintInfo) {
390         auto overlay = weak.Upgrade();
391         CHECK_NULL_RETURN(overlay, RectF());
392         return overlay->ConvertPaintInfoToRect(paintInfo);
393     };
394     handleInfo.isPaintHandleWithPoints = true;
395     handleInfo.isShow =
396         CheckHandleIsVisibleWithTransform(paintInfo.startPoint, paintInfo.endPoint, localHandleRect.Width());
397 }
398 
CheckHandleIsVisibleWithTransform(const OffsetF & startPoint,const OffsetF & endPoint,float epsilon)399 bool BaseTextSelectOverlay::CheckHandleIsVisibleWithTransform(
400     const OffsetF& startPoint, const OffsetF& endPoint, float epsilon)
401 {
402     auto pattern = GetPattern<Pattern>();
403     CHECK_NULL_RETURN(pattern, true);
404     auto host = pattern->GetHost();
405     CHECK_NULL_RETURN(host, true);
406     auto geometryNode = host->GetGeometryNode();
407     CHECK_NULL_RETURN(geometryNode, true);
408     auto contentRect = geometryNode->GetContentRect();
409     auto rectVertices = GetGlobalRectVertexWithTransform(contentRect, epsilon);
410     auto leftTop = rectVertices[0];
411     auto rightTop = rectVertices[1];
412     auto leftBottom = rectVertices[2];
413     auto rightBottom = rectVertices[3];
414     auto isStartPointInRect = IsPointInRect(startPoint, leftBottom, rightBottom, rightTop, leftTop);
415     auto isEndPointInRect = IsPointInRect(endPoint, leftBottom, rightBottom, rightTop, leftTop);
416     if (isStartPointInRect && isEndPointInRect) {
417         auto visibleContentRect = GetVisibleContentRectWithTransform(epsilon);
418         leftTop = OffsetF(visibleContentRect.Left(), visibleContentRect.Top());
419         rightTop = OffsetF(visibleContentRect.Right(), visibleContentRect.Top());
420         leftBottom = OffsetF(visibleContentRect.Left(), visibleContentRect.Bottom());
421         rightBottom = OffsetF(visibleContentRect.Right(), visibleContentRect.Bottom());
422         isStartPointInRect = IsPointInRect(startPoint, leftBottom, rightBottom, rightTop, leftTop);
423         isEndPointInRect = IsPointInRect(endPoint, leftBottom, rightBottom, rightTop, leftTop);
424         return isStartPointInRect && isEndPointInRect;
425     }
426     return false;
427 }
428 
IsPointInRect(const OffsetF & point,const OffsetF & lb,const OffsetF & rb,const OffsetF & rt,const OffsetF & lt)429 bool BaseTextSelectOverlay::IsPointInRect(
430     const OffsetF& point, const OffsetF& lb, const OffsetF& rb, const OffsetF& rt, const OffsetF& lt)
431 {
432     auto crossProduct = [](const OffsetF& point, const OffsetF& point1, const OffsetF& point2) {
433         auto pointStart = OffsetF(point2.GetX() - point1.GetX(), point2.GetY() - point1.GetY());
434         auto pointEnd = OffsetF(point.GetX() - point1.GetX(), point.GetY() - point1.GetY());
435         return pointStart.GetX() * pointEnd.GetY() - pointEnd.GetX() * pointStart.GetY();
436     };
437     auto bottomProduct = crossProduct(point, lb, rb);
438     auto rightProduct = crossProduct(point, rb, rt);
439     auto topProduct = crossProduct(point, rt, lt);
440     auto leftProduct = crossProduct(point, lt, lb);
441     std::vector<float> productVector = { bottomProduct, rightProduct, topProduct, leftProduct };
442     auto minMax = std::minmax_element(productVector.begin(), productVector.end());
443     // 所用向量叉积方向一致(都为正数或者都为负数),表示点在矩形内. 最小值大于0或者最大值小于0.
444     return Positive(*minMax.first) || Negative(* minMax.second);
445 }
446 
GetVisibleContentRectWithTransform(float epsilon)447 RectF BaseTextSelectOverlay::GetVisibleContentRectWithTransform(float epsilon)
448 {
449     RectF visibleContentRect;
450     auto pattern = GetPattern<Pattern>();
451     CHECK_NULL_RETURN(pattern, visibleContentRect);
452     auto host = pattern->GetHost();
453     CHECK_NULL_RETURN(host, visibleContentRect);
454     auto context = host->GetContext();
455     CHECK_NULL_RETURN(context, visibleContentRect);
456     auto geometryNode = host->GetGeometryNode();
457     CHECK_NULL_RETURN(geometryNode, visibleContentRect);
458     visibleContentRect = geometryNode->GetContentRect();
459     auto width = visibleContentRect.Width() + 2 * epsilon;
460     auto height = visibleContentRect.Height() + 2 * epsilon;
461     visibleContentRect.SetLeft(visibleContentRect.Left() - epsilon);
462     visibleContentRect.SetTop(visibleContentRect.Top() - epsilon);
463     visibleContentRect.SetWidth(width);
464     visibleContentRect.SetHeight(height);
465     GetGlobalRectWithTransform(visibleContentRect);
466     return GetVisibleRect(pattern->GetHost(), visibleContentRect);
467 }
468 
GetGlobalPointsWithTransform(std::vector<OffsetF> & points)469 void BaseTextSelectOverlay::GetGlobalPointsWithTransform(std::vector<OffsetF>& points)
470 {
471     CHECK_NULL_VOID(hasTransform_);
472     auto pattern = GetPattern<Pattern>();
473     CHECK_NULL_VOID(pattern);
474     auto parent = pattern->GetHost();
475     std::vector<PointF> convertPoints;
476     auto pointConverter = [](const OffsetF& offset) { return PointF(offset.GetX(), offset.GetY()); };
477     std::transform(points.begin(), points.end(), std::back_inserter(convertPoints), pointConverter);
478     while (parent) {
479         if (parent->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
480             break;
481         }
482         auto renderContext = parent->GetRenderContext();
483         CHECK_NULL_VOID(renderContext);
484         auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
485         for (auto& pointElement : convertPoints) {
486             pointElement = pointElement + paintOffset;
487             renderContext->GetPointTransform(pointElement);
488         }
489         parent = parent->GetAncestorNodeOfFrame(true);
490     }
491     points.clear();
492     auto offsetConverter = [](const PointF& point) { return OffsetF(point.GetX(), point.GetY()); };
493     std::transform(convertPoints.begin(), convertPoints.end(), std::back_inserter(points), offsetConverter);
494 }
495 
GetGlobalRectWithTransform(RectF & localRect)496 void BaseTextSelectOverlay::GetGlobalRectWithTransform(RectF& localRect)
497 {
498     CHECK_NULL_VOID(hasTransform_);
499     auto rectVertex = GetGlobalRectVertexWithTransform(localRect);
500     auto compareOffsetX = [](const OffsetF& offset1, const OffsetF& offset2) {
501         return LessNotEqual(offset1.GetX(), offset2.GetX());
502     };
503     auto minMaxX = std::minmax_element(rectVertex.begin(), rectVertex.end(), compareOffsetX);
504     auto compareOffsetY = [](const OffsetF& offset1, const OffsetF& offset2) {
505         return LessNotEqual(offset1.GetY(), offset2.GetY());
506     };
507     auto minMaxY = std::minmax_element(rectVertex.begin(), rectVertex.end(), compareOffsetY);
508     localRect.SetOffset(OffsetF(minMaxX.first->GetX(), minMaxY.first->GetY()));
509     localRect.SetSize(
510         SizeF(minMaxX.second->GetX() - minMaxX.first->GetX(), minMaxY.second->GetY() - minMaxY.first->GetY()));
511 }
512 
GetGlobalRectVertexWithTransform(const RectF & rect,float extendValue)513 std::vector<OffsetF> BaseTextSelectOverlay::GetGlobalRectVertexWithTransform(const RectF& rect, float extendValue)
514 {
515     std::vector<OffsetF> rectVertices = {
516         OffsetF(rect.Left() - extendValue, rect.Top() - extendValue),
517         OffsetF(rect.Right() + extendValue, rect.Top() - extendValue),
518         OffsetF(rect.Left() - extendValue, rect.Bottom() + extendValue),
519         OffsetF(rect.Right() + extendValue, rect.Bottom() + extendValue)
520     };
521     GetGlobalPointsWithTransform(rectVertices);
522     return rectVertices;
523 }
524 
GetLocalPointWithTransform(OffsetF & localPoint)525 void BaseTextSelectOverlay::GetLocalPointWithTransform(OffsetF& localPoint)
526 {
527     CHECK_NULL_VOID(hasTransform_);
528     std::vector<OffsetF> points = { localPoint };
529     GetLocalPointsWithTransform(points);
530     localPoint = points[0];
531 }
532 
GetLocalPointsWithTransform(std::vector<OffsetF> & localPoints)533 void BaseTextSelectOverlay::GetLocalPointsWithTransform(std::vector<OffsetF>& localPoints)
534 {
535     CHECK_NULL_VOID(hasTransform_);
536     auto textPaintOffset = GetPaintRectOffsetWithTransform();
537     GetGlobalPointsWithTransform(localPoints);
538     for (auto& pointElement : localPoints) {
539         pointElement = pointElement - textPaintOffset;
540     }
541 }
542 
GetPaintRectWithTransform()543 RectF BaseTextSelectOverlay::GetPaintRectWithTransform()
544 {
545     auto pattern = GetPattern<Pattern>();
546     CHECK_NULL_RETURN(pattern, RectF());
547     auto host = pattern->GetHost();
548     CHECK_NULL_RETURN(host, RectF());
549     auto geometryNode = host->GetGeometryNode();
550     CHECK_NULL_RETURN(geometryNode, RectF());
551     auto globalFrameRect = RectF(OffsetF(0.0f, 0.0f), geometryNode->GetFrameSize());
552     GetGlobalRectWithTransform(globalFrameRect);
553     return globalFrameRect;
554 }
555 
GetPaintRectOffsetWithTransform()556 OffsetF BaseTextSelectOverlay::GetPaintRectOffsetWithTransform()
557 {
558     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
559     CHECK_NULL_RETURN(pipeline, OffsetF(0.0f, 0.0f));
560     auto globalFrameRect = GetPaintRectWithTransform();
561     return globalFrameRect.GetOffset() - pipeline->GetRootRect().GetOffset();
562 }
563 
GetLocalRectWithTransform(RectF & rect)564 void BaseTextSelectOverlay::GetLocalRectWithTransform(RectF& rect)
565 {
566     CHECK_NULL_VOID(hasTransform_);
567     std::vector<OffsetF> localRectVertices = {
568         OffsetF(rect.Left(), rect.Top()),
569         OffsetF(rect.Right(), rect.Top()),
570         OffsetF(rect.Left(), rect.Bottom()),
571         OffsetF(rect.Right(), rect.Bottom())
572     };
573     GetLocalPointsWithTransform(localRectVertices);
574     auto compareOffsetX = [](const OffsetF& offset1, const OffsetF& offset2) {
575         return LessNotEqual(offset1.GetX(), offset2.GetX());
576     };
577     auto minMaxX = std::minmax_element(localRectVertices.begin(), localRectVertices.end(), compareOffsetX);
578     auto compareOffsetY = [](const OffsetF& offset1, const OffsetF& offset2) {
579         return LessNotEqual(offset1.GetY(), offset2.GetY());
580     };
581     auto minMaxY = std::minmax_element(localRectVertices.begin(), localRectVertices.end(), compareOffsetY);
582     rect.SetOffset(OffsetF(minMaxX.first->GetX(), minMaxY.first->GetY()));
583     rect.SetSize(SizeF(minMaxX.second->GetX() - minMaxX.first->GetX(), minMaxY.second->GetY() - minMaxY.first->GetY()));
584 }
585 
RevertLocalPointWithTransform(OffsetF & point)586 void BaseTextSelectOverlay::RevertLocalPointWithTransform(OffsetF& point)
587 {
588     CHECK_NULL_VOID(hasTransform_);
589     auto pattern = GetPattern<Pattern>();
590     CHECK_NULL_VOID(pattern);
591     auto parent = pattern->GetHost();
592     CHECK_NULL_VOID(parent);
593     std::stack<RefPtr<FrameNode>> nodeStack;
594     while (parent) {
595         nodeStack.push(parent);
596         parent = parent->GetAncestorNodeOfFrame(true);
597     }
598     CHECK_NULL_VOID(!nodeStack.empty());
599     PointF localPoint(point.GetX(), point.GetY());
600     while (!nodeStack.empty()) {
601         parent = nodeStack.top();
602         CHECK_NULL_VOID(parent);
603         nodeStack.pop();
604         auto renderContext = parent->GetRenderContext();
605         CHECK_NULL_VOID(renderContext);
606         renderContext->GetPointWithRevert(localPoint);
607         auto rectOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
608         localPoint = localPoint - rectOffset;
609     }
610     point.SetX(localPoint.GetX());
611     point.SetY(localPoint.GetY());
612 }
613 
ConvertPaintInfoToRect(const SelectHandlePaintInfo & paintInfo)614 RectF BaseTextSelectOverlay::ConvertPaintInfoToRect(const SelectHandlePaintInfo& paintInfo)
615 {
616     auto topOffset = paintInfo.startPoint;
617     RevertLocalPointWithTransform(topOffset);
618     auto bottomOffset = paintInfo.endPoint;
619     RevertLocalPointWithTransform(bottomOffset);
620     auto offset = topOffset + GetPaintOffsetWithoutTransform();
621     auto size = SizeF(paintInfo.width, bottomOffset.GetY() - topOffset.GetY());
622     return RectF(offset, size);
623 }
624 
GetPaintOffsetWithoutTransform()625 OffsetF BaseTextSelectOverlay::GetPaintOffsetWithoutTransform()
626 {
627     auto pattern = GetPattern<Pattern>();
628     CHECK_NULL_RETURN(pattern, OffsetF());
629     OffsetF offset;
630     auto parent = pattern->GetHost();
631     if (!hasTransform_) {
632         return parent->GetTransformRelativeOffset();
633     }
634     while (parent) {
635         auto renderContext = parent->GetRenderContext();
636         CHECK_NULL_RETURN(renderContext, OffsetF());
637         offset += renderContext->GetPaintRectWithoutTransform().GetOffset();
638         parent = parent->GetAncestorNodeOfFrame(true);
639     }
640     return offset;
641 }
642 
UpdateTransformFlag()643 void BaseTextSelectOverlay::UpdateTransformFlag()
644 {
645     hasTransform_ = HasUnsupportedTransform(true);
646 }
647 
GetAncestorNodeViewPort()648 std::optional<RectF> BaseTextSelectOverlay::GetAncestorNodeViewPort()
649 {
650     if (IsClipHandleWithViewPort()) {
651         RectF viewPort;
652         if (GetClipHandleViewPort(viewPort)) {
653             return viewPort;
654         }
655     }
656     auto pattern = GetPattern<Pattern>();
657     CHECK_NULL_RETURN(pattern, std::nullopt);
658     auto host = pattern->GetHost();
659     CHECK_NULL_RETURN(host, std::nullopt);
660     auto parent = host->GetAncestorNodeOfFrame(true);
661     while (parent) {
662         auto scrollableContainer = parent->GetPattern<NestableScrollContainer>();
663         if (scrollableContainer) {
664             return parent->GetTransformRectRelativeToWindow();
665         }
666         parent = parent->GetAncestorNodeOfFrame(true);
667     }
668     return std::nullopt;
669 }
670 
IsAcceptResetSelectionEvent(SourceType sourceType,TouchType touchType)671 bool BaseTextSelectOverlay::IsAcceptResetSelectionEvent(SourceType sourceType, TouchType touchType)
672 {
673     return (sourceType == SourceType::MOUSE || sourceType == SourceType::TOUCH) && touchType == TouchType::DOWN;
674 }
675 
GetHandleDiameter()676 float BaseTextSelectOverlay::GetHandleDiameter()
677 {
678     auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
679     CHECK_NULL_RETURN(overlayManager, 0.0f);
680     return overlayManager->GetHandleDiameter();
681 }
682 
SwitchToOverlayMode()683 void BaseTextSelectOverlay::SwitchToOverlayMode()
684 {
685     if (HasUnsupportedTransform() || IsHandleInParentSafeAreaPadding()) {
686         return;
687     }
688     auto manager = GetManager<SelectContentOverlayManager>();
689     CHECK_NULL_VOID(manager);
690     handleLevelMode_ = HandleLevelMode::OVERLAY;
691     manager->SwitchToHandleMode(handleLevelMode_);
692 }
693 
SwitchToEmbedMode()694 void BaseTextSelectOverlay::SwitchToEmbedMode()
695 {
696     CHECK_NULL_VOID(!isHandleMoving_);
697     auto manager = GetManager<SelectContentOverlayManager>();
698     CHECK_NULL_VOID(manager);
699     handleLevelMode_ = HandleLevelMode::EMBED;
700     manager->SwitchToHandleMode(handleLevelMode_);
701 }
702 
GetHostScale()703 VectorF BaseTextSelectOverlay::GetHostScale()
704 {
705     auto pattern = GetPattern<Pattern>();
706     auto unitScale = VectorF(1, 1);
707     CHECK_NULL_RETURN(pattern, unitScale);
708     auto host = pattern->GetHost();
709     CHECK_NULL_RETURN(host, unitScale);
710     auto scaleX = 1.0f;
711     auto scaleY = 1.0f;
712     while (host && host->GetTag() != V2::WINDOW_SCENE_ETS_TAG) {
713         auto renderContext = host->GetRenderContext();
714         CHECK_NULL_RETURN(renderContext, unitScale);
715         auto scale = renderContext->GetTransformScaleValue(unitScale);
716         scaleX *= std::abs(scale.x);
717         scaleY *= std::abs(scale.y);
718         auto transformMatrix = renderContext->GetTransformMatrix();
719         if (transformMatrix.has_value()) {
720             DecomposedTransform transform;
721             TransformUtil::DecomposeTransform(transform, transformMatrix.value());
722             scaleX *= std::abs(transform.scale[0]);
723             scaleY *= std::abs(transform.scale[1]);
724         }
725         host = host->GetAncestorNodeOfFrame(true);
726     }
727     return VectorF(1.0f / scaleX, 1.0f / scaleY);
728 }
729 
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)730 void BaseTextSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
731 {
732     isHandleDragging_ = false;
733     dragHandleIndex_ = DragHandleIndex::NONE;
734     if (reason == CloseReason::CLOSE_REASON_BY_RECREATE) {
735         return;
736     }
737     originalMenuIsShow_ = false;
738     if (enableHandleLevel_) {
739         auto host = GetOwner();
740         CHECK_NULL_VOID(host);
741         host->UnregisterNodeChangeListener();
742     }
743 }
744 
SetHandleLevelMode(HandleLevelMode mode)745 void BaseTextSelectOverlay::SetHandleLevelMode(HandleLevelMode mode)
746 {
747     if (handleLevelMode_ == mode) {
748         return;
749     }
750     handleLevelMode_ = mode;
751 }
752 
GetHandleLocalPaintRect(DragHandleIndex dragHandleIndex)753 RectF BaseTextSelectOverlay::GetHandleLocalPaintRect(DragHandleIndex dragHandleIndex)
754 {
755     return RectF();
756 }
757 
IsPointsInRegion(const std::vector<PointF> & points,const RectF & regionRect)758 bool BaseTextSelectOverlay::IsPointsInRegion(const std::vector<PointF>& points, const RectF& regionRect)
759 {
760     for (const auto& point : points) {
761         if (!regionRect.IsInRegion(point)) {
762             return false;
763         }
764     }
765     return true;
766 }
767 
GetHandlePoints(const RectF & handleRect,std::vector<PointF> & points,bool handleOnTop)768 void BaseTextSelectOverlay::GetHandlePoints(const RectF& handleRect, std::vector<PointF>& points, bool handleOnTop)
769 {
770     auto diameter = GetHandleDiameter();
771     auto handlePaintRect = handleRect;
772     auto offsetX = handlePaintRect.Left() + (handlePaintRect.Width() - diameter) / 2.0f;
773     auto offsetY = handleOnTop ? handlePaintRect.Top() - diameter : handlePaintRect.Bottom();
774     handlePaintRect.SetOffset(OffsetF(offsetX, offsetY));
775     handlePaintRect.SetSize(SizeF(diameter, diameter));
776     points.push_back(PointF(handlePaintRect.Left(), handlePaintRect.Top()));
777     points.push_back(PointF(handlePaintRect.Right(), handlePaintRect.Top()));
778     points.push_back(PointF(handlePaintRect.Left(), handlePaintRect.Bottom()));
779     points.push_back(PointF(handlePaintRect.Right(), handlePaintRect.Bottom()));
780 }
781 
CheckHandleCanPaintInHost(const RectF & firstRect,const RectF & secondRect)782 bool BaseTextSelectOverlay::CheckHandleCanPaintInHost(const RectF& firstRect, const RectF& secondRect)
783 {
784     if (isChangeToOverlayModeAtEdge_) {
785         return false;
786     }
787     std::vector<PointF> firstPoints;
788     GetHandlePoints(firstRect, firstPoints, false);
789     std::vector<PointF> secondPoints;
790     GetHandlePoints(secondRect, secondPoints, false);
791     auto host = GetOwner();
792     CHECK_NULL_RETURN(host, false);
793     auto parent = host;
794     while (parent) {
795         CHECK_NULL_RETURN(parent->GetGeometryNode(), false);
796         auto parentRect = RectF();
797         parentRect.SetSize(parent->GetGeometryNode()->GetFrameSize());
798         if (IsPointsInRegion(firstPoints, parentRect) && IsPointsInRegion(secondPoints, parentRect)) {
799             return true;
800         }
801         auto renderContext = parent->GetRenderContext();
802         CHECK_NULL_RETURN(renderContext, false);
803         auto isClip = renderContext->GetClipEdge().value_or(false);
804         if (isClip) {
805             break;
806         }
807         auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
808         for (auto& point : firstPoints) {
809             point = point + paintOffset;
810             renderContext->GetPointTransform(point);
811         }
812         for (auto& point : secondPoints) {
813             point = point + paintOffset;
814             renderContext->GetPointTransform(point);
815         }
816         parent = parent->GetAncestorNodeOfFrame(true);
817     }
818     return false;
819 }
820 
CalcHandleLevelMode(const RectF & firstLocalPaintRect,const RectF & secondLocalPaintRect)821 void BaseTextSelectOverlay::CalcHandleLevelMode(const RectF& firstLocalPaintRect, const RectF& secondLocalPaintRect)
822 {
823     if (CheckHandleCanPaintInHost(firstLocalPaintRect, secondLocalPaintRect) || HasUnsupportedTransform() ||
824         IsHandleInParentSafeAreaPadding(firstLocalPaintRect, secondLocalPaintRect)) {
825         SetHandleLevelMode(HandleLevelMode::EMBED);
826     } else {
827         SetHandleLevelMode(HandleLevelMode::OVERLAY);
828     }
829 }
830 
OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)831 void BaseTextSelectOverlay::OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)
832 {
833     auto isStartScroll = IsAncestorNodeStartScroll(flag);
834     auto isStartAnimation = IsAncestorNodeStartAnimation(flag);
835     auto isTransformChanged = IsAncestorNodeTransformChange(flag);
836     auto isStartTransition = IsAncestorNodeHasTransition(flag);
837     auto isSwitchToEmbed = isStartScroll || isStartAnimation || isTransformChanged || isStartTransition;
838     // parent size changes but the child does not change.
839     if (IsAncestorNodeGeometryChange(flag)) {
840         isSwitchToEmbed = isSwitchToEmbed || CheckAndUpdateHostGlobalPaintRect();
841     }
842     auto isScrollEnd = IsAncestorNodeEndScroll(flag) || ((flag & AVOID_KEYBOARD_END_FALG) == AVOID_KEYBOARD_END_FALG);
843     isSwitchToEmbed = isSwitchToEmbed && (!isScrollEnd || HasUnsupportedTransform());
844     UpdateMenuWhileAncestorNodeChanged(
845         isStartScroll || isStartAnimation || isTransformChanged || isStartTransition, isScrollEnd, flag);
846     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
847     CHECK_NULL_VOID(pipeline);
848     auto switchTask = [weak = WeakClaim(this), isSwitchToEmbed, isScrollEnd]() {
849         auto overlay = weak.Upgrade();
850         CHECK_NULL_VOID(overlay);
851         if (isScrollEnd) {
852             overlay->SwitchToOverlayMode();
853             return;
854         }
855         if (isSwitchToEmbed) {
856             overlay->SwitchToEmbedMode();
857         }
858     };
859     if (AnimationUtils::IsImplicitAnimationOpen()) {
860         switchTask();
861     } else {
862         pipeline->AddAfterRenderTask(switchTask);
863     }
864     if ((flag & FRAME_NODE_CONTENT_CLIP_CHANGE) == FRAME_NODE_CONTENT_CLIP_CHANGE) {
865         if (IsOverlayMode() && IsHandleInParentSafeAreaPadding()) {
866             SwitchToEmbedMode();
867         }
868         UpdateViewPort();
869     }
870 }
871 
UpdateMenuWhileAncestorNodeChanged(bool shouldHideMenu,bool shouldShowMenu,FrameNodeChangeInfoFlag extraFlag)872 void BaseTextSelectOverlay::UpdateMenuWhileAncestorNodeChanged(
873     bool shouldHideMenu, bool shouldShowMenu, FrameNodeChangeInfoFlag extraFlag)
874 {
875     auto manager = GetManager<SelectContentOverlayManager>();
876     CHECK_NULL_VOID(manager);
877     if (shouldHideMenu) {
878         manager->HideOptionMenu(true);
879         return;
880     }
881     if ((extraFlag & AVOID_KEYBOARD_END_FALG) == AVOID_KEYBOARD_END_FALG && !GetIsHandleDragging()) {
882         manager->ShowOptionMenu();
883         return;
884     }
885     if (shouldShowMenu && originalMenuIsShow_ && !GetIsHandleDragging() && !GetSelectArea().IsEmpty()) {
886         manager->ShowOptionMenu();
887     }
888 }
889 
IsAncestorNodeStartAnimation(FrameNodeChangeInfoFlag flag)890 bool BaseTextSelectOverlay::IsAncestorNodeStartAnimation(FrameNodeChangeInfoFlag flag)
891 {
892     return ((flag & FRAME_NODE_CHANGE_START_ANIMATION) == FRAME_NODE_CHANGE_START_ANIMATION);
893 }
894 
IsAncestorNodeGeometryChange(FrameNodeChangeInfoFlag flag)895 bool BaseTextSelectOverlay::IsAncestorNodeGeometryChange(FrameNodeChangeInfoFlag flag)
896 {
897     return ((flag & FRAME_NODE_CHANGE_GEOMETRY_CHANGE) == FRAME_NODE_CHANGE_GEOMETRY_CHANGE);
898 }
899 
IsAncestorNodeStartScroll(FrameNodeChangeInfoFlag flag)900 bool BaseTextSelectOverlay::IsAncestorNodeStartScroll(FrameNodeChangeInfoFlag flag)
901 {
902     return ((flag & FRAME_NODE_CHANGE_START_SCROLL) == FRAME_NODE_CHANGE_START_SCROLL);
903 }
904 
IsAncestorNodeEndScroll(FrameNodeChangeInfoFlag flag)905 bool BaseTextSelectOverlay::IsAncestorNodeEndScroll(FrameNodeChangeInfoFlag flag)
906 {
907     return ((flag & FRAME_NODE_CHANGE_END_SCROLL) == FRAME_NODE_CHANGE_END_SCROLL);
908 }
909 
IsAncestorNodeTransformChange(FrameNodeChangeInfoFlag flag)910 bool BaseTextSelectOverlay::IsAncestorNodeTransformChange(FrameNodeChangeInfoFlag flag)
911 {
912     return ((flag & FRAME_NODE_CHANGE_TRANSFORM_CHANGE) == FRAME_NODE_CHANGE_TRANSFORM_CHANGE);
913 }
914 
IsAncestorNodeHasTransition(FrameNodeChangeInfoFlag flag)915 bool BaseTextSelectOverlay::IsAncestorNodeHasTransition(FrameNodeChangeInfoFlag flag)
916 {
917     return ((flag & FRAME_NODE_CHANGE_TRANSITION_START) == FRAME_NODE_CHANGE_TRANSITION_START);
918 }
919 
IsTouchAtHandle(const TouchEventInfo & info)920 bool BaseTextSelectOverlay::IsTouchAtHandle(const TouchEventInfo& info)
921 {
922     auto overlayManager = GetManager<SelectContentOverlayManager>();
923     CHECK_NULL_RETURN(overlayManager, false);
924     CHECK_NULL_RETURN(!info.GetTouches().empty(), false);
925     auto touchType = info.GetTouches().front().GetTouchType();
926     if (touchType == TouchType::DOWN) {
927         auto localOffset = info.GetTouches().front().GetLocalLocation();
928         auto globalOffset = info.GetTouches().front().GetGlobalLocation();
929         touchAtHandle_ = overlayManager->IsTouchAtHandle(
930             PointF(localOffset.GetX(), localOffset.GetY()), PointF(globalOffset.GetX(), globalOffset.GetY()));
931     } else if (touchType == TouchType::UP) {
932         if (touchAtHandle_) {
933             touchAtHandle_ = false;
934             return true;
935         }
936     }
937     return touchAtHandle_;
938 }
939 
IsClickAtHandle(const GestureEvent & info)940 bool BaseTextSelectOverlay::IsClickAtHandle(const GestureEvent& info)
941 {
942     auto overlayManager = GetManager<SelectContentOverlayManager>();
943     CHECK_NULL_RETURN(overlayManager, false);
944     auto localOffset = info.GetLocalLocation();
945     auto globalOffset = info.GetGlobalLocation();
946     return overlayManager->IsTouchAtHandle(
947         PointF(localOffset.GetX(), localOffset.GetY()), PointF(globalOffset.GetX(), globalOffset.GetY()));
948 }
949 
HasUnsupportedTransform(bool checkScale)950 bool BaseTextSelectOverlay::HasUnsupportedTransform(bool checkScale)
951 {
952     auto pattern = GetPattern<Pattern>();
953     CHECK_NULL_RETURN(pattern, false);
954     auto parent = pattern->GetHost();
955     CHECK_NULL_RETURN(parent, false);
956     while (parent) {
957         auto renderContext = parent->GetRenderContext();
958         CHECK_NULL_RETURN(renderContext, false);
959         if (parent->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
960             return false;
961         }
962         if (renderContext->HasMotionPath()) {
963             return true;
964         }
965         auto rotateVector = renderContext->GetTransformRotate();
966         if (rotateVector.has_value() && !NearZero(rotateVector->w) &&
967             !(NearZero(rotateVector->x) && NearZero(rotateVector->y) && NearZero(rotateVector->z))) {
968             return true;
969         }
970         if (CheckUnsupportedTransformMatrix(renderContext, checkScale)) {
971             return true;
972         }
973         auto translate = renderContext->GetTransformTranslate();
974         if (translate && !NearZero(translate->z.Value())) {
975             return true;
976         }
977         if (checkScale) {
978             auto scale = renderContext->GetTransformScale();
979             if (scale && (!NearEqual(scale->x, 1.0f) || !NearEqual(scale->y, 1.0f))) {
980                 return true;
981             }
982         }
983         parent = parent->GetAncestorNodeOfFrame(true);
984     }
985     return false;
986 }
987 
CheckUnsupportedTransformMatrix(const RefPtr<RenderContext> context,bool checkScale)988 bool BaseTextSelectOverlay::CheckUnsupportedTransformMatrix(const RefPtr<RenderContext> context, bool checkScale)
989 {
990     auto transformMatrix = context->GetTransformMatrix();
991     if (!transformMatrix) {
992         return false;
993     }
994     DecomposedTransform transform;
995     TransformUtil::DecomposeTransform(transform, transformMatrix.value());
996     Quaternion identity(0.0f, 0.0f, 0.0f, 1.0f);
997     const int32_t zTranslateIndex = 2;
998     if (transform.quaternion != identity || !NearZero(transform.translate[zTranslateIndex])) {
999         return true;
1000     }
1001     if (checkScale) {
1002         for (const auto& scalValue : transform.scale) {
1003             if (!NearEqual(scalValue, 1.0f)) {
1004                 return true;
1005             }
1006         }
1007     }
1008     return false;
1009 }
1010 
CheckSwitchToMode(HandleLevelMode mode)1011 bool BaseTextSelectOverlay::CheckSwitchToMode(HandleLevelMode mode)
1012 {
1013     if (mode == HandleLevelMode::OVERLAY && (HasUnsupportedTransform() || IsHandleInParentSafeAreaPadding())) {
1014         return false;
1015     }
1016     return true;
1017 }
1018 
OnSelectionMenuOptionsUpdate(const NG::OnCreateMenuCallback && onCreateMenuCallback,const NG::OnMenuItemClickCallback && onMenuItemClick,const NG::OnPrepareMenuCallback && onPrepareMenuCallback)1019 void BaseTextSelectOverlay::OnSelectionMenuOptionsUpdate(const NG::OnCreateMenuCallback&& onCreateMenuCallback,
1020     const NG::OnMenuItemClickCallback&& onMenuItemClick, const NG::OnPrepareMenuCallback&& onPrepareMenuCallback)
1021 {
1022     onCreateMenuCallback_ = onCreateMenuCallback;
1023     onMenuItemClick_ = onMenuItemClick;
1024     onPrepareMenuCallback_ = onPrepareMenuCallback;
1025 }
1026 
RegisterScrollingListener(const RefPtr<FrameNode> scrollableNode)1027 void BaseTextSelectOverlay::RegisterScrollingListener(const RefPtr<FrameNode> scrollableNode)
1028 {
1029     if (hasRegisterListener_) {
1030         return;
1031     }
1032     auto scrollingNode = scrollableNode;
1033     if (!scrollingNode) {
1034         auto host = GetOwner();
1035         CHECK_NULL_VOID(host);
1036         scrollingNode = host->GetAncestorNodeOfFrame(true);
1037         while (scrollingNode) {
1038             if (scrollingNode->GetTag() == V2::SWIPER_ETS_TAG) {
1039                 break;
1040             }
1041             scrollingNode = scrollingNode->GetAncestorNodeOfFrame(true);
1042         }
1043     }
1044     if (scrollingNode) {
1045         auto pattern = scrollingNode->GetPattern<Pattern>();
1046         CHECK_NULL_VOID(pattern);
1047         auto scrollCallback = [weak = WeakClaim(this), scrollNode = WeakClaim(AceType::RawPtr(scrollableNode))] {
1048             auto overlay = weak.Upgrade();
1049             CHECK_NULL_VOID(overlay);
1050             overlay->OnHandleScrolling(scrollNode);
1051         };
1052         auto scrollListener = AceType::MakeRefPtr<ScrollingListener>(scrollCallback);
1053         pattern->RegisterScrollingListener(scrollListener);
1054         hasRegisterListener_ = true;
1055     }
1056 }
1057 
OnHandleScrolling(const WeakPtr<FrameNode> & scrollingNode)1058 void BaseTextSelectOverlay::OnHandleScrolling(const WeakPtr<FrameNode>& scrollingNode)
1059 {
1060     if (SelectOverlayIsOn()) {
1061         HideMenu(true);
1062         auto taskExecutor = Container::CurrentTaskExecutor();
1063         CHECK_NULL_VOID(taskExecutor);
1064         taskExecutor->PostTask(
1065             [weak = WeakClaim(this), scrollingNode] {
1066                 auto overlay = weak.Upgrade();
1067                 CHECK_NULL_VOID(overlay);
1068                 overlay->hasRegisterListener_ = false;
1069                 if (overlay->SelectOverlayIsOn()) {
1070                     overlay->RegisterScrollingListener(scrollingNode.Upgrade());
1071                 }
1072             },
1073             TaskExecutor::TaskType::UI, "RegisterScrollingListener");
1074     } else {
1075         hasRegisterListener_ = false;
1076     }
1077 }
1078 
CheckAndUpdateHostGlobalPaintRect()1079 bool BaseTextSelectOverlay::CheckAndUpdateHostGlobalPaintRect()
1080 {
1081     auto host = GetOwner();
1082     CHECK_NULL_RETURN(host, false);
1083     auto geometryNode = host->GetGeometryNode();
1084     CHECK_NULL_RETURN(geometryNode, false);
1085     auto framePaintRect = RectF(host->GetTransformRelativeOffset(), geometryNode->GetFrameSize());
1086     auto changed = globalPaintRect_.GetOffset() != framePaintRect.GetOffset();
1087     globalPaintRect_ = framePaintRect;
1088     return changed;
1089 }
1090 
CheckHasTransformAttr()1091 bool BaseTextSelectOverlay::CheckHasTransformAttr()
1092 {
1093     auto pattern = GetPattern<Pattern>();
1094     CHECK_NULL_RETURN(pattern, false);
1095     auto host = pattern->GetHost();
1096     CHECK_NULL_RETURN(host, false);
1097     auto hasTransform = false;
1098     VectorF scaleIdentity(1.0f, 1.0f);
1099     Vector5F rotateIdentity(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
1100     while (host) {
1101         auto renderContext = host->GetRenderContext();
1102         CHECK_NULL_RETURN(renderContext, false);
1103         if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
1104             break;
1105         }
1106         if (renderContext->HasMotionPath()) {
1107             hasTransform = true;
1108             break;
1109         }
1110         // has rotate.
1111         auto rotateVector = renderContext->GetTransformRotate();
1112         if (rotateVector.has_value() && !(rotateIdentity == rotateVector.value())) {
1113             hasTransform = true;
1114             break;
1115         }
1116         // has scale.
1117         auto scaleVector = renderContext->GetTransformScale();
1118         if (scaleVector.has_value() && !(scaleIdentity == scaleVector.value())) {
1119             hasTransform = true;
1120             break;
1121         }
1122         // has z translate.
1123         auto translate = renderContext->GetTransformTranslate();
1124         if (translate && !NearZero(translate->z.Value())) {
1125             hasTransform = true;
1126             break;
1127         }
1128         if (CheckHasTransformMatrix(renderContext)) {
1129             hasTransform = true;
1130             break;
1131         }
1132         host = host->GetAncestorNodeOfFrame(true);
1133     }
1134     return hasTransform;
1135 }
1136 
CheckHasTransformMatrix(const RefPtr<RenderContext> & context)1137 bool BaseTextSelectOverlay::CheckHasTransformMatrix(const RefPtr<RenderContext>& context)
1138 {
1139     auto transformMatrix = context->GetTransformMatrix();
1140     CHECK_NULL_RETURN(transformMatrix, false);
1141     const int32_t xIndex = 0;
1142     const int32_t yIndex = 1;
1143     const int32_t zIndex = 2;
1144     const int32_t wIndex = 3;
1145     DecomposedTransform transform;
1146     TransformUtil::DecomposeTransform(transform, transformMatrix.value());
1147     if (!NearZero(transform.translate[zIndex])) {
1148         return true;
1149     }
1150     Quaternion quaternionIdentity(0.0f, 0.0f, 0.0f, 1.0f);
1151     if (transform.quaternion != quaternionIdentity) {
1152         return true;
1153     }
1154     Vector3F scaleIdentity(1.0f, 1.0f, 1.0f);
1155     Vector3F scaleVector(transform.scale[xIndex], transform.scale[yIndex], transform.scale[zIndex]);
1156     if (!(scaleVector == scaleIdentity)) {
1157         return true;
1158     }
1159     Vector3F skewIdentity(0.0f, 0.0f, 0.0f);
1160     Vector3F skewVector(transform.skew[xIndex], transform.skew[yIndex], transform.skew[zIndex]);
1161     if (!(skewVector == skewIdentity)) {
1162         return true;
1163     }
1164     Vector4F perspectiveIdentity(0.0f, 0.0f, 0.0f, 1.0f);
1165     Vector4F perspectiveVector(transform.perspective[xIndex], transform.perspective[yIndex],
1166         transform.perspective[zIndex], transform.perspective[wIndex]);
1167     return !(perspectiveVector == perspectiveIdentity);
1168 }
1169 
GetClipHandleViewPort(RectF & rect)1170 bool BaseTextSelectOverlay::GetClipHandleViewPort(RectF& rect)
1171 {
1172     auto host = GetOwner();
1173     CHECK_NULL_RETURN(host, false);
1174     if (HasUnsupportedTransform()) {
1175         return false;
1176     }
1177     RectF contentRect;
1178     if (!GetFrameNodeContentRect(host, contentRect)) {
1179         return false;
1180     }
1181     contentRect.SetOffset(contentRect.GetOffset() + host->GetPaintRectWithTransform().GetOffset());
1182     CHECK_NULL_RETURN(CalculateClippedRect(contentRect), false);
1183     UpdateClipHandleViewPort(contentRect);
1184     rect = contentRect;
1185     return true;
1186 }
1187 
CalculateClippedRect(RectF & contentRect)1188 bool BaseTextSelectOverlay::CalculateClippedRect(RectF& contentRect)
1189 {
1190     auto host = GetOwner();
1191     CHECK_NULL_RETURN(host, false);
1192     auto parent = host->GetAncestorNodeOfFrame(true);
1193     while (parent) {
1194         RectF parentContentRect;
1195         if (!GetFrameNodeContentRect(parent, parentContentRect)) {
1196             return false;
1197         }
1198         auto renderContext = parent->GetRenderContext();
1199         CHECK_NULL_RETURN(renderContext, false);
1200         if (renderContext->GetClipEdge().value_or(false)) {
1201             auto isOverTheParentBottom = GreatNotEqual(contentRect.Top(), parentContentRect.Bottom());
1202             contentRect = contentRect.IntersectRectT(parentContentRect);
1203             if (isOverTheParentBottom) {
1204                 contentRect.SetTop(parentContentRect.Bottom());
1205             }
1206         }
1207         contentRect.SetOffset(contentRect.GetOffset() + parent->GetPaintRectWithTransform().GetOffset());
1208         contentRect.SetWidth(std::max(contentRect.Width(), 0.0f));
1209         contentRect.SetHeight(std::max(contentRect.Height(), 0.0f));
1210         parent = parent->GetAncestorNodeOfFrame(true);
1211     }
1212     contentRect.SetWidth(std::max(contentRect.Width(), 0.0f));
1213     contentRect.SetHeight(std::max(contentRect.Height(), 0.0f));
1214     return true;
1215 }
1216 
GetFrameNodeContentRect(const RefPtr<FrameNode> & node,RectF & contentRect)1217 bool BaseTextSelectOverlay::GetFrameNodeContentRect(const RefPtr<FrameNode>& node, RectF& contentRect)
1218 {
1219     CHECK_NULL_RETURN(node, false);
1220     if (GetScrollableClipContentRect(node, contentRect)) {
1221         return true;
1222     }
1223     auto geometryNode = node->GetGeometryNode();
1224     CHECK_NULL_RETURN(geometryNode, false);
1225     auto renderContext = node->GetRenderContext();
1226     CHECK_NULL_RETURN(renderContext, false);
1227     if (geometryNode->GetContent()) {
1228         contentRect = geometryNode->GetContentRect();
1229     } else {
1230         contentRect = RectF(OffsetF(0.0f, 0.0f), geometryNode->GetFrameSize());
1231     }
1232     return true;
1233 }
1234 
MarkOverlayDirty()1235 void BaseTextSelectOverlay::MarkOverlayDirty()
1236 {
1237     if (SelectOverlayIsOn()) {
1238         auto host = GetOwner();
1239         CHECK_NULL_VOID(host);
1240         auto overlayNode = host->GetOverlayNode();
1241         CHECK_NULL_VOID(overlayNode);
1242         overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1243     }
1244 }
1245 
ApplySelectAreaWithKeyboard(RectF & selectArea)1246 void BaseTextSelectOverlay::ApplySelectAreaWithKeyboard(RectF& selectArea)
1247 {
1248     if (Negative(selectArea.Top())) {
1249         selectArea.SetHeight(selectArea.Height() + selectArea.Top());
1250         selectArea.SetTop(0.0f);
1251     }
1252     auto host = GetOwner();
1253     CHECK_NULL_VOID(host);
1254     auto pipeline = host->GetContext();
1255     CHECK_NULL_VOID(pipeline);
1256     auto safeAreaManager = pipeline->GetSafeAreaManager();
1257     CHECK_NULL_VOID(safeAreaManager);
1258     auto keyboardInset = safeAreaManager->GetKeyboardInset();
1259     if (keyboardInset.Length() <= 0) {
1260         return;
1261     }
1262     if (GreatOrEqual(selectArea.Top(), keyboardInset.start)) {
1263         selectArea.SetHeight(0.0f);
1264     }
1265 }
1266 
OnHandleMarkInfoChange(const std::shared_ptr<SelectOverlayInfo> info,SelectOverlayDirtyFlag flag)1267 void BaseTextSelectOverlay::OnHandleMarkInfoChange(
1268     const std::shared_ptr<SelectOverlayInfo> info, SelectOverlayDirtyFlag flag)
1269 {
1270     auto manager = GetManager<SelectContentOverlayManager>();
1271     CHECK_NULL_VOID(manager);
1272     if ((flag & DIRTY_HANDLE_COLOR_FLAG) == DIRTY_HANDLE_COLOR_FLAG) {
1273         info->handlerColor = GetHandleColor();
1274         manager->MarkHandleDirtyNode(PROPERTY_UPDATE_RENDER);
1275     }
1276     if ((flag & DIRTY_FIRST_HANDLE) == DIRTY_FIRST_HANDLE ||
1277         (flag & DIRTY_SECOND_HANDLE) == DIRTY_SECOND_HANDLE) {
1278         if (info->menuInfo.showTranslate != (menuTranslateIsSupport_ && AllowTranslate() &&
1279             IsNeedMenuTranslate())) {
1280             info->menuInfo.showTranslate = !info->menuInfo.showTranslate;
1281             manager->NotifyUpdateToolBar(true);
1282         }
1283         if (info->menuInfo.showSearch != (isSupportMenuSearch_ && AllowSearch() &&
1284             IsNeedMenuSearch())) {
1285             info->menuInfo.showSearch = !info->menuInfo.showSearch;
1286             manager->NotifyUpdateToolBar(true);
1287         }
1288         if (info->menuInfo.showShare != (IsSupportMenuShare() && AllowShare() &&
1289             IsNeedMenuShare())) {
1290             info->menuInfo.showShare = !info->menuInfo.showShare;
1291             manager->NotifyUpdateToolBar(true);
1292         }
1293     }
1294 }
1295 
UpdateHandleColor()1296 void BaseTextSelectOverlay::UpdateHandleColor()
1297 {
1298     auto manager = GetManager<SelectContentOverlayManager>();
1299     CHECK_NULL_VOID(manager);
1300     manager->MarkInfoChange(DIRTY_HANDLE_COLOR_FLAG);
1301 }
1302 
IsNeedMenuTranslate()1303 bool BaseTextSelectOverlay::IsNeedMenuTranslate()
1304 {
1305     auto translation = GetSelectedText();
1306     return !std::regex_match(translation, std::regex("^\\s*$"));
1307 }
1308 
ConvertWindowToScreenDomain(RectF rect)1309 RectF BaseTextSelectOverlay::ConvertWindowToScreenDomain(RectF rect)
1310 {
1311     auto host = GetOwner();
1312     CHECK_NULL_RETURN(host, rect);
1313     auto pipeline = host->GetContext();
1314     CHECK_NULL_RETURN(pipeline, rect);
1315     Rect windowOffset = pipeline->GetDisplayWindowRectInfo();
1316     rect.SetLeft(rect.Left() + windowOffset.Left());
1317     rect.SetTop(rect.Top() + windowOffset.Top());
1318     return rect;
1319 }
1320 
ConvertWindowToScreenDomain(EdgeF edge)1321 EdgeF BaseTextSelectOverlay::ConvertWindowToScreenDomain(EdgeF edge)
1322 {
1323     auto host = GetOwner();
1324     CHECK_NULL_RETURN(host, edge);
1325     auto pipeline = host->GetContext();
1326     CHECK_NULL_RETURN(pipeline, edge);
1327     Rect windowOffset = pipeline->GetDisplayWindowRectInfo();
1328     edge.x += windowOffset.Left();
1329     edge.y += windowOffset.Top();
1330     return edge;
1331 }
1332 
GetTranslateParamRectStr(RectF rect,EdgeF rectLeftTop,EdgeF rectRightBottom)1333 std::string BaseTextSelectOverlay::GetTranslateParamRectStr(RectF rect, EdgeF rectLeftTop, EdgeF rectRightBottom)
1334 {
1335     auto jsonValue = JsonUtil::Create(true);
1336     jsonValue->Put("x", std::round(rect.GetX()));
1337     jsonValue->Put("y", std::round(rect.GetY()));
1338     jsonValue->Put("width", std::round(rect.Width()));
1339     jsonValue->Put("height", std::round(rect.Height()));
1340     jsonValue->Put("startLeft", std::round(rectLeftTop.x));
1341     jsonValue->Put("startTop", std::round(rectLeftTop.y));
1342     jsonValue->Put("endRight", std::round(rectRightBottom.x));
1343     jsonValue->Put("endBottom", std::round(rectRightBottom.y));
1344     return jsonValue->ToString();
1345 }
1346 
HandleOnTranslate()1347 void BaseTextSelectOverlay::HandleOnTranslate()
1348 {
1349     HideMenu(true);
1350     auto value = GetSelectedText();
1351     auto queryWord = std::regex_replace(value, std::regex("^\\s+|\\s+$"), "");
1352     if (!queryWord.empty()) {
1353         RectF rect = GetSelectArea();
1354         EdgeF rectLeftTop = GetSelectAreaStartLeftTop();
1355         EdgeF rectRightBottom = GetSelectAreaEndRightBottom();
1356         rect = ConvertWindowToScreenDomain(rect);
1357         rectLeftTop = ConvertWindowToScreenDomain(rectLeftTop);
1358         rectRightBottom = ConvertWindowToScreenDomain(rectRightBottom);
1359         TextTranslationAdapter::StartAITextTranslationTask(queryWord,
1360             GetTranslateParamRectStr(rect, rectLeftTop, rectRightBottom));
1361     }
1362 }
1363 
IsNeedMenuSearch()1364 bool BaseTextSelectOverlay::IsNeedMenuSearch()
1365 {
1366     auto searchContent = GetSelectedText();
1367     return !std::regex_match(searchContent, std::regex("^\\s*$"));
1368 }
1369 
HandleOnSearch()1370 void BaseTextSelectOverlay::HandleOnSearch()
1371 {
1372     HideMenu(true);
1373     auto value = GetSelectedText();
1374     auto queryWord = std::regex_replace(value, std::regex("^\\s+|\\s+$"), "");
1375     if (!queryWord.empty()) {
1376         auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
1377         CHECK_NULL_VOID(pipeline);
1378         pipeline->StartAbilityOnQuery(queryWord);
1379     }
1380 }
1381 
IsSupportMenuShare()1382 bool BaseTextSelectOverlay::IsSupportMenuShare()
1383 {
1384     auto container = Container::Current();
1385     if (container && container->IsSceneBoardWindow()) {
1386         return false;
1387     }
1388     return SystemProperties::IsSyscapExist(SYSTEM_CAPABILITY_OF_SHARE);
1389 }
1390 
IsNeedMenuShare()1391 bool BaseTextSelectOverlay::IsNeedMenuShare()
1392 {
1393     auto shareContent = GetSelectedText();
1394     auto shareWord = std::regex_replace(shareContent, std::regex("^\\s+|\\s+$"), "");
1395     if (shareWord.empty()) {
1396         return false;
1397     }
1398     auto maxShareLength = TextShareAdapter::GetMaxTextShareLength();
1399     if (shareWord.size() > maxShareLength) {
1400         return false;
1401     }
1402     return true;
1403 }
1404 
HandleOnShare()1405 void BaseTextSelectOverlay::HandleOnShare()
1406 {
1407     HideMenu(true);
1408     auto value = GetSelectedText();
1409     auto shareWord = std::regex_replace(value, std::regex("^\\s+|\\s+$"), "");
1410     if (!shareWord.empty()) {
1411         auto pipeline = PipelineBase::GetCurrentContextSafelyWithCheck();
1412         CHECK_NULL_VOID(pipeline);
1413         auto containerId = pipeline->GetInstanceId();
1414         auto contentRect = GetSelectArea();
1415         TextShareAdapter::StartTextShareTask(containerId, contentRect, shareWord);
1416     }
1417 }
1418 
GetScrollableClipInfo(const RefPtr<FrameNode> & node)1419 std::pair<ContentClipMode, std::optional<ContentClip>> BaseTextSelectOverlay::GetScrollableClipInfo(
1420     const RefPtr<FrameNode>& node)
1421 {
1422     auto props = DynamicCast<ScrollablePaintProperty>(node->GetPaintProperty<PaintProperty>());
1423     CHECK_NULL_RETURN(props, std::make_pair(ContentClipMode::DEFAULT, std::nullopt));
1424     auto clip = props->GetContentClip();
1425     CHECK_NULL_RETURN(clip, std::make_pair(ContentClipMode::DEFAULT, std::nullopt));
1426     auto mode = clip->first;
1427     if (mode == ContentClipMode::DEFAULT) {
1428         if (node->GetTag() == V2::GRID_ETS_TAG || node->GetTag() == V2::SCROLL_ETS_TAG) {
1429             mode = ContentClipMode::BOUNDARY;
1430         } else if (node->GetTag() == V2::LIST_ETS_TAG || node->GetTag() == V2::WATERFLOW_ETS_TAG) {
1431             mode = ContentClipMode::CONTENT_ONLY;
1432         }
1433     }
1434     return std::make_pair(mode, clip);
1435 }
1436 
GetScrollableClipContentRect(const RefPtr<FrameNode> & node,RectF & rect)1437 bool BaseTextSelectOverlay::GetScrollableClipContentRect(const RefPtr<FrameNode>& node, RectF& rect)
1438 {
1439     auto clipInfo = GetScrollableClipInfo(node);
1440     auto geo = node->GetGeometryNode();
1441     CHECK_NULL_RETURN(geo, false);
1442     switch (clipInfo.first) {
1443         case ContentClipMode::SAFE_AREA:
1444         case ContentClipMode::CONTENT_ONLY: {
1445             rect = geo->GetPaddingRect();
1446             rect.SetOffset(rect.GetOffset() - geo->GetFrameOffset());
1447             return true;
1448         }
1449         case ContentClipMode::BOUNDARY: {
1450             rect = geo->GetFrameRect();
1451             rect.SetOffset({ 0.0f, 0.0f });
1452             return true;
1453         }
1454         case ContentClipMode::CUSTOM: {
1455             auto contentClip = clipInfo.second;
1456             CHECK_NULL_RETURN(contentClip, false);
1457             auto shapeRect = contentClip->second;
1458             CHECK_NULL_RETURN(shapeRect, false);
1459             auto clipOffset = shapeRect->GetOffset();
1460             rect = RectF(clipOffset.GetX().ConvertToPx(), clipOffset.GetY().ConvertToPx(),
1461                 shapeRect->GetWidth().ConvertToPx(), shapeRect->GetHeight().ConvertToPx());
1462             return true;
1463         }
1464         default:
1465             return false;
1466     }
1467 }
1468 
CheckHandleIsInSafeAreaPadding(const RefPtr<FrameNode> & node,const RectF & handle)1469 bool BaseTextSelectOverlay::CheckHandleIsInSafeAreaPadding(const RefPtr<FrameNode>& node, const RectF& handle)
1470 {
1471     auto clipInfo = GetScrollableClipInfo(node);
1472     if (clipInfo.first != ContentClipMode::SAFE_AREA) {
1473         return false;
1474     }
1475     auto layoutProperty = node->GetLayoutProperty();
1476     CHECK_NULL_RETURN(layoutProperty, false);
1477     auto safeAreaPadding = layoutProperty->GetOrCreateSafeAreaPadding();
1478     if (!safeAreaPadding.HasValue()) {
1479         return false;
1480     }
1481     auto geo = node->GetGeometryNode();
1482     CHECK_NULL_RETURN(geo, false);
1483     auto paddingRect = geo->GetPaddingRect();
1484     if (safeAreaPadding.left && LessNotEqual(handle.Left(), paddingRect.Left())) {
1485         return true;
1486     }
1487     if (safeAreaPadding.top && LessNotEqual(handle.Top(), paddingRect.Top())) {
1488         return true;
1489     }
1490     if (safeAreaPadding.right && GreatNotEqual(handle.Right(), paddingRect.Right())) {
1491         return true;
1492     }
1493     if (safeAreaPadding.bottom && GreatNotEqual(handle.Bottom(), paddingRect.Bottom())) {
1494         return true;
1495     }
1496     return false;
1497 }
1498 
IsHandleInParentSafeAreaPadding(const RectF & firstRect,const RectF & secondRect)1499 bool BaseTextSelectOverlay::IsHandleInParentSafeAreaPadding(const RectF& firstRect, const RectF& secondRect)
1500 {
1501     auto firstHandlePaint = firstRect;
1502     auto secondHandlePaint = secondRect;
1503     auto parent = GetOwner();
1504     while (parent) {
1505         if (GetOwner() != parent) {
1506             if (CheckHandleIsInSafeAreaPadding(parent, secondHandlePaint)) {
1507                 return true;
1508             }
1509             if (!IsSingleHandle() && CheckHandleIsInSafeAreaPadding(parent, firstHandlePaint)) {
1510                 return true;
1511             }
1512         }
1513         auto context = parent->GetRenderContext();
1514         CHECK_NULL_RETURN(context, false);
1515         firstHandlePaint += context->GetPaintRectWithTransform().GetOffset();
1516         secondHandlePaint += context->GetPaintRectWithTransform().GetOffset();
1517         parent = parent->GetAncestorNodeOfFrame(true);
1518     }
1519     return false;
1520 }
1521 
IsHandleInParentSafeAreaPadding()1522 bool BaseTextSelectOverlay::IsHandleInParentSafeAreaPadding()
1523 {
1524     auto overlayManager = GetManager<SelectContentOverlayManager>();
1525     CHECK_NULL_RETURN(overlayManager, false);
1526     auto overlayInfo = overlayManager->GetSelectOverlayInfo();
1527     CHECK_NULL_RETURN(overlayInfo, false);
1528     return IsHandleInParentSafeAreaPadding(
1529         overlayInfo->firstHandle.localPaintRect, overlayInfo->secondHandle.localPaintRect);
1530 }
1531 
AddAvoidKeyboardCallback(bool isCustomKeyboard)1532 void BaseTextSelectOverlay::AddAvoidKeyboardCallback(bool isCustomKeyboard)
1533 {
1534     auto host = GetOwner();
1535     CHECK_NULL_VOID(host);
1536     auto context = host->GetContext();
1537     CHECK_NULL_VOID(context);
1538     auto textFieldManagerNg = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
1539     CHECK_NULL_VOID(textFieldManagerNg);
1540     textFieldManagerNg->AddAvoidKeyboardCallback(host->GetId(), isCustomKeyboard, [weak = WeakClaim(this)]() {
1541         auto overlay = weak.Upgrade();
1542         CHECK_NULL_VOID(overlay);
1543         if (!overlay->SelectOverlayIsOn()) {
1544             return;
1545         }
1546         auto host = overlay->GetOwner();
1547         CHECK_NULL_VOID(host);
1548         auto flag = host->GetChangeInfoFlag();
1549         host->ClearChangeInfoFlag();
1550         host->AddFrameNodeChangeInfoFlag(AVOID_KEYBOARD_END_FALG);
1551         host->ProcessFrameNodeChangeFlag();
1552         host->ClearChangeInfoFlag();
1553         host->AddFrameNodeChangeInfoFlag(flag);
1554     });
1555 }
1556 
RemoveAvoidKeyboardCallback()1557 void BaseTextSelectOverlay::RemoveAvoidKeyboardCallback()
1558 {
1559     auto host = GetOwner();
1560     CHECK_NULL_VOID(host);
1561     auto context = host->GetContext();
1562     CHECK_NULL_VOID(context);
1563     auto textFieldManagerNg = DynamicCast<TextFieldManagerNG>(context->GetTextFieldManager());
1564     CHECK_NULL_VOID(textFieldManagerNg);
1565     textFieldManagerNg->RemoveAvoidKeyboardCallback(host->GetId());
1566 }
1567 
IsHiddenHandle()1568 bool BaseTextSelectOverlay::IsHiddenHandle()
1569 {
1570     auto overlayManager = GetManager<SelectContentOverlayManager>();
1571     CHECK_NULL_RETURN(overlayManager, false);
1572     auto overlayInfo = overlayManager->GetSelectOverlayInfo();
1573     CHECK_NULL_RETURN(overlayInfo, false);
1574     return overlayInfo->isSingleHandle && overlayManager->IsHiddenHandle();
1575 }
1576 
IsHandleVisible(bool isFirst)1577 bool BaseTextSelectOverlay::IsHandleVisible(bool isFirst)
1578 {
1579     auto overlayManager = GetManager<SelectContentOverlayManager>();
1580     CHECK_NULL_RETURN(overlayManager, false);
1581     auto overlayInfo = overlayManager->GetSelectOverlayInfo();
1582     CHECK_NULL_RETURN(overlayInfo, false);
1583     return isFirst ? overlayInfo->firstHandle.isShow : overlayInfo->secondHandle.isShow;
1584 }
1585 
UpdateMenuOnWindowSizeChanged(WindowSizeChangeReason type)1586 void BaseTextSelectOverlay::UpdateMenuOnWindowSizeChanged(WindowSizeChangeReason type)
1587 {
1588     auto overlayManager = GetManager<SelectContentOverlayManager>();
1589     CHECK_NULL_VOID(overlayManager);
1590     if (overlayManager->IsRightClickSubWindowMenu()) {
1591         if (NeedsProcessMenuOnWinChange()) {
1592             CloseOverlay(false, CloseReason::CLOSE_REASON_WINDOW_SIZE_CHANGE);
1593         }
1594     } else if (overlayManager->IsSelectOverlaySubWindowMenu()) {
1595         if (isSuperFoldDisplayDevice_ && NeedsProcessMenuOnWinChange()) {
1596             CloseOverlay(false, CloseReason::CLOSE_REASON_WINDOW_SIZE_CHANGE);
1597             return;
1598         }
1599         if (overlayManager->IsMenuShow() && NeedsProcessMenuOnWinChange()) {
1600             HideMenu(true);
1601             TAG_LOGI(AceLogTag::ACE_SELECT_OVERLAY, "Hide selectoverlay subwindow menu on window size change.");
1602         }
1603     }
1604 }
1605 
IsEnableSelectionMenu()1606 bool BaseTextSelectOverlay::IsEnableSelectionMenu()
1607 {
1608     auto host = GetOwner();
1609     CHECK_NULL_RETURN(host, true);
1610     auto pipelineContext = host->GetContext();
1611     CHECK_NULL_RETURN(pipelineContext, true);
1612     auto textOverlayTheme = pipelineContext->GetTheme<TextOverlayTheme>();
1613     CHECK_NULL_RETURN(textOverlayTheme, true);
1614     return textOverlayTheme->GetEnableSelectionMenu();
1615 }
1616 
NeedsProcessMenuOnWinChange()1617 bool BaseTextSelectOverlay::NeedsProcessMenuOnWinChange()
1618 {
1619     auto host = GetOwner();
1620     CHECK_NULL_RETURN(host, false);
1621     auto pipelineContext = host->GetContext();
1622     CHECK_NULL_RETURN(pipelineContext, false);
1623     auto container = AceEngine::Get().GetContainer(pipelineContext->GetInstanceId());
1624     CHECK_NULL_RETURN(container, false);
1625     auto selectTheme = pipelineContext->GetTheme<SelectTheme>();
1626     CHECK_NULL_RETURN(selectTheme, false);
1627     return selectTheme->GetExpandDisplay() || container->IsFreeMultiWindow();
1628 }
1629 
GetDragViewHandleRects(RectF & firstRect,RectF & secondRect)1630 bool BaseTextSelectOverlay::GetDragViewHandleRects(RectF& firstRect, RectF& secondRect)
1631 {
1632     auto overlayInfo = GetSelectOverlayInfos();
1633     CHECK_NULL_RETURN(overlayInfo, false);
1634     if (overlayInfo->handleLevelMode == HandleLevelMode::OVERLAY || CheckSwitchToMode(HandleLevelMode::OVERLAY)) {
1635         firstRect = overlayInfo->firstHandle.paintRect;
1636         secondRect = overlayInfo->secondHandle.paintRect;
1637         return true;
1638     }
1639     auto pattern = GetPattern<Pattern>();
1640     CHECK_NULL_RETURN(pattern, false);
1641     auto textDragBase = AceType::DynamicCast<TextDragBase>(pattern);
1642     CHECK_NULL_RETURN(textDragBase, false);
1643     auto dragParentOffset = textDragBase->GetParentGlobalOffset();
1644     firstRect = overlayInfo->firstHandle.localPaintRect + dragParentOffset;
1645     secondRect = overlayInfo->secondHandle.localPaintRect + dragParentOffset;
1646     return true;
1647 }
1648 
UpdateIsSingleHandle(bool isSingleHandle)1649 void BaseTextSelectOverlay::UpdateIsSingleHandle(bool isSingleHandle)
1650 {
1651     SetIsSingleHandle(isSingleHandle);
1652     auto manager = GetManager<SelectContentOverlayManager>();
1653     CHECK_NULL_VOID(manager);
1654     manager->UpdateIsSingleHandle(isSingleHandle);
1655 }
1656 } // namespace OHOS::Ace::NG
1657