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/utils.h"
19 #include "core/components_ng/pattern/pattern.h"
20 #include "core/components_ng/pattern/scrollable/nestable_scroll_container.h"
21 #include "core/components_ng/pattern/select_overlay/select_overlay_property.h"
22 #include "core/components_ng/pattern/text_field/text_field_manager.h"
23 #include "core/components_v2/inspector/inspector_constants.h"
24 
25 namespace OHOS::Ace::NG {
26 namespace {
27 constexpr int32_t NO_NEED_RESTART_SINGLE_HANDLE = 100;
28 } // namespace
ProcessOverlay(const OverlayRequest & request)29 void BaseTextSelectOverlay::ProcessOverlay(const OverlayRequest& request)
30 {
31     UpdateTransformFlag();
32     if (!PreProcessOverlay(request) || AnimationUtils::IsImplicitAnimationOpen()) {
33         return;
34     }
35     auto checkClipboard = [weak = WeakClaim(this), request](bool hasData) {
36         TAG_LOGI(AceLogTag::ACE_TEXT, "HasData callback from clipboard, data available ? %{public}d", hasData);
37         auto overlay = weak.Upgrade();
38         CHECK_NULL_VOID(overlay);
39         overlay->ShowSelectOverlay(request, hasData);
40     };
41     auto textBase = hostTextBase_.Upgrade();
42     CHECK_NULL_VOID(textBase);
43     auto clipboard = textBase->GetClipboard();
44     if (clipboard) {
45         auto mimeTypes = GetPasteMimeTypes();
46         if (!mimeTypes.empty()) {
47             clipboard->HasDataType(checkClipboard, mimeTypes);
48             return;
49         }
50         clipboard->HasData(checkClipboard);
51     } else {
52         checkClipboard(false);
53     }
54 }
55 
ShowSelectOverlay(const OverlayRequest & request,bool hasClipboardData)56 void BaseTextSelectOverlay::ShowSelectOverlay(const OverlayRequest& request, bool hasClipboardData)
57 {
58     SetShowPaste(hasClipboardData);
59     SetMenuIsShow(request.menuIsShow);
60     SetIsShowHandleLine(!request.hideHandleLine);
61     latestReqeust_ = request;
62     if (!SelectOverlayIsOn() && enableHandleLevel_) {
63         auto firstLocalRect = GetFirstHandleLocalPaintRect();
64         auto secondLocalRect = GetSecondHandleLocalPaintRect();
65         CalcHandleLevelMode(firstLocalRect, secondLocalRect);
66     }
67     if (enableHandleLevel_) {
68         auto host = GetOwner();
69         CHECK_NULL_VOID(host);
70         host->RegisterNodeChangeListener();
71         RegisterScrollingListener(nullptr);
72         CheckAndUpdateHostGlobalPaintRect();
73     }
74     auto manager = SelectContentOverlayManager::GetOverlayManager(Claim(this));
75     CHECK_NULL_VOID(manager);
76     manager->Show(request.animation, request.requestCode);
77 }
78 
ProcessOverlayOnAreaChanged(const OverlayRequest & request)79 void BaseTextSelectOverlay::ProcessOverlayOnAreaChanged(const OverlayRequest& request)
80 {
81     auto overlayRequest = request;
82     overlayRequest.requestCode = NO_NEED_RESTART_SINGLE_HANDLE;
83     ProcessOverlay(overlayRequest);
84 }
85 
CheckRestartHiddenHandleTask(int32_t requestCode)86 bool BaseTextSelectOverlay::CheckRestartHiddenHandleTask(int32_t requestCode)
87 {
88     return requestCode != NO_NEED_RESTART_SINGLE_HANDLE;
89 }
90 
IsShowMouseMenu()91 bool BaseTextSelectOverlay::IsShowMouseMenu()
92 {
93     auto overlayManager = GetManager<SelectContentOverlayManager>();
94     CHECK_NULL_RETURN(overlayManager, false);
95     return overlayManager->GetShowMenuType() == OptionMenuType::MOUSE_MENU;
96 }
97 
IsCurrentMenuVisibile()98 bool BaseTextSelectOverlay::IsCurrentMenuVisibile()
99 {
100     auto overlayManager = GetManager<SelectContentOverlayManager>();
101     CHECK_NULL_RETURN(overlayManager, false);
102     return overlayManager->IsMenuShow();
103 }
104 
IsHandleReverse()105 bool BaseTextSelectOverlay::IsHandleReverse()
106 {
107     auto overlayManager = GetManager<SelectContentOverlayManager>();
108     CHECK_NULL_RETURN(overlayManager, false);
109     return overlayManager->IsHandleReverse();
110 }
111 
SelectOverlayIsOn()112 bool BaseTextSelectOverlay::SelectOverlayIsOn()
113 {
114     auto manager = GetManager<SelectContentOverlayManager>();
115     CHECK_NULL_RETURN(manager, false);
116     return manager->IsOpen();
117 }
118 
SelectOverlayIsCreating()119 bool BaseTextSelectOverlay::SelectOverlayIsCreating()
120 {
121     auto manager = GetManager<SelectContentOverlayManager>();
122     CHECK_NULL_RETURN(manager, false);
123     return manager->IsCreating();
124 }
125 
CloseOverlay(bool animation,CloseReason reason)126 void BaseTextSelectOverlay::CloseOverlay(bool animation, CloseReason reason)
127 {
128     auto overlayManager = GetManager<SelectContentOverlayManager>();
129     CHECK_NULL_VOID(overlayManager);
130     overlayManager->Close(GetOwnerId(), false, reason);
131     AfterCloseOverlay();
132 }
133 
ToggleMenu()134 void BaseTextSelectOverlay::ToggleMenu()
135 {
136     auto manager = GetManager<SelectContentOverlayManager>();
137     CHECK_NULL_VOID(manager);
138     manager->ToggleOptionMenu();
139     UpdateOriginalMenuIsShow();
140 }
141 
ShowMenu()142 void BaseTextSelectOverlay::ShowMenu()
143 {
144     auto manager = GetManager<SelectContentOverlayManager>();
145     CHECK_NULL_VOID(manager);
146     manager->ShowOptionMenu();
147     UpdateOriginalMenuIsShow();
148 }
149 
HideMenu(bool noAnimation)150 void BaseTextSelectOverlay::HideMenu(bool noAnimation)
151 {
152     auto manager = GetManager<SelectContentOverlayManager>();
153     CHECK_NULL_VOID(manager);
154     manager->HideOptionMenu(noAnimation);
155     UpdateOriginalMenuIsShow();
156 }
157 
DisableMenu()158 void BaseTextSelectOverlay::DisableMenu()
159 {
160     auto manager = GetManager<SelectContentOverlayManager>();
161     CHECK_NULL_VOID(manager);
162     manager->DisableMenu();
163 }
164 
EnableMenu()165 void BaseTextSelectOverlay::EnableMenu()
166 {
167     auto manager = GetManager<SelectContentOverlayManager>();
168     CHECK_NULL_VOID(manager);
169     manager->EnableMenu();
170 }
171 
UpdateAllHandlesOffset()172 void BaseTextSelectOverlay::UpdateAllHandlesOffset()
173 {
174     auto manager = GetManager<SelectContentOverlayManager>();
175     CHECK_NULL_VOID(manager);
176     manager->MarkInfoChange(DIRTY_DOUBLE_HANDLE | DIRTY_SELECT_AREA);
177 }
178 
UpdateFirstHandleOffset()179 void BaseTextSelectOverlay::UpdateFirstHandleOffset()
180 {
181     auto manager = GetManager<SelectContentOverlayManager>();
182     CHECK_NULL_VOID(manager);
183     manager->MarkInfoChange(DIRTY_FIRST_HANDLE);
184 }
185 
UpdateSecondHandleOffset()186 void BaseTextSelectOverlay::UpdateSecondHandleOffset()
187 {
188     auto manager = GetManager<SelectContentOverlayManager>();
189     CHECK_NULL_VOID(manager);
190     manager->MarkInfoChange(DIRTY_SECOND_HANDLE);
191 }
192 
UpdateViewPort()193 void BaseTextSelectOverlay::UpdateViewPort()
194 {
195     auto manager = GetManager<SelectContentOverlayManager>();
196     CHECK_NULL_VOID(manager);
197     manager->MarkInfoChange(DIRTY_VIEWPORT);
198 }
199 
GetOwner()200 RefPtr<FrameNode> BaseTextSelectOverlay::GetOwner()
201 {
202     auto pattern = GetPattern<Pattern>();
203     CHECK_NULL_RETURN(pattern, nullptr);
204     return pattern->GetHost();
205 }
206 
OnHandleGlobalTouchEvent(SourceType sourceType,TouchType touchType,bool touchInside)207 void BaseTextSelectOverlay::OnHandleGlobalTouchEvent(SourceType sourceType, TouchType touchType, bool touchInside)
208 {
209     if (IsMouseClickDown(sourceType, touchType)) {
210         CloseOverlay(false, CloseReason::CLOSE_REASON_CLICK_OUTSIDE);
211     } else if (IsTouchUp(sourceType, touchType)) {
212         HideMenu(true);
213     }
214 }
215 
CheckTouchInHostNode(const PointF & touchPoint)216 bool BaseTextSelectOverlay::CheckTouchInHostNode(const PointF& touchPoint)
217 {
218     auto host = GetOwner();
219     CHECK_NULL_RETURN(host, false);
220     auto geo = host->GetGeometryNode();
221     CHECK_NULL_RETURN(geo, false);
222     auto rect = RectF(OffsetF(0.0f, 0.0f), geo->GetFrameSize());
223     return rect.IsInRegion(touchPoint);
224 }
225 
OnUpdateSelectOverlayInfo(SelectOverlayInfo & overlayInfo,int32_t requestCode)226 void BaseTextSelectOverlay::OnUpdateSelectOverlayInfo(SelectOverlayInfo& overlayInfo, int32_t requestCode)
227 {
228     overlayInfo.isSingleHandle = isSingleHandle_;
229     overlayInfo.isHandleLineShow = isShowHandleLine_;
230     overlayInfo.recreateOverlay = isUsingMouse_;
231     overlayInfo.rightClickOffset = mouseMenuOffset_;
232     overlayInfo.isUsingMouse = isUsingMouse_;
233     overlayInfo.isNewAvoid = true;
234     overlayInfo.hitTestMode = HitTestMode::HTMDEFAULT;
235     if (hasTransform_) {
236         overlayInfo.callerNodeInfo = {
237             .paintFrameRect = GetPaintRectWithTransform(),
238             .paintOffset = GetPaintRectOffsetWithTransform()
239         };
240     }
241     overlayInfo.ancestorViewPort = GetAncestorNodeViewPort();
242     overlayInfo.enableHandleLevel = enableHandleLevel_;
243     overlayInfo.handleLevelMode = handleLevelMode_;
244     if (enableHandleLevel_) {
245         overlayInfo.scale = GetHostScale();
246     }
247     overlayInfo.afterOnClick = [weak = WeakClaim(this)](const GestureEvent&, bool isFirst) {
248         auto overlay = weak.Upgrade();
249         CHECK_NULL_VOID(overlay);
250         overlay->UpdateOriginalMenuIsShow();
251     };
252 }
253 
GetVisibleRect(const RefPtr<FrameNode> & node,const RectF & visibleRect)254 RectF BaseTextSelectOverlay::GetVisibleRect(const RefPtr<FrameNode>& node, const RectF& visibleRect)
255 {
256     CHECK_NULL_RETURN(node, visibleRect);
257     auto parentNode = node->GetAncestorNodeOfFrame(true);
258     CHECK_NULL_RETURN(parentNode, visibleRect);
259     if (parentNode->GetTag() == V2::PAGE_ETS_TAG) {
260         return visibleRect;
261     }
262     auto intersectRect = visibleRect;
263     auto scrollablePattern = AceType::DynamicCast<NestableScrollContainer>(parentNode->GetPattern());
264     auto geometryNode = parentNode->GetGeometryNode();
265     if (scrollablePattern && geometryNode) {
266         auto parentViewPort = RectF(parentNode->GetTransformRelativeOffset(), geometryNode->GetFrameSize());
267         if (parentViewPort.IsIntersectWith(visibleRect)) {
268             intersectRect = parentViewPort.IntersectRectT(visibleRect);
269         } else {
270             return RectF(0, 0, 0, 0);
271         }
272     }
273     return GetVisibleRect(parentNode, intersectRect);
274 }
275 
RemoveSelectionHoldCallback()276 void BaseTextSelectOverlay::RemoveSelectionHoldCallback()
277 {
278     auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
279     CHECK_NULL_VOID(overlayManager);
280     overlayManager->RemoveHoldSelectionCallback(GetOwnerId());
281 }
282 
SetSelectionHoldCallback()283 void BaseTextSelectOverlay::SetSelectionHoldCallback()
284 {
285     auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
286     CHECK_NULL_VOID(overlayManager);
287     HoldSelectionInfo selectionInfo;
288     selectionInfo.resetSelectionCallback = [weak = WeakClaim(this)]() {
289         auto overlay = weak.Upgrade();
290         CHECK_NULL_VOID(overlay);
291         overlay->OnResetTextSelection();
292     };
293     selectionInfo.checkTouchInArea = [weak = WeakClaim(this), manager = WeakClaim(AceType::RawPtr(overlayManager))](
294                                          const PointF& point) {
295         auto baseOverlay = weak.Upgrade();
296         CHECK_NULL_RETURN(baseOverlay, false);
297         auto overlayManager = manager.Upgrade();
298         CHECK_NULL_RETURN(overlayManager, false);
299         auto host = baseOverlay->GetOwner();
300         CHECK_NULL_RETURN(host, false);
301         auto localPoint = point;
302         overlayManager->ConvertPointRelativeToNode(host, localPoint);
303         return baseOverlay->CheckTouchInHostNode(localPoint);
304     };
305     selectionInfo.eventFilter = [weak = WeakClaim(this)](SourceType sourceType, TouchType touchType) {
306         auto overlay = weak.Upgrade();
307         CHECK_NULL_RETURN(overlay, false);
308         return overlay->IsAcceptResetSelectionEvent(sourceType, touchType);
309     };
310     overlayManager->SetHoldSelectionCallback(GetOwnerId(), selectionInfo);
311 }
312 
GetVisibleContentRect()313 RectF BaseTextSelectOverlay::GetVisibleContentRect()
314 {
315     RectF visibleContentRect;
316     auto pattern = GetPattern<Pattern>();
317     CHECK_NULL_RETURN(pattern, visibleContentRect);
318     auto host = pattern->GetHost();
319     CHECK_NULL_RETURN(host, visibleContentRect);
320     auto context = host->GetContext();
321     CHECK_NULL_RETURN(context, visibleContentRect);
322     auto geometryNode = host->GetGeometryNode();
323     CHECK_NULL_RETURN(geometryNode, visibleContentRect);
324     auto paintOffset = host->GetTransformRelativeOffset();
325     visibleContentRect = RectF(geometryNode->GetContentOffset() + paintOffset, geometryNode->GetContentSize());
326     if (enableHandleLevel_ && handleLevelMode_ == HandleLevelMode::EMBED) {
327         return visibleContentRect;
328     }
329     return GetVisibleRect(pattern->GetHost(), visibleContentRect);
330 }
331 
MergeSelectedBoxes(const std::vector<RectF> & boxes,const RectF & contentRect,const RectF & textRect,const OffsetF & paintOffset)332 RectF BaseTextSelectOverlay::MergeSelectedBoxes(
333     const std::vector<RectF>& boxes, const RectF& contentRect, const RectF& textRect, const OffsetF& paintOffset)
334 {
335     auto frontRect = boxes.front();
336     auto backRect = boxes.back();
337     RectF res;
338     if (GreatNotEqual(backRect.Bottom(), frontRect.Bottom())) {
339         res.SetRect(contentRect.GetX() + paintOffset.GetX(), frontRect.GetY() + textRect.GetY() + paintOffset.GetY(),
340             contentRect.Width(), backRect.Bottom() - frontRect.Top());
341     } else {
342         res.SetRect(frontRect.GetX() + textRect.GetX() + paintOffset.GetX(),
343             frontRect.GetY() + textRect.GetY() + paintOffset.GetY(), backRect.Right() - frontRect.Left(),
344             backRect.Bottom() - frontRect.Top());
345     }
346     return res;
347 }
348 
SetTransformPaintInfo(SelectHandleInfo & handleInfo,const RectF & localHandleRect)349 void BaseTextSelectOverlay::SetTransformPaintInfo(SelectHandleInfo& handleInfo, const RectF& localHandleRect)
350 {
351     CHECK_NULL_VOID(hasTransform_);
352     SelectHandlePaintInfo paintInfo;
353     auto left = localHandleRect.Left() + localHandleRect.Width() / 2.0f;
354     std::vector<OffsetF> points = { OffsetF(left, localHandleRect.Top()), OffsetF(left, localHandleRect.Bottom()) };
355     GetGlobalPointsWithTransform(points);
356     paintInfo.startPoint = points[0];
357     paintInfo.endPoint = points[1];
358     paintInfo.width = localHandleRect.Width();
359     handleInfo.paintInfo = paintInfo;
360     handleInfo.paintInfoConverter = [weak = WeakClaim(this)](const SelectHandlePaintInfo& paintInfo) {
361         auto overlay = weak.Upgrade();
362         CHECK_NULL_RETURN(overlay, RectF());
363         return overlay->ConvertPaintInfoToRect(paintInfo);
364     };
365     handleInfo.isPaintHandleWithPoints = true;
366     handleInfo.isShow =
367         CheckHandleIsVisibleWithTransform(paintInfo.startPoint, paintInfo.endPoint, localHandleRect.Width());
368 }
369 
CheckHandleIsVisibleWithTransform(const OffsetF & startPoint,const OffsetF & endPoint,float epsilon)370 bool BaseTextSelectOverlay::CheckHandleIsVisibleWithTransform(
371     const OffsetF& startPoint, const OffsetF& endPoint, float epsilon)
372 {
373     auto pattern = GetPattern<Pattern>();
374     CHECK_NULL_RETURN(pattern, true);
375     auto host = pattern->GetHost();
376     CHECK_NULL_RETURN(host, true);
377     auto geometryNode = host->GetGeometryNode();
378     CHECK_NULL_RETURN(geometryNode, true);
379     auto contentRect = geometryNode->GetContentRect();
380     auto rectVertices = GetGlobalRectVertexWithTransform(contentRect, epsilon);
381     auto leftTop = rectVertices[0];
382     auto rightTop = rectVertices[1];
383     auto leftBottom = rectVertices[2];
384     auto rightBottom = rectVertices[3];
385     auto isStartPointInRect = IsPointInRect(startPoint, leftBottom, rightBottom, rightTop, leftTop);
386     auto isEndPointInRect = IsPointInRect(endPoint, leftBottom, rightBottom, rightTop, leftTop);
387     if (isStartPointInRect && isEndPointInRect) {
388         auto visibleContentRect = GetVisibleContentRectWithTransform(epsilon);
389         leftTop = OffsetF(visibleContentRect.Left(), visibleContentRect.Top());
390         rightTop = OffsetF(visibleContentRect.Right(), visibleContentRect.Top());
391         leftBottom = OffsetF(visibleContentRect.Left(), visibleContentRect.Bottom());
392         rightBottom = OffsetF(visibleContentRect.Right(), visibleContentRect.Bottom());
393         isStartPointInRect = IsPointInRect(startPoint, leftBottom, rightBottom, rightTop, leftTop);
394         isEndPointInRect = IsPointInRect(endPoint, leftBottom, rightBottom, rightTop, leftTop);
395         return isStartPointInRect && isEndPointInRect;
396     }
397     return false;
398 }
399 
IsPointInRect(const OffsetF & point,const OffsetF & lb,const OffsetF & rb,const OffsetF & rt,const OffsetF & lt)400 bool BaseTextSelectOverlay::IsPointInRect(
401     const OffsetF& point, const OffsetF& lb, const OffsetF& rb, const OffsetF& rt, const OffsetF& lt)
402 {
403     auto crossProduct = [](const OffsetF& point, const OffsetF& point1, const OffsetF& point2) {
404         auto pointStart = OffsetF(point2.GetX() - point1.GetX(), point2.GetY() - point1.GetY());
405         auto pointEnd = OffsetF(point.GetX() - point1.GetX(), point.GetY() - point1.GetY());
406         return pointStart.GetX() * pointEnd.GetY() - pointEnd.GetX() * pointStart.GetY();
407     };
408     auto bottomProduct = crossProduct(point, lb, rb);
409     auto rightProduct = crossProduct(point, rb, rt);
410     auto topProduct = crossProduct(point, rt, lt);
411     auto leftProduct = crossProduct(point, lt, lb);
412     std::vector<float> productVector = { bottomProduct, rightProduct, topProduct, leftProduct };
413     auto minMax = std::minmax_element(productVector.begin(), productVector.end());
414     // 所用向量叉积方向一致(都为正数或者都为负数),表示点在矩形内. 最小值大于0或者最大值小于0.
415     return Positive(*minMax.first) || Negative(* minMax.second);
416 }
417 
GetVisibleContentRectWithTransform(float epsilon)418 RectF BaseTextSelectOverlay::GetVisibleContentRectWithTransform(float epsilon)
419 {
420     RectF visibleContentRect;
421     auto pattern = GetPattern<Pattern>();
422     CHECK_NULL_RETURN(pattern, visibleContentRect);
423     auto host = pattern->GetHost();
424     CHECK_NULL_RETURN(host, visibleContentRect);
425     auto context = host->GetContext();
426     CHECK_NULL_RETURN(context, visibleContentRect);
427     auto geometryNode = host->GetGeometryNode();
428     CHECK_NULL_RETURN(geometryNode, visibleContentRect);
429     visibleContentRect = geometryNode->GetContentRect();
430     auto width = visibleContentRect.Width() + 2 * epsilon;
431     auto height = visibleContentRect.Height() + 2 * epsilon;
432     visibleContentRect.SetLeft(visibleContentRect.Left() - epsilon);
433     visibleContentRect.SetTop(visibleContentRect.Top() - epsilon);
434     visibleContentRect.SetWidth(width);
435     visibleContentRect.SetHeight(height);
436     GetGlobalRectWithTransform(visibleContentRect);
437     return GetVisibleRect(pattern->GetHost(), visibleContentRect);
438 }
439 
GetGlobalPointsWithTransform(std::vector<OffsetF> & points)440 void BaseTextSelectOverlay::GetGlobalPointsWithTransform(std::vector<OffsetF>& points)
441 {
442     CHECK_NULL_VOID(hasTransform_);
443     auto pattern = GetPattern<Pattern>();
444     CHECK_NULL_VOID(pattern);
445     auto parent = pattern->GetHost();
446     std::vector<PointF> convertPoints;
447     auto pointConverter = [](const OffsetF& offset) { return PointF(offset.GetX(), offset.GetY()); };
448     std::transform(points.begin(), points.end(), std::back_inserter(convertPoints), pointConverter);
449     while (parent) {
450         if (parent->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
451             break;
452         }
453         auto renderContext = parent->GetRenderContext();
454         CHECK_NULL_VOID(renderContext);
455         auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
456         for (auto& pointElement : convertPoints) {
457             pointElement = pointElement + paintOffset;
458             renderContext->GetPointTransform(pointElement);
459         }
460         parent = parent->GetAncestorNodeOfFrame(true);
461     }
462     points.clear();
463     auto offsetConverter = [](const PointF& point) { return OffsetF(point.GetX(), point.GetY()); };
464     std::transform(convertPoints.begin(), convertPoints.end(), std::back_inserter(points), offsetConverter);
465 }
466 
GetGlobalRectWithTransform(RectF & localRect)467 void BaseTextSelectOverlay::GetGlobalRectWithTransform(RectF& localRect)
468 {
469     CHECK_NULL_VOID(hasTransform_);
470     auto rectVertex = GetGlobalRectVertexWithTransform(localRect);
471     auto compareOffsetX = [](const OffsetF& offset1, const OffsetF& offset2) {
472         return LessNotEqual(offset1.GetX(), offset2.GetX());
473     };
474     auto minMaxX = std::minmax_element(rectVertex.begin(), rectVertex.end(), compareOffsetX);
475     auto compareOffsetY = [](const OffsetF& offset1, const OffsetF& offset2) {
476         return LessNotEqual(offset1.GetY(), offset2.GetY());
477     };
478     auto minMaxY = std::minmax_element(rectVertex.begin(), rectVertex.end(), compareOffsetY);
479     localRect.SetOffset(OffsetF(minMaxX.first->GetX(), minMaxY.first->GetY()));
480     localRect.SetSize(
481         SizeF(minMaxX.second->GetX() - minMaxX.first->GetX(), minMaxY.second->GetY() - minMaxY.first->GetY()));
482 }
483 
GetGlobalRectVertexWithTransform(const RectF & rect,float extendValue)484 std::vector<OffsetF> BaseTextSelectOverlay::GetGlobalRectVertexWithTransform(const RectF& rect, float extendValue)
485 {
486     std::vector<OffsetF> rectVertices = {
487         OffsetF(rect.Left() - extendValue, rect.Top() - extendValue),
488         OffsetF(rect.Right() + extendValue, rect.Top() - extendValue),
489         OffsetF(rect.Left() - extendValue, rect.Bottom() + extendValue),
490         OffsetF(rect.Right() + extendValue, rect.Bottom() + extendValue)
491     };
492     GetGlobalPointsWithTransform(rectVertices);
493     return rectVertices;
494 }
495 
GetLocalPointWithTransform(OffsetF & localPoint)496 void BaseTextSelectOverlay::GetLocalPointWithTransform(OffsetF& localPoint)
497 {
498     CHECK_NULL_VOID(hasTransform_);
499     std::vector<OffsetF> points = { localPoint };
500     GetLocalPointsWithTransform(points);
501     localPoint = points[0];
502 }
503 
GetLocalPointsWithTransform(std::vector<OffsetF> & localPoints)504 void BaseTextSelectOverlay::GetLocalPointsWithTransform(std::vector<OffsetF>& localPoints)
505 {
506     CHECK_NULL_VOID(hasTransform_);
507     auto textPaintOffset = GetPaintRectOffsetWithTransform();
508     GetGlobalPointsWithTransform(localPoints);
509     for (auto& pointElement : localPoints) {
510         pointElement = pointElement - textPaintOffset;
511     }
512 }
513 
GetPaintRectWithTransform()514 RectF BaseTextSelectOverlay::GetPaintRectWithTransform()
515 {
516     auto pattern = GetPattern<Pattern>();
517     CHECK_NULL_RETURN(pattern, RectF());
518     auto host = pattern->GetHost();
519     CHECK_NULL_RETURN(host, RectF());
520     auto geometryNode = host->GetGeometryNode();
521     CHECK_NULL_RETURN(geometryNode, RectF());
522     auto globalFrameRect = RectF(OffsetF(0.0f, 0.0f), geometryNode->GetFrameSize());
523     GetGlobalRectWithTransform(globalFrameRect);
524     return globalFrameRect;
525 }
526 
GetPaintRectOffsetWithTransform()527 OffsetF BaseTextSelectOverlay::GetPaintRectOffsetWithTransform()
528 {
529     auto pipeline = PipelineContext::GetCurrentContextSafely();
530     CHECK_NULL_RETURN(pipeline, OffsetF(0.0f, 0.0f));
531     auto globalFrameRect = GetPaintRectWithTransform();
532     return globalFrameRect.GetOffset() - pipeline->GetRootRect().GetOffset();
533 }
534 
GetLocalRectWithTransform(RectF & rect)535 void BaseTextSelectOverlay::GetLocalRectWithTransform(RectF& rect)
536 {
537     CHECK_NULL_VOID(hasTransform_);
538     std::vector<OffsetF> localRectVertices = {
539         OffsetF(rect.Left(), rect.Top()),
540         OffsetF(rect.Right(), rect.Top()),
541         OffsetF(rect.Left(), rect.Bottom()),
542         OffsetF(rect.Right(), rect.Bottom())
543     };
544     GetLocalPointsWithTransform(localRectVertices);
545     auto compareOffsetX = [](const OffsetF& offset1, const OffsetF& offset2) {
546         return LessNotEqual(offset1.GetX(), offset2.GetX());
547     };
548     auto minMaxX = std::minmax_element(localRectVertices.begin(), localRectVertices.end(), compareOffsetX);
549     auto compareOffsetY = [](const OffsetF& offset1, const OffsetF& offset2) {
550         return LessNotEqual(offset1.GetY(), offset2.GetY());
551     };
552     auto minMaxY = std::minmax_element(localRectVertices.begin(), localRectVertices.end(), compareOffsetY);
553     rect.SetOffset(OffsetF(minMaxX.first->GetX(), minMaxY.first->GetY()));
554     rect.SetSize(SizeF(minMaxX.second->GetX() - minMaxX.first->GetX(), minMaxY.second->GetY() - minMaxY.first->GetY()));
555 }
556 
RevertLocalPointWithTransform(OffsetF & point)557 void BaseTextSelectOverlay::RevertLocalPointWithTransform(OffsetF& point)
558 {
559     CHECK_NULL_VOID(hasTransform_);
560     auto pattern = GetPattern<Pattern>();
561     CHECK_NULL_VOID(pattern);
562     auto parent = pattern->GetHost();
563     CHECK_NULL_VOID(parent);
564     std::stack<RefPtr<FrameNode>> nodeStack;
565     while (parent) {
566         nodeStack.push(parent);
567         parent = parent->GetAncestorNodeOfFrame(true);
568     }
569     CHECK_NULL_VOID(!nodeStack.empty());
570     PointF localPoint(point.GetX(), point.GetY());
571     while (!nodeStack.empty()) {
572         parent = nodeStack.top();
573         CHECK_NULL_VOID(parent);
574         nodeStack.pop();
575         auto renderContext = parent->GetRenderContext();
576         CHECK_NULL_VOID(renderContext);
577         renderContext->GetPointWithRevert(localPoint);
578         auto rectOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
579         localPoint = localPoint - rectOffset;
580     }
581     point.SetX(localPoint.GetX());
582     point.SetY(localPoint.GetY());
583 }
584 
ConvertPaintInfoToRect(const SelectHandlePaintInfo & paintInfo)585 RectF BaseTextSelectOverlay::ConvertPaintInfoToRect(const SelectHandlePaintInfo& paintInfo)
586 {
587     auto topOffset = paintInfo.startPoint;
588     RevertLocalPointWithTransform(topOffset);
589     auto bottomOffset = paintInfo.endPoint;
590     RevertLocalPointWithTransform(bottomOffset);
591     auto offset = topOffset + GetPaintOffsetWithoutTransform();
592     auto size = SizeF(paintInfo.width, bottomOffset.GetY() - topOffset.GetY());
593     return RectF(offset, size);
594 }
595 
GetPaintOffsetWithoutTransform()596 OffsetF BaseTextSelectOverlay::GetPaintOffsetWithoutTransform()
597 {
598     auto pattern = GetPattern<Pattern>();
599     CHECK_NULL_RETURN(pattern, OffsetF());
600     OffsetF offset;
601     auto parent = pattern->GetHost();
602     if (!hasTransform_) {
603         return parent->GetTransformRelativeOffset();
604     }
605     while (parent) {
606         auto renderContext = parent->GetRenderContext();
607         CHECK_NULL_RETURN(renderContext, OffsetF());
608         offset += renderContext->GetPaintRectWithoutTransform().GetOffset();
609         parent = parent->GetAncestorNodeOfFrame(true);
610     }
611     return offset;
612 }
613 
UpdateTransformFlag()614 void BaseTextSelectOverlay::UpdateTransformFlag()
615 {
616     auto pattern = GetPattern<Pattern>();
617     CHECK_NULL_VOID(pattern);
618     auto host = pattern->GetHost();
619     CHECK_NULL_VOID(host);
620     auto hasTransform = false;
621     while (host) {
622         auto renderContext = host->GetRenderContext();
623         CHECK_NULL_VOID(renderContext);
624         if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
625             break;
626         }
627         if (!hasTransform) {
628             auto noTransformRect = renderContext->GetPaintRectWithoutTransform();
629             auto transformRect = renderContext->GetPaintRectWithTransform();
630             hasTransform = noTransformRect != transformRect;
631         }
632         host = host->GetAncestorNodeOfFrame(true);
633     }
634     hasTransform_ = hasTransform;
635 }
636 
GetAncestorNodeViewPort()637 std::optional<RectF> BaseTextSelectOverlay::GetAncestorNodeViewPort()
638 {
639     if (IsClipHandleWithViewPort()) {
640         RectF viewPort;
641         if (GetClipHandleViewPort(viewPort)) {
642             return viewPort;
643         }
644     }
645     auto pattern = GetPattern<Pattern>();
646     CHECK_NULL_RETURN(pattern, std::nullopt);
647     auto host = pattern->GetHost();
648     CHECK_NULL_RETURN(host, std::nullopt);
649     auto parent = host->GetAncestorNodeOfFrame(true);
650     while (parent) {
651         auto scrollableContainer = parent->GetPattern<NestableScrollContainer>();
652         if (scrollableContainer) {
653             return parent->GetTransformRectRelativeToWindow();
654         }
655         parent = parent->GetAncestorNodeOfFrame(true);
656     }
657     return std::nullopt;
658 }
659 
IsAcceptResetSelectionEvent(SourceType sourceType,TouchType touchType)660 bool BaseTextSelectOverlay::IsAcceptResetSelectionEvent(SourceType sourceType, TouchType touchType)
661 {
662     return (sourceType == SourceType::MOUSE || sourceType == SourceType::TOUCH) && touchType == TouchType::DOWN;
663 }
664 
GetHandleDiameter()665 float BaseTextSelectOverlay::GetHandleDiameter()
666 {
667     auto overlayManager = SelectContentOverlayManager::GetOverlayManager();
668     CHECK_NULL_RETURN(overlayManager, 0.0f);
669     return overlayManager->GetHandleDiameter();
670 }
671 
SwitchToOverlayMode()672 void BaseTextSelectOverlay::SwitchToOverlayMode()
673 {
674     if (HasUnsupportedTransform()) {
675         return;
676     }
677     auto manager = GetManager<SelectContentOverlayManager>();
678     CHECK_NULL_VOID(manager);
679     handleLevelMode_ = HandleLevelMode::OVERLAY;
680     manager->SwitchToHandleMode(handleLevelMode_);
681 }
682 
SwitchToEmbedMode()683 void BaseTextSelectOverlay::SwitchToEmbedMode()
684 {
685     CHECK_NULL_VOID(!isHandleMoving_);
686     auto manager = GetManager<SelectContentOverlayManager>();
687     CHECK_NULL_VOID(manager);
688     handleLevelMode_ = HandleLevelMode::EMBED;
689     manager->SwitchToHandleMode(handleLevelMode_);
690 }
691 
GetHostScale()692 VectorF BaseTextSelectOverlay::GetHostScale()
693 {
694     auto pattern = GetPattern<Pattern>();
695     auto unitScale = VectorF(1, 1);
696     CHECK_NULL_RETURN(pattern, unitScale);
697     auto host = pattern->GetHost();
698     CHECK_NULL_RETURN(host, unitScale);
699     auto scaleX = 1.0f;
700     auto scaleY = 1.0f;
701     while (host && host->GetTag() != V2::WINDOW_SCENE_ETS_TAG) {
702         auto renderContext = host->GetRenderContext();
703         CHECK_NULL_RETURN(renderContext, unitScale);
704         auto scale = renderContext->GetTransformScaleValue(unitScale);
705         scaleX *= std::abs(scale.x);
706         scaleY *= std::abs(scale.y);
707         auto transformMatrix = renderContext->GetTransformMatrix();
708         if (transformMatrix.has_value()) {
709             DecomposedTransform transform;
710             TransformUtil::DecomposeTransform(transform, transformMatrix.value());
711             scaleX *= std::abs(transform.scale[0]);
712             scaleY *= std::abs(transform.scale[1]);
713         }
714         host = host->GetAncestorNodeOfFrame(true);
715     }
716     return VectorF(1.0f / scaleX, 1.0f / scaleY);
717 }
718 
OnCloseOverlay(OptionMenuType menuType,CloseReason reason,RefPtr<OverlayInfo> info)719 void BaseTextSelectOverlay::OnCloseOverlay(OptionMenuType menuType, CloseReason reason, RefPtr<OverlayInfo> info)
720 {
721     isHandleDragging_ = false;
722     originalMenuIsShow_ = false;
723     if (enableHandleLevel_) {
724         auto host = GetOwner();
725         CHECK_NULL_VOID(host);
726         host->UnregisterNodeChangeListener();
727     }
728 }
729 
SetHandleLevelMode(HandleLevelMode mode)730 void BaseTextSelectOverlay::SetHandleLevelMode(HandleLevelMode mode)
731 {
732     if (handleLevelMode_ == mode) {
733         return;
734     }
735     handleLevelMode_ = mode;
736 }
737 
GetFirstHandleLocalPaintRect()738 RectF BaseTextSelectOverlay::GetFirstHandleLocalPaintRect()
739 {
740     return RectF();
741 }
742 
GetSecondHandleLocalPaintRect()743 RectF BaseTextSelectOverlay::GetSecondHandleLocalPaintRect()
744 {
745     return RectF();
746 }
747 
IsPointsInRegion(const std::vector<PointF> & points,const RectF & regionRect)748 bool BaseTextSelectOverlay::IsPointsInRegion(const std::vector<PointF>& points, const RectF& regionRect)
749 {
750     for (const auto& point : points) {
751         if (!regionRect.IsInRegion(point)) {
752             return false;
753         }
754     }
755     return true;
756 }
757 
GetHandlePoints(const RectF & handleRect,std::vector<PointF> & points,bool handleOnTop)758 void BaseTextSelectOverlay::GetHandlePoints(const RectF& handleRect, std::vector<PointF>& points, bool handleOnTop)
759 {
760     auto diameter = GetHandleDiameter();
761     auto handlePaintRect = handleRect;
762     auto offsetX = handlePaintRect.Left() + (handlePaintRect.Width() - diameter) / 2.0f;
763     auto offsetY = handleOnTop ? handlePaintRect.Top() - diameter : handlePaintRect.Bottom();
764     handlePaintRect.SetOffset(OffsetF(offsetX, offsetY));
765     handlePaintRect.SetSize(SizeF(diameter, diameter));
766     points.push_back(PointF(handlePaintRect.Left(), handlePaintRect.Top()));
767     points.push_back(PointF(handlePaintRect.Right(), handlePaintRect.Top()));
768     points.push_back(PointF(handlePaintRect.Left(), handlePaintRect.Bottom()));
769     points.push_back(PointF(handlePaintRect.Right(), handlePaintRect.Bottom()));
770 }
771 
CheckHandleCanPaintInHost(const RectF & firstRect,const RectF & secondRect)772 bool BaseTextSelectOverlay::CheckHandleCanPaintInHost(const RectF& firstRect, const RectF& secondRect)
773 {
774     if (isChangeToOverlayModeAtEdge_) {
775         return false;
776     }
777     std::vector<PointF> firstPoints;
778     GetHandlePoints(firstRect, firstPoints, false);
779     std::vector<PointF> secondPoints;
780     GetHandlePoints(secondRect, secondPoints, false);
781     auto host = GetOwner();
782     CHECK_NULL_RETURN(host, false);
783     auto parent = host;
784     while (parent) {
785         CHECK_NULL_RETURN(parent->GetGeometryNode(), false);
786         auto parentRect = RectF();
787         parentRect.SetSize(parent->GetGeometryNode()->GetFrameSize());
788         if (IsPointsInRegion(firstPoints, parentRect) && IsPointsInRegion(secondPoints, parentRect)) {
789             return true;
790         }
791         auto renderContext = parent->GetRenderContext();
792         CHECK_NULL_RETURN(renderContext, false);
793         auto isClip = renderContext->GetClipEdge().value_or(false);
794         if (isClip) {
795             break;
796         }
797         auto paintOffset = renderContext->GetPaintRectWithoutTransform().GetOffset();
798         for (auto& point : firstPoints) {
799             point = point + paintOffset;
800             renderContext->GetPointTransform(point);
801         }
802         for (auto& point : secondPoints) {
803             point = point + paintOffset;
804             renderContext->GetPointTransform(point);
805         }
806         parent = parent->GetAncestorNodeOfFrame(true);
807     }
808     return false;
809 }
810 
CalcHandleLevelMode(const RectF & firstLocalPaintRect,const RectF & secondLocalPaintRect)811 void BaseTextSelectOverlay::CalcHandleLevelMode(const RectF& firstLocalPaintRect, const RectF& secondLocalPaintRect)
812 {
813     if (CheckHandleCanPaintInHost(firstLocalPaintRect, secondLocalPaintRect) || HasUnsupportedTransform()) {
814         SetHandleLevelMode(HandleLevelMode::EMBED);
815     } else {
816         SetHandleLevelMode(HandleLevelMode::OVERLAY);
817     }
818 }
819 
OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)820 void BaseTextSelectOverlay::OnAncestorNodeChanged(FrameNodeChangeInfoFlag flag)
821 {
822     auto isStartScroll = IsAncestorNodeStartScroll(flag);
823     auto isStartAnimation = IsAncestorNodeStartAnimation(flag);
824     auto isTransformChanged = IsAncestorNodeTransformChange(flag);
825     auto isStartTransition = IsAncestorNodeHasTransition(flag);
826     auto isSwitchToEmbed = isStartScroll || isStartAnimation || isTransformChanged || isStartTransition;
827     // parent size changes but the child does not change.
828     if (IsAncestorNodeGeometryChange(flag)) {
829         isSwitchToEmbed = isSwitchToEmbed || CheckAndUpdateHostGlobalPaintRect();
830     }
831     auto isScrollEnd = IsAncestorNodeEndScroll(flag);
832     isSwitchToEmbed = isSwitchToEmbed && (!isScrollEnd || HasUnsupportedTransform());
833     UpdateMenuWhileAncestorNodeChanged(
834         isStartScroll || isStartAnimation || isTransformChanged || isStartTransition, isScrollEnd);
835     auto pipeline = PipelineContext::GetCurrentContextSafely();
836     CHECK_NULL_VOID(pipeline);
837     pipeline->AddAfterRenderTask([weak = WeakClaim(this), isSwitchToEmbed, isScrollEnd]() {
838         auto overlay = weak.Upgrade();
839         CHECK_NULL_VOID(overlay);
840         if (isScrollEnd) {
841             overlay->SwitchToOverlayMode();
842             return;
843         }
844         if (isSwitchToEmbed) {
845             overlay->SwitchToEmbedMode();
846         }
847     });
848 }
849 
UpdateMenuWhileAncestorNodeChanged(bool shouldHideMenu,bool shouldShowMenu)850 void BaseTextSelectOverlay::UpdateMenuWhileAncestorNodeChanged(bool shouldHideMenu, bool shouldShowMenu)
851 {
852     auto manager = GetManager<SelectContentOverlayManager>();
853     CHECK_NULL_VOID(manager);
854     if (shouldHideMenu) {
855         manager->HideOptionMenu(true);
856         return;
857     }
858     if (shouldShowMenu && originalMenuIsShow_ && !GetIsHandleDragging() && !GetSelectArea().IsEmpty()) {
859         manager->ShowOptionMenu();
860     }
861 }
862 
IsAncestorNodeStartAnimation(FrameNodeChangeInfoFlag flag)863 bool BaseTextSelectOverlay::IsAncestorNodeStartAnimation(FrameNodeChangeInfoFlag flag)
864 {
865     return ((flag & FRAME_NODE_CHANGE_START_ANIMATION) == FRAME_NODE_CHANGE_START_ANIMATION);
866 }
867 
IsAncestorNodeGeometryChange(FrameNodeChangeInfoFlag flag)868 bool BaseTextSelectOverlay::IsAncestorNodeGeometryChange(FrameNodeChangeInfoFlag flag)
869 {
870     return ((flag & FRAME_NODE_CHANGE_GEOMETRY_CHANGE) == FRAME_NODE_CHANGE_GEOMETRY_CHANGE);
871 }
872 
IsAncestorNodeStartScroll(FrameNodeChangeInfoFlag flag)873 bool BaseTextSelectOverlay::IsAncestorNodeStartScroll(FrameNodeChangeInfoFlag flag)
874 {
875     return ((flag & FRAME_NODE_CHANGE_START_SCROLL) == FRAME_NODE_CHANGE_START_SCROLL);
876 }
877 
IsAncestorNodeEndScroll(FrameNodeChangeInfoFlag flag)878 bool BaseTextSelectOverlay::IsAncestorNodeEndScroll(FrameNodeChangeInfoFlag flag)
879 {
880     return ((flag & FRAME_NODE_CHANGE_END_SCROLL) == FRAME_NODE_CHANGE_END_SCROLL);
881 }
882 
IsAncestorNodeTransformChange(FrameNodeChangeInfoFlag flag)883 bool BaseTextSelectOverlay::IsAncestorNodeTransformChange(FrameNodeChangeInfoFlag flag)
884 {
885     return ((flag & FRAME_NODE_CHANGE_TRANSFORM_CHANGE) == FRAME_NODE_CHANGE_TRANSFORM_CHANGE);
886 }
887 
IsAncestorNodeHasTransition(FrameNodeChangeInfoFlag flag)888 bool BaseTextSelectOverlay::IsAncestorNodeHasTransition(FrameNodeChangeInfoFlag flag)
889 {
890     return ((flag & FRAME_NODE_CHANGE_TRANSITION_START) == FRAME_NODE_CHANGE_TRANSITION_START);
891 }
892 
IsTouchAtHandle(const TouchEventInfo & info)893 bool BaseTextSelectOverlay::IsTouchAtHandle(const TouchEventInfo& info)
894 {
895     auto overlayManager = GetManager<SelectContentOverlayManager>();
896     CHECK_NULL_RETURN(overlayManager, false);
897     CHECK_NULL_RETURN(!info.GetTouches().empty(), false);
898     auto touchType = info.GetTouches().front().GetTouchType();
899     if (touchType == TouchType::DOWN) {
900         auto localOffset = info.GetTouches().front().GetLocalLocation();
901         auto globalOffset = info.GetTouches().front().GetGlobalLocation();
902         touchAtHandle_ = overlayManager->IsTouchAtHandle(
903             PointF(localOffset.GetX(), localOffset.GetY()), PointF(globalOffset.GetX(), globalOffset.GetY()));
904     } else if (touchType == TouchType::UP) {
905         if (touchAtHandle_) {
906             touchAtHandle_ = false;
907             return true;
908         }
909     }
910     return touchAtHandle_;
911 }
912 
IsClickAtHandle(const GestureEvent & info)913 bool BaseTextSelectOverlay::IsClickAtHandle(const GestureEvent& info)
914 {
915     auto overlayManager = GetManager<SelectContentOverlayManager>();
916     CHECK_NULL_RETURN(overlayManager, false);
917     auto localOffset = info.GetLocalLocation();
918     auto globalOffset = info.GetGlobalLocation();
919     return overlayManager->IsTouchAtHandle(
920         PointF(localOffset.GetX(), localOffset.GetY()), PointF(globalOffset.GetX(), globalOffset.GetY()));
921 }
922 
HasUnsupportedTransform()923 bool BaseTextSelectOverlay::HasUnsupportedTransform()
924 {
925     auto pattern = GetPattern<Pattern>();
926     CHECK_NULL_RETURN(pattern, false);
927     auto parent = pattern->GetHost();
928     CHECK_NULL_RETURN(parent, false);
929     const int32_t zTranslateIndex = 2;
930     while (parent) {
931         auto renderContext = parent->GetRenderContext();
932         CHECK_NULL_RETURN(renderContext, false);
933         if (parent->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
934             return false;
935         }
936         if (renderContext->HasMotionPath()) {
937             return true;
938         }
939         auto rotateVector = renderContext->GetTransformRotate();
940         if (rotateVector.has_value() && !NearZero(rotateVector->w) &&
941             !(NearZero(rotateVector->x) && NearZero(rotateVector->y))) {
942             return true;
943         }
944         auto transformMatrix = renderContext->GetTransformMatrix();
945         if (transformMatrix) {
946             DecomposedTransform transform;
947             TransformUtil::DecomposeTransform(transform, transformMatrix.value());
948             Quaternion identity(0.0f, 0.0f, 0.0f, 1.0f);
949             if (transform.quaternion != identity || !NearZero(transform.translate[zTranslateIndex])) {
950                 return true;
951             }
952         }
953         auto translate = renderContext->GetTransformTranslate();
954         if (translate && !NearZero(translate->z.Value())) {
955             return true;
956         }
957         parent = parent->GetAncestorNodeOfFrame(true);
958     }
959     return false;
960 }
961 
CheckSwitchToMode(HandleLevelMode mode)962 bool BaseTextSelectOverlay::CheckSwitchToMode(HandleLevelMode mode)
963 {
964     if (mode == HandleLevelMode::OVERLAY && HasUnsupportedTransform()) {
965         return false;
966     }
967     return true;
968 }
969 
OnSelectionMenuOptionsUpdate(const NG::OnCreateMenuCallback && onCreateMenuCallback,const NG::OnMenuItemClickCallback && onMenuItemClick)970 void BaseTextSelectOverlay::OnSelectionMenuOptionsUpdate(
971     const NG::OnCreateMenuCallback&& onCreateMenuCallback, const NG::OnMenuItemClickCallback&& onMenuItemClick)
972 {
973     onCreateMenuCallback_ = onCreateMenuCallback;
974     onMenuItemClick_ = onMenuItemClick;
975 }
976 
RegisterScrollingListener(const RefPtr<FrameNode> scrollableNode)977 void BaseTextSelectOverlay::RegisterScrollingListener(const RefPtr<FrameNode> scrollableNode)
978 {
979     if (hasRegisterListener_) {
980         return;
981     }
982     auto scrollingNode = scrollableNode;
983     if (!scrollingNode) {
984         auto host = GetOwner();
985         CHECK_NULL_VOID(host);
986         scrollingNode = host->GetAncestorNodeOfFrame(true);
987         while (scrollingNode) {
988             if (scrollingNode->GetTag() == V2::SWIPER_ETS_TAG) {
989                 break;
990             }
991             scrollingNode = scrollingNode->GetAncestorNodeOfFrame(true);
992         }
993     }
994     if (scrollingNode) {
995         auto pattern = scrollingNode->GetPattern<Pattern>();
996         CHECK_NULL_VOID(pattern);
997         auto scrollCallback = [weak = WeakClaim(this), scrollNode = WeakClaim(AceType::RawPtr(scrollableNode))] {
998             auto overlay = weak.Upgrade();
999             CHECK_NULL_VOID(overlay);
1000             overlay->OnHandleScrolling(scrollNode);
1001         };
1002         auto scrollListener = AceType::MakeRefPtr<ScrollingListener>(scrollCallback);
1003         pattern->RegisterScrollingListener(scrollListener);
1004         hasRegisterListener_ = true;
1005     }
1006 }
1007 
OnHandleScrolling(const WeakPtr<FrameNode> & scrollingNode)1008 void BaseTextSelectOverlay::OnHandleScrolling(const WeakPtr<FrameNode>& scrollingNode)
1009 {
1010     if (SelectOverlayIsOn()) {
1011         HideMenu(true);
1012         auto taskExecutor = Container::CurrentTaskExecutor();
1013         taskExecutor->PostTask(
1014             [weak = WeakClaim(this), scrollingNode] {
1015                 auto overlay = weak.Upgrade();
1016                 CHECK_NULL_VOID(overlay);
1017                 overlay->hasRegisterListener_ = false;
1018                 if (overlay->SelectOverlayIsOn()) {
1019                     overlay->RegisterScrollingListener(scrollingNode.Upgrade());
1020                 }
1021             },
1022             TaskExecutor::TaskType::UI, "RegisterScrollingListener");
1023     } else {
1024         hasRegisterListener_ = false;
1025     }
1026 }
1027 
CheckAndUpdateHostGlobalPaintRect()1028 bool BaseTextSelectOverlay::CheckAndUpdateHostGlobalPaintRect()
1029 {
1030     auto host = GetOwner();
1031     CHECK_NULL_RETURN(host, false);
1032     auto geometryNode = host->GetGeometryNode();
1033     CHECK_NULL_RETURN(geometryNode, false);
1034     auto framePaintRect = RectF(host->GetTransformRelativeOffset(), geometryNode->GetFrameSize());
1035     auto changed = globalPaintRect_ != framePaintRect;
1036     globalPaintRect_ = framePaintRect;
1037     return changed;
1038 }
1039 
CheckHasTransformAttr()1040 bool BaseTextSelectOverlay::CheckHasTransformAttr()
1041 {
1042     auto pattern = GetPattern<Pattern>();
1043     CHECK_NULL_RETURN(pattern, false);
1044     auto host = pattern->GetHost();
1045     CHECK_NULL_RETURN(host, false);
1046     auto hasTransform = false;
1047     VectorF scaleIdentity(1.0f, 1.0f);
1048     Vector5F rotateIdentity(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
1049     while (host) {
1050         auto renderContext = host->GetRenderContext();
1051         CHECK_NULL_RETURN(renderContext, false);
1052         if (host->GetTag() == V2::WINDOW_SCENE_ETS_TAG) {
1053             break;
1054         }
1055         if (renderContext->HasMotionPath()) {
1056             hasTransform = true;
1057             break;
1058         }
1059         // has rotate.
1060         auto rotateVector = renderContext->GetTransformRotate();
1061         if (rotateVector.has_value() && !(rotateIdentity == rotateVector.value())) {
1062             hasTransform = true;
1063             break;
1064         }
1065         // has scale.
1066         auto scaleVector = renderContext->GetTransformScale();
1067         if (scaleVector.has_value() && !(scaleIdentity == scaleVector.value())) {
1068             hasTransform = true;
1069             break;
1070         }
1071         // has z translate.
1072         auto translate = renderContext->GetTransformTranslate();
1073         if (translate && !NearZero(translate->z.Value())) {
1074             hasTransform = true;
1075             break;
1076         }
1077         if (CheckHasTransformMatrix(renderContext)) {
1078             hasTransform = true;
1079             break;
1080         }
1081         host = host->GetAncestorNodeOfFrame(true);
1082     }
1083     return hasTransform;
1084 }
1085 
CheckHasTransformMatrix(const RefPtr<RenderContext> & context)1086 bool BaseTextSelectOverlay::CheckHasTransformMatrix(const RefPtr<RenderContext>& context)
1087 {
1088     auto transformMatrix = context->GetTransformMatrix();
1089     CHECK_NULL_RETURN(transformMatrix, false);
1090     const int32_t xIndex = 0;
1091     const int32_t yIndex = 1;
1092     const int32_t zIndex = 2;
1093     const int32_t wIndex = 3;
1094     DecomposedTransform transform;
1095     TransformUtil::DecomposeTransform(transform, transformMatrix.value());
1096     if (!NearZero(transform.translate[zIndex])) {
1097         return true;
1098     }
1099     Quaternion quaternionIdentity(0.0f, 0.0f, 0.0f, 1.0f);
1100     if (transform.quaternion != quaternionIdentity) {
1101         return true;
1102     }
1103     Vector3F scaleIdentity(1.0f, 1.0f, 1.0f);
1104     Vector3F scaleVector(transform.scale[xIndex], transform.scale[yIndex], transform.scale[zIndex]);
1105     if (!(scaleVector == scaleIdentity)) {
1106         return true;
1107     }
1108     Vector3F skewIdentity(0.0f, 0.0f, 0.0f);
1109     Vector3F skewVector(transform.skew[xIndex], transform.skew[yIndex], transform.skew[zIndex]);
1110     if (!(skewVector == skewIdentity)) {
1111         return true;
1112     }
1113     Vector4F perspectiveIdentity(0.0f, 0.0f, 0.0f, 1.0f);
1114     Vector4F perspectiveVector(transform.perspective[xIndex], transform.perspective[yIndex],
1115         transform.perspective[zIndex], transform.perspective[wIndex]);
1116     return !(perspectiveVector == perspectiveIdentity);
1117 }
1118 
GetClipHandleViewPort(RectF & rect)1119 bool BaseTextSelectOverlay::GetClipHandleViewPort(RectF& rect)
1120 {
1121     auto host = GetOwner();
1122     CHECK_NULL_RETURN(host, false);
1123     if (HasUnsupportedTransform()) {
1124         return false;
1125     }
1126     RectF contentRect;
1127     if (!GetFrameNodeContentRect(host, contentRect)) {
1128         return false;
1129     }
1130     contentRect.SetOffset(contentRect.GetOffset() + host->GetPaintRectWithTransform().GetOffset());
1131     auto parent = host->GetAncestorNodeOfFrame(true);
1132     while (parent) {
1133         RectF parentContentRect;
1134         if (!GetFrameNodeContentRect(parent, parentContentRect)) {
1135             return false;
1136         }
1137         auto renderContext = parent->GetRenderContext();
1138         CHECK_NULL_RETURN(renderContext, false);
1139         if (renderContext->GetClipEdge().value_or(false)) {
1140             contentRect = contentRect.IntersectRectT(parentContentRect);
1141         }
1142         contentRect.SetOffset(contentRect.GetOffset() + parent->GetPaintRectWithTransform().GetOffset());
1143         parent = parent->GetAncestorNodeOfFrame(true);
1144     }
1145     contentRect.SetWidth(std::max(contentRect.Width(), 0.0f));
1146     contentRect.SetHeight(std::max(contentRect.Height(), 0.0f));
1147     UpdateClipHandleViewPort(contentRect);
1148     rect = contentRect;
1149     return true;
1150 }
1151 
GetFrameNodeContentRect(const RefPtr<FrameNode> & node,RectF & contentRect)1152 bool BaseTextSelectOverlay::GetFrameNodeContentRect(const RefPtr<FrameNode>& node, RectF& contentRect)
1153 {
1154     CHECK_NULL_RETURN(node, false);
1155     auto geometryNode = node->GetGeometryNode();
1156     CHECK_NULL_RETURN(geometryNode, false);
1157     auto renderContext = node->GetRenderContext();
1158     CHECK_NULL_RETURN(renderContext, false);
1159     if (geometryNode->GetContent()) {
1160         contentRect = geometryNode->GetContentRect();
1161     } else {
1162         contentRect = RectF(OffsetF(0.0f, 0.0f), geometryNode->GetFrameSize());
1163     }
1164     return true;
1165 }
1166 
MarkOverlayDirty()1167 void BaseTextSelectOverlay::MarkOverlayDirty()
1168 {
1169     if (SelectOverlayIsOn()) {
1170         auto host = GetOwner();
1171         CHECK_NULL_VOID(host);
1172         auto overlayNode = host->GetOverlayNode();
1173         CHECK_NULL_VOID(overlayNode);
1174         overlayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1175     }
1176 }
1177 
ApplySelectAreaWithKeyboard(RectF & selectArea)1178 void BaseTextSelectOverlay::ApplySelectAreaWithKeyboard(RectF& selectArea)
1179 {
1180     auto host = GetOwner();
1181     CHECK_NULL_VOID(host);
1182     auto pipeline = host->GetContext();
1183     CHECK_NULL_VOID(pipeline);
1184     auto safeAreaManager = pipeline->GetSafeAreaManager();
1185     CHECK_NULL_VOID(safeAreaManager);
1186     auto keyboardInset = safeAreaManager->GetKeyboardInset();
1187     if (keyboardInset.Length() <= 0) {
1188         return;
1189     }
1190     if (GreatOrEqual(selectArea.Top(), keyboardInset.start)) {
1191         selectArea.SetHeight(0.0f);
1192     }
1193 }
1194 
OnHandleMarkInfoChange(const std::shared_ptr<SelectOverlayInfo> info,SelectOverlayDirtyFlag flag)1195 void BaseTextSelectOverlay::OnHandleMarkInfoChange(
1196     const std::shared_ptr<SelectOverlayInfo> info, SelectOverlayDirtyFlag flag)
1197 {
1198     auto manager = GetManager<SelectContentOverlayManager>();
1199     CHECK_NULL_VOID(manager);
1200     if ((flag & DIRTY_HANDLE_COLOR_FLAG) == DIRTY_HANDLE_COLOR_FLAG) {
1201         info->handlerColor = GetHandleColor();
1202         manager->MarkHandleDirtyNode(PROPERTY_UPDATE_RENDER);
1203     }
1204 }
1205 
UpdateHandleColor()1206 void BaseTextSelectOverlay::UpdateHandleColor()
1207 {
1208     auto manager = GetManager<SelectContentOverlayManager>();
1209     CHECK_NULL_VOID(manager);
1210     manager->MarkInfoChange(DIRTY_HANDLE_COLOR_FLAG);
1211 }
1212 } // namespace OHOS::Ace::NG
1213