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