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